From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 1BCF628076 for ; Wed, 29 Aug 2018 14:57:07 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id YJM64IurwHtq for ; Wed, 29 Aug 2018 14:57:06 -0400 (EDT) Received: from mail-lj1-f179.google.com (mail-lj1-f179.google.com [209.85.208.179]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 87ADB27981 for ; Wed, 29 Aug 2018 14:57:06 -0400 (EDT) Received: by mail-lj1-f179.google.com with SMTP id p6-v6so5249516ljc.5 for ; Wed, 29 Aug 2018 11:57:06 -0700 (PDT) From: Olga Arkhangelskaia Subject: [tarantool-patches] [PATCH v5 3/3] box: adds replication sync after cfg. update Date: Wed, 29 Aug 2018 21:56:42 +0300 Message-Id: <20180829185642.49479-3-krishtal.olja@gmail.com> In-Reply-To: <20180829185642.49479-1-krishtal.olja@gmail.com> References: <20180829185642.49479-1-krishtal.olja@gmail.com> Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: tarantool-patches@freelists.org Cc: Olga Arkhangelskaia When replica reconnects to replica set not for the first time, we suffer from absence of synchronization. Such behavior leads to giving away outdated data. @TarantoolBot document Title: Orphan status after configuration update or initial bootstrap. In case of initial bootstrap or after configuration update we can get an orphan status in two cases. If we synced up with number of replicas that is smaller than quorum or if we failed to sync up during the time specified in replication_sync_lag_timeout. Closes #3427 --- https://github.com/tarantool/tarantool/issues/3427 https://github.com/tarantool/tarantool/tree/OKriw/gh-3427-replication-no-sync-1.9 v1: https://www.freelists.org/post/tarantool-patches/PATCH-replication-adds-replication-sync-after-cfg-update v2: https://www.freelists.org/post/tarantool-patches/PATCH-v2-replication-adds-replication-sync-after-cfg-update v3: https://www.freelists.org/post/tarantool-patches/PATCH-v3-box-adds-replication-sync-after-cfg-update v4: https://www.freelists.org/post/tarantool-patches/PATCH-v4-22-box-adds-replication-sync-after-cfg-update Changes in v2: - fixed test - changed replicaset_sync Changes in v3: - now we raise the exception when sync is not successful. - fixed test - renamed test Changes in v4: - fixed test - replication_sync_lag is made dynamicall in separate patch - removed unnecessary error type - moved say_crit to another place - in case of sync error we rollback to prev. config Changes in v5: - added test case - now we don't roll back to prev. cfg src/box/box.cc | 7 ++- src/box/replication.cc | 12 ++--- src/box/replication.h | 6 +-- test/replication/sync.result | 112 +++++++++++++++++++++++++++++++++++++++++ test/replication/sync.test.lua | 57 +++++++++++++++++++++ 5 files changed, 184 insertions(+), 10 deletions(-) create mode 100644 test/replication/sync.result create mode 100644 test/replication/sync.test.lua diff --git a/src/box/box.cc b/src/box/box.cc index 0f8364ebc..6bae9ea78 100644 --- a/src/box/box.cc +++ b/src/box/box.cc @@ -646,6 +646,10 @@ box_set_replication(void) box_sync_replication(true); /* Follow replica */ replicaset_follow(); + /* Sync replica up to quorum */ + if (!replicaset_sync()) { + say_crit("entering orphan mode"); + } } void @@ -1967,7 +1971,8 @@ box_cfg_xc(void) is_box_configured = true; if (!is_bootstrap_leader) - replicaset_sync(); + if (!replicaset_sync()) + say_crit("entering orphan mode"); say_info("ready to accept requests"); } diff --git a/src/box/replication.cc b/src/box/replication.cc index 731b05faf..86d6f454b 100644 --- a/src/box/replication.cc +++ b/src/box/replication.cc @@ -661,13 +661,13 @@ replicaset_follow(void) } } -void +bool replicaset_sync(void) { int quorum = replicaset_quorum(); if (quorum == 0) - return; + return true; say_verbose("synchronizing with %d replicas", quorum); @@ -680,8 +680,8 @@ replicaset_sync(void) replicaset.applier.loading >= quorum) { if (fiber_cond_wait_timeout(&replicaset.applier.cond, replication_sync_lag_timeout) != 0) { - say_crit("replication_sync_lag_timeout fired, entering orphan mode"); - return; + say_crit("replication_sync_lag_timeout fired"); + return false; } } @@ -692,12 +692,12 @@ replicaset_sync(void) * Do not stall configuration, leave the instance * in 'orphan' state. */ - say_crit("entering orphan mode"); - return; + return false; } say_crit("replica set sync complete, quorum of %d " "replicas formed", quorum); + return true; } void diff --git a/src/box/replication.h b/src/box/replication.h index 71c17dc8e..512a4085e 100644 --- a/src/box/replication.h +++ b/src/box/replication.h @@ -379,10 +379,10 @@ replicaset_follow(void); /** * Wait until a replication quorum is formed. - * Return immediately if a quorum cannot be - * formed because of errors. + * @return true in case of success. + * @return false if a quorum cannot be formed because of errors. */ -void +bool replicaset_sync(void); /** diff --git a/test/replication/sync.result b/test/replication/sync.result new file mode 100644 index 000000000..875dfaa41 --- /dev/null +++ b/test/replication/sync.result @@ -0,0 +1,112 @@ +-- +-- gh-3427: no sync after configuration update +-- +-- +-- successful sync +-- +env = require('test_run') +--- +... +test_run = env.new() +--- +... +engine = test_run:get_cfg('engine') +--- +... +box.schema.user.grant('guest', 'replication') +--- +... +test_run:cmd("create server replica with rpl_master=default, script='replication/replica.lua'") +--- +- true +... +test_run:cmd("start server replica") +--- +- true +... +s = box.schema.space.create('test', {engine = engine}) +--- +... +index = s:create_index('primary') +--- +... +-- change replica configuration +test_run:cmd("switch replica") +--- +- true +... +box.cfg{replication_sync_lag = 0.1} +--- +... +replication = box.cfg.replication +--- +... +box.cfg{replication={}} +--- +... +test_run:cmd("switch default") +--- +- true +... +-- insert values on the master while replica is unconfigured +a = 100 box.begin() while a > 0 do a = a-1 box.space.test:insert{a,a} end box.commit() +--- +... +test_run:cmd("switch replica") +--- +- true +... +box.cfg{replication = replication} +--- +... +box.space.test:count() == 100 +--- +- true +... +-- +-- unsuccessful sync +-- +box.cfg{replication={}} +--- +... +box.cfg{replication_sync_lag_timeout = 0.001} +--- +... +test_run:cmd("switch default") +--- +- true +... +-- insert values on the master while replica is unconfigured +a = 200 box.begin() while a > 100 do a = a-1 box.space.test:insert{a,a} end box.commit() +--- +... +test_run:cmd("switch replica") +--- +- true +... +box.cfg{replication = replication} +--- +... +box.space.test:count() < 200 +--- +- true +... +test_run:cmd("switch default") +--- +- true +... +-- cleanup +test_run:cmd("stop server replica") +--- +- true +... +test_run:cmd("cleanup server replica") +--- +- true +... +box.space.test:drop() +--- +... +box.schema.user.revoke('guest', 'replication') +--- +... diff --git a/test/replication/sync.test.lua b/test/replication/sync.test.lua new file mode 100644 index 000000000..e63edd0d3 --- /dev/null +++ b/test/replication/sync.test.lua @@ -0,0 +1,57 @@ +-- +-- gh-3427: no sync after configuration update +-- + +-- +-- successful sync +-- + +env = require('test_run') +test_run = env.new() +engine = test_run:get_cfg('engine') + +box.schema.user.grant('guest', 'replication') + +test_run:cmd("create server replica with rpl_master=default, script='replication/replica.lua'") +test_run:cmd("start server replica") + +s = box.schema.space.create('test', {engine = engine}) +index = s:create_index('primary') + +-- change replica configuration +test_run:cmd("switch replica") +box.cfg{replication_sync_lag = 0.1} +replication = box.cfg.replication +box.cfg{replication={}} + +test_run:cmd("switch default") +-- insert values on the master while replica is unconfigured +a = 100 box.begin() while a > 0 do a = a-1 box.space.test:insert{a,a} end box.commit() + +test_run:cmd("switch replica") +box.cfg{replication = replication} + +box.space.test:count() == 100 + + +-- +-- unsuccessful sync +-- +box.cfg{replication={}} +box.cfg{replication_sync_lag_timeout = 0.001} + +test_run:cmd("switch default") +-- insert values on the master while replica is unconfigured +a = 200 box.begin() while a > 100 do a = a-1 box.space.test:insert{a,a} end box.commit() + +test_run:cmd("switch replica") +box.cfg{replication = replication} +box.space.test:count() < 200 + +test_run:cmd("switch default") + +-- cleanup +test_run:cmd("stop server replica") +test_run:cmd("cleanup server replica") +box.space.test:drop() +box.schema.user.revoke('guest', 'replication') -- 2.14.3 (Apple Git-98)