diff --git a/src/box/lua/info.c b/src/box/lua/info.c index a789f782288d58b66f63e1f11ee78b536f003655..1e77737fd5f0fb7d97827c3e42e4dec085fdbc9d 100644 --- a/src/box/lua/info.c +++ b/src/box/lua/info.c @@ -214,6 +214,55 @@ lbox_info_replication(struct lua_State *L) return 1; } +static int +lbox_info_replication_anon_call(struct lua_State *L) +{ + lua_newtable(L); + + /* Metatable. */ + lua_newtable(L); + lua_pushliteral(L, "mapping"); + lua_setfield(L, -2, "__serialize"); + lua_setmetatable(L, -2); + + replicaset_foreach(replica) { + if (!replica->anon) + continue; + + lua_pushstring(L, tt_uuid_str(&replica->uuid)); + lbox_pushreplica(L, replica); + + lua_settable(L, -3); + } + + return 1; +} + +static int +lbox_info_replication_anon(struct lua_State *L) +{ + /* + * Make the .replication_anon field callable in order to + * not flood the output with possibly lots of anonymous + * replicas on box.info call. + */ + lua_newtable(L); + + lua_pushliteral(L, "count"); + lua_pushinteger(L, replicaset.anon_count); + lua_settable(L, -3); + + /* Metatable. */ + lua_newtable(L); + + lua_pushstring(L, "__call"); + lua_pushcfunction(L, lbox_info_replication_anon_call); + lua_settable(L, -3); + + lua_setmetatable(L, -2); + return 1; +} + static int lbox_info_id(struct lua_State *L) { @@ -534,6 +583,7 @@ static const struct luaL_Reg lbox_info_dynamic_meta[] = { {"vclock", lbox_info_vclock}, {"ro", lbox_info_ro}, {"replication", lbox_info_replication}, + {"replication_anon", lbox_info_replication_anon}, {"status", lbox_info_status}, {"uptime", lbox_info_uptime}, {"pid", lbox_info_pid}, diff --git a/src/box/replication.cc b/src/box/replication.cc index 7c10fb6f2028167eb438cb9933c5d6175a43925a..1b61c92c0dbde6b70c09906e6f972ea0c52f507c 100644 --- a/src/box/replication.cc +++ b/src/box/replication.cc @@ -219,6 +219,7 @@ replicaset_add_anon(const struct tt_uuid *replica_uuid) replica->uuid = *replica_uuid; replica_hash_insert(&replicaset.hash, replica); replica->anon = true; + replicaset.anon_count++; return replica; } @@ -909,6 +910,8 @@ replica_on_relay_stop(struct replica *replica) * replicas. */ assert(replica->applier == NULL); + assert(replicaset.anon_count > 0); + replicaset.anon_count--; } } if (replica_is_orphan(replica)) { diff --git a/src/box/replication.h b/src/box/replication.h index 9df91e61185cd5bc537798c44611edac8aa3a2b7..93a25c8a78cdba6babf87b46e11adbaf70c068fc 100644 --- a/src/box/replication.h +++ b/src/box/replication.h @@ -203,6 +203,8 @@ struct replicaset { * from a remote master. */ bool is_joining; + /* A number of anonymous replicas following this instance. */ + int anon_count; /** Applier state. */ struct { /** diff --git a/test/box/info.result b/test/box/info.result index e6d0ba6aa914f3e6f188a97f8e16fc0761120462..40eeae06952d7e240e60eeeb5b020077d74e90e3 100644 --- a/test/box/info.result +++ b/test/box/info.result @@ -83,6 +83,7 @@ t - package - pid - replication + - replication_anon - ro - signature - sql diff --git a/test/replication/anon.result b/test/replication/anon.result index cbbeeef09cf2745ec4a246fd3551d892e2827ef0..a7e244d3f4d211d1b0c521614fbe87b9e4c2d98d 100644 --- a/test/replication/anon.result +++ b/test/replication/anon.result @@ -151,10 +151,28 @@ test_run:cmd('switch default') | - true | ... --- Replica isn't visible on master. -#box.info.replication +-- Test box.info.replication_anon. +box.info.replication_anon + | --- + | - count: 1 + | ... +#box.info.replication_anon() + | --- + | - 0 + | ... +uuid, tbl = next(box.info.replication_anon()) + | --- + | ... +-- Anonymous replicas are indexed by uuid strings. +require("uuid").fromstr(uuid) ~= nil + | --- + | - true + | ... +-- Anonymous replicas share box.info representation with +-- normal replicas. +tbl.downstream.status | --- - | - 1 + | - follow | ... -- Test that replication (even anonymous) from an anonymous diff --git a/test/replication/anon.test.lua b/test/replication/anon.test.lua index 627dc5c8ec1f11a42113ce2ef41d7926f0261e9a..fef72d07d336a5e47311a1bcff3243b77892c4ed 100644 --- a/test/replication/anon.test.lua +++ b/test/replication/anon.test.lua @@ -50,8 +50,15 @@ box.space.loc:truncate() test_run:cmd('switch default') --- Replica isn't visible on master. -#box.info.replication +-- Test box.info.replication_anon. +box.info.replication_anon +#box.info.replication_anon() +uuid, tbl = next(box.info.replication_anon()) +-- Anonymous replicas are indexed by uuid strings. +require("uuid").fromstr(uuid) ~= nil +-- Anonymous replicas share box.info representation with +-- normal replicas. +tbl.downstream.status -- Test that replication (even anonymous) from an anonymous -- instance is forbidden. An anonymous replica will fetch