[tarantool-patches] [PATCH] [replication] introduce anonymous replicas.
Serge Petrenko
sergepetrenko at tarantool.org
Sat Oct 13 19:54:49 MSK 2018
This patch makes it possible for a replica to join/subscribe
anonymously, i.e. without being added to the _cluster table.
This allows to have more than VCLOCK_MAX (currently 32) replicas in a
replicaset, with a condition that some of them must be read only.
This is achieved by introducing a new field to JOIN/SUBSCRIBE
requests: IPROTO_REPLICA_ANON. Upon recieving a request with the option
set to true, master adds the newly connected replica to a replica hash,
but does not register it in _cluster table and does not assign an id to
it. The replica still appears in `box.info.replication` with
'anonymous` parameter set to true.
To make replica send 'anonymous' JOIN/SUBSCRIBE requests, a new config
option is introduced: `replica_anon`. It may only be set to true
together with `read_only`.
Closes #3186
---
https://github.com/tarantool/tarantool/issues/3186
https://github.com/tarantool/tarantool/tree/sp/gh-3186-anon-replica
src/box/alter.cc | 2 +-
src/box/applier.cc | 4 +-
src/box/applier.h | 1 +
src/box/box.cc | 55 +++++++++++--
src/box/box.h | 2 +
src/box/iproto_constants.h | 1 +
src/box/lua/info.c | 35 +++++++--
src/box/lua/load_cfg.lua | 2 +
src/box/relay.cc | 2 +-
src/box/replication.cc | 16 +++-
src/box/replication.h | 11 ++-
src/box/xrow.c | 26 +++++--
src/box/xrow.h | 35 +++++----
test/app-tap/init_script.result | 51 ++++++------
test/box/admin.result | 2 +
test/box/cfg.result | 4 +
test/replication/replica_anon.lua | 9 +++
test/replication/replica_anon.result | 103 +++++++++++++++++++++++++
test/replication/replica_anon.test.lua | 41 ++++++++++
19 files changed, 337 insertions(+), 65 deletions(-)
create mode 100644 test/replication/replica_anon.lua
create mode 100644 test/replication/replica_anon.result
create mode 100644 test/replication/replica_anon.test.lua
diff --git a/src/box/alter.cc b/src/box/alter.cc
index 4ac44c240..a26bd7edf 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -2916,7 +2916,7 @@ on_commit_dd_cluster(struct trigger *trigger, void *event)
replica_set_id(replica, id);
} else {
try {
- replica = replicaset_add(id, &uuid);
+ replica = replicaset_add(id, &uuid, false);
/* Can't throw exceptions from on_commit trigger */
} catch(Exception *e) {
panic("Can't register replica: %s", e->errmsg);
diff --git a/src/box/applier.cc b/src/box/applier.cc
index 7da278e68..5ac0134aa 100644
--- a/src/box/applier.cc
+++ b/src/box/applier.cc
@@ -278,7 +278,7 @@ applier_join(struct applier *applier)
struct ev_io *coio = &applier->io;
struct ibuf *ibuf = &applier->ibuf;
struct xrow_header row;
- xrow_encode_join_xc(&row, &INSTANCE_UUID);
+ xrow_encode_join_xc(&row, &INSTANCE_UUID, replica_anon);
coio_write_xrow(coio, &row);
/**
@@ -388,7 +388,7 @@ applier_subscribe(struct applier *applier)
struct vclock remote_vclock_at_subscribe;
xrow_encode_subscribe_xc(&row, &REPLICASET_UUID, &INSTANCE_UUID,
- &replicaset.vclock);
+ &replicaset.vclock, replica_anon);
coio_write_xrow(coio, &row);
/* Read SUBSCRIBE response */
diff --git a/src/box/applier.h b/src/box/applier.h
index 5a9c40fc8..5d5cbf978 100644
--- a/src/box/applier.h
+++ b/src/box/applier.h
@@ -42,6 +42,7 @@
#include "trivia/util.h"
#include "tt_uuid.h"
#include "uri.h"
+#include "box.h" /* replica_anon */
#include "xrow.h"
diff --git a/src/box/box.cc b/src/box/box.cc
index 7e32b9fc7..38d8b5db4 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -109,6 +109,9 @@ static struct gc_checkpoint_ref backup_gc;
*/
static bool is_box_configured = false;
static bool is_ro = true;
+
+bool replica_anon = false;
+
static fiber_cond ro_cond;
/**
@@ -217,6 +220,10 @@ process_nop(struct request *request)
void
box_set_ro(bool ro)
{
+ if(replica_anon && !ro) {
+ tnt_raise(ClientError, ER_CFG, "read_only",
+ "instance is anonymous and cannot become writeable.");
+ }
is_ro = ro;
fiber_cond_broadcast(&ro_cond);
}
@@ -465,6 +472,17 @@ box_check_replication_sync_timeout(void)
return timeout;
}
+static bool
+box_check_replica_anon(void)
+{
+ bool is_anon = cfg_geti("replica_anon") != 0;
+ if (is_anon && !is_ro) {
+ tnt_raise(ClientError, ER_CFG, "replica_anon",
+ "only a read-only instance may be anonymous.");
+ }
+ return is_anon;
+}
+
static void
box_check_instance_uuid(struct tt_uuid *uuid)
{
@@ -745,6 +763,12 @@ box_set_replication_skip_conflict(void)
replication_skip_conflict = cfg_geti("replication_skip_conflict");
}
+void
+box_set_replica_anon(void)
+{
+ replica_anon = box_check_replica_anon();
+}
+
void
box_listen(void)
{
@@ -1419,7 +1443,8 @@ box_process_join(struct ev_io *io, struct xrow_header *header)
/* Decode JOIN request */
struct tt_uuid instance_uuid = uuid_nil;
- xrow_decode_join_xc(header, &instance_uuid);
+ bool anon;
+ xrow_decode_join_xc(header, &instance_uuid, &anon);
/* Check that bootstrap has been finished */
if (!is_box_configured)
@@ -1439,7 +1464,7 @@ box_process_join(struct ev_io *io, struct xrow_header *header)
* appropriate access privileges.
*/
struct replica *replica = replica_by_uuid(&instance_uuid);
- if (replica == NULL || replica->id == REPLICA_ID_NIL) {
+ if ((replica == NULL || replica->id == REPLICA_ID_NIL) && !anon) {
box_check_writable_xc();
struct space *space = space_cache_find_xc(BOX_CLUSTER_ID);
access_check_space_xc(space, PRIV_W);
@@ -1492,7 +1517,15 @@ box_process_join(struct ev_io *io, struct xrow_header *header)
* sending OK - if the hook fails, the error reaches the
* client.
*/
- box_on_join(&instance_uuid);
+ if (!anon)
+ box_on_join(&instance_uuid);
+ else {
+ /*
+ * In case of an anonymous join manually add a
+ * replica to replica hash.
+ */
+ replicaset_add(REPLICA_ID_NIL, &instance_uuid, true);
+ }
replica = replica_by_uuid(&instance_uuid);
assert(replica != NULL);
@@ -1543,8 +1576,9 @@ box_process_subscribe(struct ev_io *io, struct xrow_header *header)
struct vclock replica_clock;
uint32_t replica_version_id;
vclock_create(&replica_clock);
+ bool anon;
xrow_decode_subscribe_xc(header, &replicaset_uuid, &replica_uuid,
- &replica_clock, &replica_version_id);
+ &replica_clock, &replica_version_id, &anon);
/* Forbid connection to itself */
if (tt_uuid_is_equal(&replica_uuid, &INSTANCE_UUID))
@@ -1567,11 +1601,19 @@ box_process_subscribe(struct ev_io *io, struct xrow_header *header)
/* Check replica uuid */
struct replica *replica = replica_by_uuid(&replica_uuid);
- if (replica == NULL || replica->id == REPLICA_ID_NIL) {
+ if ((replica == NULL || replica->id == REPLICA_ID_NIL) && !anon) {
tnt_raise(ClientError, ER_UNKNOWN_REPLICA,
tt_uuid_str(&replica_uuid),
tt_uuid_str(&REPLICASET_UUID));
}
+ /*
+ * This is an anonymous subscribe. We have to manually add a
+ * replica to replica hash.
+ */
+ if (replica == NULL) {
+ replicaset_add(REPLICA_ID_NIL, &replica_uuid, true);
+ replica = replica_by_uuid(&replica_uuid);
+ }
/* Don't allow multiple relays for the same replica */
if (relay_get_state(replica->relay) == RELAY_FOLLOW) {
@@ -2051,6 +2093,7 @@ box_cfg_xc(void)
box_set_replication_sync_lag();
box_set_replication_sync_timeout();
box_set_replication_skip_conflict();
+ box_set_replica_anon();
xstream_create(&join_stream, apply_initial_join_row);
xstream_create(&subscribe_stream, apply_row);
@@ -2086,7 +2129,7 @@ box_cfg_xc(void)
/* Check for correct registration of the instance in _cluster */
{
struct replica *self = replica_by_uuid(&INSTANCE_UUID);
- if (self == NULL || self->id == REPLICA_ID_NIL) {
+ if ((self == NULL || self->id == REPLICA_ID_NIL) && !replica_anon) {
tnt_raise(ClientError, ER_UNKNOWN_REPLICA,
tt_uuid_str(&INSTANCE_UUID),
tt_uuid_str(&REPLICASET_UUID));
diff --git a/src/box/box.h b/src/box/box.h
index 9930d4a1a..42fe7845f 100644
--- a/src/box/box.h
+++ b/src/box/box.h
@@ -116,6 +116,8 @@ extern bool box_checkpoint_is_in_progress;
/** Incremented with each next snapshot. */
extern uint32_t snapshot_version;
+extern bool replica_anon;
+
/**
* Iterate over all spaces and save them to the
* snapshot file.
diff --git a/src/box/iproto_constants.h b/src/box/iproto_constants.h
index 404f97a2e..ccb1599a2 100644
--- a/src/box/iproto_constants.h
+++ b/src/box/iproto_constants.h
@@ -79,6 +79,7 @@ enum iproto_key {
IPROTO_OPS = 0x28, /* UPSERT but not UPDATE ops, because of legacy */
IPROTO_BALLOT = 0x29,
IPROTO_TUPLE_META = 0x2a,
+ IPROTO_REPLICA_ANON = 0x2b,
/* Leave a gap between request keys and response keys */
IPROTO_DATA = 0x30,
IPROTO_ERROR = 0x31,
diff --git a/src/box/lua/info.c b/src/box/lua/info.c
index 655768ec4..693b4674d 100644
--- a/src/box/lua/info.c
+++ b/src/box/lua/info.c
@@ -132,18 +132,27 @@ lbox_pushreplica(lua_State *L, struct replica *replica)
/* 16 is used to get the best visual experience in YAML output */
lua_createtable(L, 0, 16);
+ /* An anonymous replica has a zero id. */
+ if (!replica->is_anon)
+ {
+ lua_pushstring(L, "id");
+ lua_pushinteger(L, replica->id);
+ lua_settable(L, -3);
+ }
- lua_pushstring(L, "id");
- lua_pushinteger(L, replica->id);
+ lua_pushstring(L, "anonymous");
+ lua_pushboolean(L, replica->is_anon);
lua_settable(L, -3);
lua_pushstring(L, "uuid");
lua_pushstring(L, tt_uuid_str(&replica->uuid));
lua_settable(L, -3);
-
- lua_pushstring(L, "lsn");
- luaL_pushuint64(L, vclock_get(&replicaset.vclock, replica->id));
- lua_settable(L, -3);
+ /* Anonymous replica's lsn isn't added to the vclock. */
+ if (!replica->is_anon) {
+ lua_pushstring(L, "lsn");
+ luaL_pushuint64(L, vclock_get(&replicaset.vclock, replica->id));
+ lua_settable(L, -3);
+ }
if (applier != NULL && applier->state != APPLIER_OFF) {
lua_pushstring(L, "upstream");
@@ -185,6 +194,7 @@ lbox_info_replication(struct lua_State *L)
lua_setfield(L, -2, "__serialize");
lua_setmetatable(L, -2);
+ uint32_t anon_ctr = 0;
replicaset_foreach(replica) {
/* Applier hasn't received replica id yet */
if (replica->id == REPLICA_ID_NIL)
@@ -193,6 +203,19 @@ lbox_info_replication(struct lua_State *L)
lbox_pushreplica(L, replica);
lua_rawseti(L, -2, replica->id);
+ /*
+ * Needed to start enumerating anonymous replicas
+ * after the usual ones.
+ */
+ anon_ctr = MAX(anon_ctr, replica->id);
+ }
+ replicaset_foreach(replica) {
+ if (!replica->is_anon)
+ continue;
+
+ lbox_pushreplica(L, replica);
+
+ lua_rawseti(L, -2, ++anon_ctr);
}
return 1;
diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua
index f62f4dc1e..ddf0c0c20 100644
--- a/src/box/lua/load_cfg.lua
+++ b/src/box/lua/load_cfg.lua
@@ -76,6 +76,7 @@ local default_cfg = {
replication_connect_timeout = 30,
replication_connect_quorum = nil, -- connect all
replication_skip_conflict = false,
+ replica_anon = false,
feedback_enabled = true,
feedback_host = "https://feedback.tarantool.io",
feedback_interval = 3600,
@@ -138,6 +139,7 @@ local template_cfg = {
replication_connect_timeout = 'number',
replication_connect_quorum = 'number',
replication_skip_conflict = 'boolean',
+ replica_anon = 'boolean',
feedback_enabled = 'boolean',
feedback_host = 'string',
feedback_interval = 'number',
diff --git a/src/box/relay.cc b/src/box/relay.cc
index d5df487eb..0182cb833 100644
--- a/src/box/relay.cc
+++ b/src/box/relay.cc
@@ -583,7 +583,7 @@ void
relay_subscribe(struct replica *replica, int fd, uint64_t sync,
struct vclock *replica_clock, uint32_t replica_version_id)
{
- assert(replica->id != REPLICA_ID_NIL);
+ assert(replica->id != REPLICA_ID_NIL || replica->is_anon);
struct relay *relay = replica->relay;
assert(relay->state != RELAY_FOLLOW);
/*
diff --git a/src/box/replication.cc b/src/box/replication.cc
index 2cb4ec0f8..864f03482 100644
--- a/src/box/replication.cc
+++ b/src/box/replication.cc
@@ -150,6 +150,7 @@ replica_new(void)
replica->uuid = uuid_nil;
replica->applier = NULL;
replica->gc = NULL;
+ replica->is_anon = false;
rlist_create(&replica->in_anon);
trigger_create(&replica->on_applier_state,
replica_on_applier_state_f, NULL, NULL);
@@ -170,17 +171,26 @@ replica_delete(struct replica *replica)
free(replica);
}
+static void
+replica_set_anon(struct replica *replica, bool is_anon)
+{
+ replica->is_anon = is_anon;
+}
+
struct replica *
-replicaset_add(uint32_t replica_id, const struct tt_uuid *replica_uuid)
+replicaset_add(uint32_t replica_id, const struct tt_uuid *replica_uuid, bool is_anon)
{
assert(!tt_uuid_is_nil(replica_uuid));
- assert(replica_id != REPLICA_ID_NIL && replica_id < VCLOCK_MAX);
+ assert(replica_id != REPLICA_ID_NIL && replica_id < VCLOCK_MAX ||
+ is_anon && replica_id == REPLICA_ID_NIL);
assert(replica_by_uuid(replica_uuid) == NULL);
struct replica *replica = replica_new();
+ replica_set_anon(replica, is_anon);
replica->uuid = *replica_uuid;
replica_hash_insert(&replicaset.hash, replica);
- replica_set_id(replica, replica_id);
+ if (!is_anon)
+ replica_set_id(replica, replica_id);
return replica;
}
diff --git a/src/box/replication.h b/src/box/replication.h
index 2ac620d86..4cf2edc03 100644
--- a/src/box/replication.h
+++ b/src/box/replication.h
@@ -274,6 +274,12 @@ struct replica {
enum applier_state applier_sync_state;
/* The latch is used to order replication requests. */
struct latch order_latch;
+ /**
+ * A flag indicating that the replica is anonymous,
+ * i.e. is joined/subscribed without being added
+ * to the _cluster table.
+ */
+ bool is_anon;
};
enum {
@@ -343,10 +349,11 @@ replica_check_id(uint32_t replica_id);
* Register the universally unique identifier of a remote replica and
* a matching replica-set-local identifier in the _cluster registry.
* Called from on_replace_dd_cluster() when a remote master joins the
- * replica set.
+ * replica set or from box_process_join() upon an anonymous join.
*/
struct replica *
-replicaset_add(uint32_t replica_id, const struct tt_uuid *instance_uuid);
+replicaset_add(uint32_t replica_id, const struct tt_uuid *instance_uuid,
+ bool is_anon);
/**
* Try to connect appliers to remote peers and receive UUID.
diff --git a/src/box/xrow.c b/src/box/xrow.c
index f12b27ace..8d0698412 100644
--- a/src/box/xrow.c
+++ b/src/box/xrow.c
@@ -968,7 +968,8 @@ int
xrow_encode_subscribe(struct xrow_header *row,
const struct tt_uuid *replicaset_uuid,
const struct tt_uuid *instance_uuid,
- const struct vclock *vclock)
+ const struct vclock *vclock,
+ bool is_anon)
{
memset(row, 0, sizeof(*row));
size_t size = XROW_BODY_LEN_MAX + mp_sizeof_vclock(vclock);
@@ -978,7 +979,7 @@ xrow_encode_subscribe(struct xrow_header *row,
return -1;
}
char *data = buf;
- data = mp_encode_map(data, 4);
+ data = mp_encode_map(data, 5);
data = mp_encode_uint(data, IPROTO_CLUSTER_UUID);
data = xrow_encode_uuid(data, replicaset_uuid);
data = mp_encode_uint(data, IPROTO_INSTANCE_UUID);
@@ -987,6 +988,8 @@ xrow_encode_subscribe(struct xrow_header *row,
data = mp_encode_vclock(data, vclock);
data = mp_encode_uint(data, IPROTO_SERVER_VERSION);
data = mp_encode_uint(data, tarantool_version_id());
+ data = mp_encode_uint(data, IPROTO_REPLICA_ANON);
+ data = mp_encode_bool(data, is_anon);
assert(data <= buf + size);
row->body[0].iov_base = buf;
row->body[0].iov_len = (data - buf);
@@ -998,7 +1001,7 @@ xrow_encode_subscribe(struct xrow_header *row,
int
xrow_decode_subscribe(struct xrow_header *row, struct tt_uuid *replicaset_uuid,
struct tt_uuid *instance_uuid, struct vclock *vclock,
- uint32_t *version_id)
+ uint32_t *version_id, bool *is_anon)
{
if (row->bodycnt == 0) {
diag_set(ClientError, ER_INVALID_MSGPACK, "request body");
@@ -1054,6 +1057,16 @@ xrow_decode_subscribe(struct xrow_header *row, struct tt_uuid *replicaset_uuid,
}
*version_id = mp_decode_uint(&d);
break;
+ case IPROTO_REPLICA_ANON:
+ if (is_anon == NULL)
+ goto skip;
+ if (mp_typeof(*d) != MP_BOOL) {
+ diag_set(ClientError, ER_INVALID_MSGPACK,
+ "invalid ANON");
+ return -1;
+ }
+ *is_anon = mp_decode_bool(&d);
+ break;
default: skip:
mp_next(&d); /* value */
}
@@ -1062,7 +1075,8 @@ xrow_decode_subscribe(struct xrow_header *row, struct tt_uuid *replicaset_uuid,
}
int
-xrow_encode_join(struct xrow_header *row, const struct tt_uuid *instance_uuid)
+xrow_encode_join(struct xrow_header *row, const struct tt_uuid *instance_uuid,
+ bool is_anon)
{
memset(row, 0, sizeof(*row));
@@ -1073,10 +1087,12 @@ xrow_encode_join(struct xrow_header *row, const struct tt_uuid *instance_uuid)
return -1;
}
char *data = buf;
- data = mp_encode_map(data, 1);
+ data = mp_encode_map(data, 2);
data = mp_encode_uint(data, IPROTO_INSTANCE_UUID);
/* Greet the remote replica with our replica UUID */
data = xrow_encode_uuid(data, instance_uuid);
+ data = mp_encode_uint(data, IPROTO_REPLICA_ANON);
+ data = mp_encode_bool(data, is_anon);
assert(data <= buf + size);
row->body[0].iov_base = buf;
diff --git a/src/box/xrow.h b/src/box/xrow.h
index 3fc007a8d..2e9bb0130 100644
--- a/src/box/xrow.h
+++ b/src/box/xrow.h
@@ -257,6 +257,7 @@ xrow_encode_vote(struct xrow_header *row);
* @param replicaset_uuid Replica set uuid.
* @param instance_uuid Instance uuid.
* @param vclock Replication clock.
+ * @param is_anon Whether to encode an anonymous SUBSCRIBE.
*
* @retval 0 Success.
* @retval -1 Memory error.
@@ -265,7 +266,7 @@ int
xrow_encode_subscribe(struct xrow_header *row,
const struct tt_uuid *replicaset_uuid,
const struct tt_uuid *instance_uuid,
- const struct vclock *vclock);
+ const struct vclock *vclock, bool is_anon);
/**
* Decode SUBSCRIBE command.
@@ -274,6 +275,7 @@ xrow_encode_subscribe(struct xrow_header *row,
* @param[out] instance_uuid.
* @param[out] vclock.
* @param[out] version_id.
+ * @param[out] is_anon.
*
* @retval 0 Success.
* @retval -1 Memory or format error.
@@ -281,31 +283,35 @@ xrow_encode_subscribe(struct xrow_header *row,
int
xrow_decode_subscribe(struct xrow_header *row, struct tt_uuid *replicaset_uuid,
struct tt_uuid *instance_uuid, struct vclock *vclock,
- uint32_t *version_id);
+ uint32_t *version_id, bool *is_anon);
/**
* Encode JOIN command.
* @param[out] row Row to encode into.
* @param instance_uuid.
+ * @param is_anon Whether to encode an anonymous JOIN.
*
* @retval 0 Success.
* @retval -1 Memory error.
*/
int
-xrow_encode_join(struct xrow_header *row, const struct tt_uuid *instance_uuid);
+xrow_encode_join(struct xrow_header *row, const struct tt_uuid *instance_uuid,
+ bool is_anon);
/**
* Decode JOIN command.
* @param row Row to decode.
* @param[out] instance_uuid.
+ * @param[out] is_anon.
*
* @retval 0 Success.
* @retval -1 Memory or format error.
*/
static inline int
-xrow_decode_join(struct xrow_header *row, struct tt_uuid *instance_uuid)
+xrow_decode_join(struct xrow_header *row, struct tt_uuid *instance_uuid,
+ bool *is_anon)
{
- return xrow_decode_subscribe(row, NULL, instance_uuid, NULL, NULL);
+ return xrow_decode_subscribe(row, NULL, instance_uuid, NULL, NULL, is_anon);
}
/**
@@ -330,7 +336,7 @@ xrow_encode_vclock(struct xrow_header *row, const struct vclock *vclock);
static inline int
xrow_decode_vclock(struct xrow_header *row, struct vclock *vclock)
{
- return xrow_decode_subscribe(row, NULL, NULL, vclock, NULL);
+ return xrow_decode_subscribe(row, NULL, NULL, vclock, NULL, NULL);
}
/**
@@ -644,10 +650,10 @@ static inline void
xrow_encode_subscribe_xc(struct xrow_header *row,
const struct tt_uuid *replicaset_uuid,
const struct tt_uuid *instance_uuid,
- const struct vclock *vclock)
+ const struct vclock *vclock, bool is_anon)
{
if (xrow_encode_subscribe(row, replicaset_uuid, instance_uuid,
- vclock) != 0)
+ vclock, is_anon) != 0)
diag_raise();
}
@@ -656,27 +662,28 @@ static inline void
xrow_decode_subscribe_xc(struct xrow_header *row,
struct tt_uuid *replicaset_uuid,
struct tt_uuid *instance_uuid, struct vclock *vclock,
- uint32_t *replica_version_id)
+ uint32_t *replica_version_id, bool *is_anon)
{
if (xrow_decode_subscribe(row, replicaset_uuid, instance_uuid,
- vclock, replica_version_id) != 0)
+ vclock, replica_version_id, is_anon) != 0)
diag_raise();
}
/** @copydoc xrow_encode_join. */
static inline void
xrow_encode_join_xc(struct xrow_header *row,
- const struct tt_uuid *instance_uuid)
+ const struct tt_uuid *instance_uuid, bool is_anon)
{
- if (xrow_encode_join(row, instance_uuid) != 0)
+ if (xrow_encode_join(row, instance_uuid, is_anon) != 0)
diag_raise();
}
/** @copydoc xrow_decode_join. */
static inline void
-xrow_decode_join_xc(struct xrow_header *row, struct tt_uuid *instance_uuid)
+xrow_decode_join_xc(struct xrow_header *row, struct tt_uuid *instance_uuid,
+ bool *is_anon)
{
- if (xrow_decode_join(row, instance_uuid) != 0)
+ if (xrow_decode_join(row, instance_uuid, is_anon) != 0)
diag_raise();
}
diff --git a/test/app-tap/init_script.result b/test/app-tap/init_script.result
index a2191d15b..a0c802504 100644
--- a/test/app-tap/init_script.result
+++ b/test/app-tap/init_script.result
@@ -25,31 +25,32 @@ box.cfg
20 pid_file:box.pid
21 read_only:false
22 readahead:16320
-23 replication_connect_timeout:30
-24 replication_skip_conflict:false
-25 replication_sync_lag:10
-26 replication_sync_timeout:300
-27 replication_timeout:1
-28 rows_per_wal:500000
-29 slab_alloc_factor:1.05
-30 too_long_threshold:0.5
-31 vinyl_bloom_fpr:0.05
-32 vinyl_cache:134217728
-33 vinyl_dir:.
-34 vinyl_max_tuple_size:1048576
-35 vinyl_memory:134217728
-36 vinyl_page_size:8192
-37 vinyl_range_size:1073741824
-38 vinyl_read_threads:1
-39 vinyl_run_count_per_level:2
-40 vinyl_run_size_ratio:3.5
-41 vinyl_timeout:60
-42 vinyl_write_threads:4
-43 wal_dir:.
-44 wal_dir_rescan_delay:2
-45 wal_max_size:268435456
-46 wal_mode:write
-47 worker_pool_threads:4
+23 replica_anon:false
+24 replication_connect_timeout:30
+25 replication_skip_conflict:false
+26 replication_sync_lag:10
+27 replication_sync_timeout:300
+28 replication_timeout:1
+29 rows_per_wal:500000
+30 slab_alloc_factor:1.05
+31 too_long_threshold:0.5
+32 vinyl_bloom_fpr:0.05
+33 vinyl_cache:134217728
+34 vinyl_dir:.
+35 vinyl_max_tuple_size:1048576
+36 vinyl_memory:134217728
+37 vinyl_page_size:8192
+38 vinyl_range_size:1073741824
+39 vinyl_read_threads:1
+40 vinyl_run_count_per_level:2
+41 vinyl_run_size_ratio:3.5
+42 vinyl_timeout:60
+43 vinyl_write_threads:4
+44 wal_dir:.
+45 wal_dir_rescan_delay:2
+46 wal_max_size:268435456
+47 wal_mode:write
+48 worker_pool_threads:4
--
-- Test insert from detached fiber
--
diff --git a/test/box/admin.result b/test/box/admin.result
index 8048460a1..d84df7a56 100644
--- a/test/box/admin.result
+++ b/test/box/admin.result
@@ -62,6 +62,8 @@ cfg_filter(box.cfg)
- false
- - readahead
- 16320
+ - - replica_anon
+ - false
- - replication_connect_timeout
- 30
- - replication_skip_conflict
diff --git a/test/box/cfg.result b/test/box/cfg.result
index 515033754..3078f7fad 100644
--- a/test/box/cfg.result
+++ b/test/box/cfg.result
@@ -58,6 +58,8 @@ cfg_filter(box.cfg)
- false
- - readahead
- 16320
+ - - replica_anon
+ - false
- - replication_connect_timeout
- 30
- - replication_skip_conflict
@@ -159,6 +161,8 @@ cfg_filter(box.cfg)
- false
- - readahead
- 16320
+ - - replica_anon
+ - false
- - replication_connect_timeout
- 30
- - replication_skip_conflict
diff --git a/test/replication/replica_anon.lua b/test/replication/replica_anon.lua
new file mode 100644
index 000000000..0e5b314f3
--- /dev/null
+++ b/test/replication/replica_anon.lua
@@ -0,0 +1,9 @@
+#!/usr/bin/env tarantool
+
+require("console").listen(os.getenv("ADMIN"))
+
+box.cfg{
+ read_only=true,
+ replica_anon=true,
+ replication=os.getenv("MASTER")
+}
diff --git a/test/replication/replica_anon.result b/test/replication/replica_anon.result
new file mode 100644
index 000000000..58a892961
--- /dev/null
+++ b/test/replication/replica_anon.result
@@ -0,0 +1,103 @@
+test_run = require('test_run').new()
+---
+...
+box.schema.user.grant("guest", "replication")
+---
+...
+_ = box.schema.space.create("test")
+---
+...
+_ = box.space.test:create_index("pk")
+---
+...
+for i = 1, 100 do box.space.test:auto_increment{} end
+---
+...
+test_run:cmd("create server replica_anon with rpl_master=default, script='replication/replica_anon.lua'")
+---
+- true
+...
+test_run:cmd('start server replica_anon')
+---
+- true
+...
+-- Check anonymous join + subscribe.
+test_run:cmd("switch replica_anon")
+---
+- true
+...
+box.space.test:count()
+---
+- 100
+...
+box.info.replication[1].upstream.status
+---
+- follow
+...
+test_run:cmd("switch default")
+---
+- true
+...
+test_run:cmd("stop server replica_anon")
+---
+- true
+...
+for i = 1, 100 do box.space.test:auto_increment{} end
+---
+...
+-- Check anonymous subscribe without join.
+test_run:cmd("start server replica_anon")
+---
+- true
+...
+test_run:cmd("switch replica_anon")
+---
+- true
+...
+box.space.test:count()
+---
+- 200
+...
+test_run:cmd("switch default")
+---
+- true
+...
+for i = 1, 100 do box.space.test:auto_increment{} end
+---
+...
+-- Check following updates.
+test_run:cmd("switch replica_anon")
+---
+- true
+...
+while box.space.test:count() < 300 do fiber.sleep(0.01) end
+---
+...
+box.space.test:count()
+---
+- 300
+...
+test_run:cmd("switch default")
+---
+- true
+...
+-- Check display of anonymous replicas in box.info.
+box.info.replication[#box.info.replication].anonymous
+---
+- true
+...
+-- Cleanup.
+test_run:cmd("stop server replica_anon")
+---
+- true
+...
+test_run:cmd("cleanup server replica_anon")
+---
+- true
+...
+box.schema.user.revoke("guest", "replication")
+---
+...
+box.space.test:drop()
+---
+...
diff --git a/test/replication/replica_anon.test.lua b/test/replication/replica_anon.test.lua
new file mode 100644
index 000000000..a105f4d45
--- /dev/null
+++ b/test/replication/replica_anon.test.lua
@@ -0,0 +1,41 @@
+test_run = require('test_run').new()
+
+box.schema.user.grant("guest", "replication")
+_ = box.schema.space.create("test")
+_ = box.space.test:create_index("pk")
+
+for i = 1, 100 do box.space.test:auto_increment{} end
+
+test_run:cmd("create server replica_anon with rpl_master=default, script='replication/replica_anon.lua'")
+test_run:cmd('start server replica_anon')
+-- Check anonymous join + subscribe.
+test_run:cmd("switch replica_anon")
+box.space.test:count()
+box.info.replication[1].upstream.status
+test_run:cmd("switch default")
+
+test_run:cmd("stop server replica_anon")
+
+for i = 1, 100 do box.space.test:auto_increment{} end
+-- Check anonymous subscribe without join.
+test_run:cmd("start server replica_anon")
+test_run:cmd("switch replica_anon")
+box.space.test:count()
+test_run:cmd("switch default")
+
+for i = 1, 100 do box.space.test:auto_increment{} end
+
+-- Check following updates.
+test_run:cmd("switch replica_anon")
+while box.space.test:count() < 300 do fiber.sleep(0.01) end
+box.space.test:count()
+test_run:cmd("switch default")
+
+-- Check display of anonymous replicas in box.info.
+box.info.replication[#box.info.replication].anonymous
+
+-- Cleanup.
+test_run:cmd("stop server replica_anon")
+test_run:cmd("cleanup server replica_anon")
+box.schema.user.revoke("guest", "replication")
+box.space.test:drop()
--
2.17.1 (Apple Git-112)
More information about the Tarantool-patches
mailing list