diff --git a/src/box/applier.cc b/src/box/applier.cc index 33c992b762b77570012ba1b2dd3f48e6771c21a9..b662fcaa900e57aa5874a73efc97d8739bf7e053 100644 --- a/src/box/applier.cc +++ b/src/box/applier.cc @@ -182,19 +182,6 @@ applier_connect(struct applier *applier) "Unsupported protocol for replication"); } - /* - * Forbid changing UUID dynamically on connect because - * applier is registered by UUID in the replica set. - */ - if (!tt_uuid_is_nil(&applier->uuid) && - !tt_uuid_is_equal(&applier->uuid, &greeting.uuid)) { - Exception *e = tnt_error(ClientError, ER_INSTANCE_UUID_MISMATCH, - tt_uuid_str(&applier->uuid), - tt_uuid_str(&greeting.uuid)); - applier_log_error(applier, e); - e->raise(); - } - if (applier->version_id != greeting.version_id) { say_info("remote master is %u.%u.%u at %s\r\n", version_id_major(greeting.version_id), diff --git a/src/box/replication.cc b/src/box/replication.cc index e5fd325c7a65edfce5fa90a5544fd3fbed3ffa1a..fe926d3127964dc097f530c7fd08245835cbba0f 100644 --- a/src/box/replication.cc +++ b/src/box/replication.cc @@ -233,12 +233,9 @@ replica_on_applier_connect(struct replica *replica) { struct applier *applier = replica->applier; - if (!tt_uuid_is_nil(&replica->uuid)) { - assert(tt_uuid_is_equal(&replica->uuid, &applier->uuid)); - return; - } - + assert(tt_uuid_is_nil(&replica->uuid)); assert(!tt_uuid_is_nil(&applier->uuid)); + replica->uuid = applier->uuid; replicaset.applier.connected++; @@ -270,6 +267,33 @@ replica_on_applier_connect(struct replica *replica) } } +static void +replica_on_applier_reconnect(struct replica *replica) +{ + struct applier *applier = replica->applier; + + assert(!tt_uuid_is_nil(&replica->uuid)); + assert(!tt_uuid_is_nil(&applier->uuid)); + + if (tt_uuid_is_equal(&replica->uuid, &applier->uuid)) + return; + + /* + * Master's UUID changed, most likely because it was + * rebootstrapped. Try to look up a replica matching + * the new UUID and reassign the applier to it. + */ + struct replica *new_replica = replica_by_uuid(&applier->uuid); + if (new_replica == NULL || new_replica->applier != NULL) { + tnt_raise(ClientError, ER_INSTANCE_UUID_MISMATCH, + tt_uuid_str(&replica->uuid), + tt_uuid_str(&applier->uuid)); + } + + replica_set_applier(new_replica, applier); + replica_clear_applier(replica); +} + static void replica_on_applier_state_f(struct trigger *trigger, void *event) { @@ -278,7 +302,10 @@ replica_on_applier_state_f(struct trigger *trigger, void *event) struct replica, on_applier_state); switch (replica->applier->state) { case APPLIER_CONNECTED: - replica_on_applier_connect(replica); + if (tt_uuid_is_nil(&replica->uuid)) + replica_on_applier_connect(replica); + else + replica_on_applier_reconnect(replica); break; case APPLIER_FOLLOW: replica_on_applier_sync(replica);