Skip to content

Commit

Permalink
replication: allow to pass instance name as bootstrap_leader
Browse files Browse the repository at this point in the history
Make it possible to specify the bootstrap leader via an instance name in
addition to its URI and UUID.

While I'm at it, change the argument order of box_check_node_name() to
comply with box_check_uuid/uri/uri_set().

Closes tarantool#8539

@TarantoolBot document
Title: `box.cfg.bootstrap_leader` accepts instance names now

The option `box.cfg.bootstrap_leader`, which specifies the desired
bootstrap leader when bootstrap_strategy is "config" now accepts
instance names.

For example, this is a valid config without replication:
```lua
box.cfg{
    instance_name = 'main-server',
    bootstrap_strategy = 'config',
    bootstrap_leader = 'main-server'
}
```

When `box.cfg` contains some entries in `replication`, the node will
bootstrap from the node which has the instance name specified in
`box.cfg.bootstrap_leader`.

This is an addition to tarantool/doc#3432
  • Loading branch information
sergepetrenko committed Jun 6, 2023
1 parent 8c8191b commit d7986d8
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 16 deletions.
15 changes: 15 additions & 0 deletions changelogs/unreleased/gh-8539-bootstrap-leader-name.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## feature/replication

* Added the ability to set the `bootstrap_leader` configuration option to the
instance name of the desired bootstrap leader:
```lua
box.cfg{
bootstrap_strategy = 'config',
bootstrap_leader = 'leader-name',
replication = {
...
},
...
}
```
(gh-7999, gh-8539).
27 changes: 17 additions & 10 deletions src/box/box.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1326,7 +1326,7 @@ box_check_instance_uuid(struct tt_uuid *uuid)

/** Fetch an optional node name from the config. */
static int
box_check_node_name(const char *cfg_name, char *out)
box_check_node_name(char *out, const char *cfg_name, bool set_diag)
{
const char *name = cfg_gets(cfg_name);
if (name == NULL) {
Expand All @@ -1335,8 +1335,10 @@ box_check_node_name(const char *cfg_name, char *out)
}
/* Nil name is allowed as Lua box.NULL or nil. Not as "". */
if (!node_name_is_valid(name)) {
diag_set(ClientError, ER_CFG, cfg_name,
"expected a valid name");
if (set_diag) {
diag_set(ClientError, ER_CFG, cfg_name,
"expected a valid name");
}
return -1;
}
strlcpy(out, name, NODE_NAME_SIZE_MAX);
Expand All @@ -1346,7 +1348,7 @@ box_check_node_name(const char *cfg_name, char *out)
static int
box_check_instance_name(char *out)
{
return box_check_node_name("instance_name", out);
return box_check_node_name(out, "instance_name", true);
}

static int
Expand All @@ -1357,10 +1359,11 @@ box_check_replicaset_uuid(struct tt_uuid *uuid)

/** Check bootstrap_leader option validity. */
static int
box_check_bootstrap_leader(struct uri *uri, struct tt_uuid *uuid)
box_check_bootstrap_leader(struct uri *uri, struct tt_uuid *uuid, char *name)
{
*uuid = uuid_nil;
uri_create(uri, NULL);
*name = '\0';
const char *source = cfg_gets("bootstrap_leader");
enum bootstrap_strategy strategy = box_check_bootstrap_strategy();
if (strategy != BOOTSTRAP_STRATEGY_CONFIG) {
Expand All @@ -1383,21 +1386,23 @@ box_check_bootstrap_leader(struct uri *uri, struct tt_uuid *uuid)
/* Not a uri. Try uuid then. */
if (box_check_uuid(uuid, "bootstrap_leader", false) == 0)
return 0;
if (box_check_node_name(name, "bootstrap_leader", false) == 0)
return 0;
diag_set(ClientError, ER_CFG, "bootstrap_leader",
"the value must be either a uri or a uuid");
"the value must be either a uri, a uuid or a name");
return -1;
}

static int
box_check_replicaset_name(char *out)
{
return box_check_node_name("replicaset_name", out);
return box_check_node_name(out, "replicaset_name", true);
}

static int
box_check_cluster_name(char *out)
{
return box_check_node_name("cluster_name", out);
return box_check_node_name(out, "cluster_name", true);
}

static enum wal_mode
Expand Down Expand Up @@ -1661,6 +1666,7 @@ box_check_config(void)
struct tt_uuid uuid;
struct uri uri;
struct uri_set uri_set;
char name[NODE_NAME_SIZE_MAX];
box_check_say();
box_check_audit();
if (box_check_flightrec() != 0)
Expand Down Expand Up @@ -1696,7 +1702,7 @@ box_check_config(void)
box_check_replication_sync_timeout();
if (box_check_bootstrap_strategy() == BOOTSTRAP_STRATEGY_INVALID)
diag_raise();
if (box_check_bootstrap_leader(&uri, &uuid) != 0)
if (box_check_bootstrap_leader(&uri, &uuid, name) != 0)
diag_raise();
uri_destroy(&uri);
box_check_readahead(cfg_geti("readahead"));
Expand Down Expand Up @@ -1878,7 +1884,8 @@ static int
box_set_bootstrap_leader(void)
{
return box_check_bootstrap_leader(&cfg_bootstrap_leader_uri,
&cfg_bootstrap_leader_uuid);
&cfg_bootstrap_leader_uuid,
cfg_bootstrap_leader_name);
}

/** Persist this instance as the bootstrap leader in _schema space. */
Expand Down
11 changes: 9 additions & 2 deletions src/box/replication.cc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ int replication_threads = 1;
bool cfg_replication_anon = true;
struct tt_uuid cfg_bootstrap_leader_uuid;
struct uri cfg_bootstrap_leader_uri;
char cfg_bootstrap_leader_name[NODE_NAME_SIZE_MAX];
char cfg_instance_name[NODE_NAME_SIZE_MAX];

struct replicaset replicaset;
Expand Down Expand Up @@ -948,6 +949,10 @@ applier_is_bootstrap_leader(const struct applier *applier)
{
assert(!tt_uuid_is_nil(&applier->uuid));
if (bootstrap_strategy == BOOTSTRAP_STRATEGY_CONFIG) {
if (*cfg_bootstrap_leader_name != '\0') {
return strcmp(applier->ballot.instance_name,
cfg_bootstrap_leader_name) == 0;
}
if (!tt_uuid_is_nil(&cfg_bootstrap_leader_uuid)) {
return tt_uuid_is_equal(&applier->uuid,
&cfg_bootstrap_leader_uuid);
Expand Down Expand Up @@ -1448,8 +1453,10 @@ replicaset_find_join_master_cfg(void)
if (applier_is_bootstrap_leader(applier))
leader = replica;
}
if (leader == NULL && !tt_uuid_is_equal(&cfg_bootstrap_leader_uuid,
&INSTANCE_UUID)) {
if (leader == NULL &&
!tt_uuid_is_equal(&cfg_bootstrap_leader_uuid, &INSTANCE_UUID) &&
(strcmp(cfg_bootstrap_leader_name, cfg_instance_name) != 0 ||
*cfg_bootstrap_leader_name == '\0')) {
tnt_raise(ClientError, ER_CFG, "bootstrap_leader",
"failed to connect to the bootstrap leader");
}
Expand Down
6 changes: 6 additions & 0 deletions src/box/replication.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ extern struct tt_uuid cfg_bootstrap_leader_uuid;
*/
extern struct uri cfg_bootstrap_leader_uri;

/**
* The name of the bootstrap leader configured via the bootstrap_leader
* configuration option.
*/
extern char cfg_bootstrap_leader_name[];

/**
* Configured name of this instance. Might be different from the actual name if
* the configuration is not fully applied yet.
Expand Down
28 changes: 24 additions & 4 deletions test/replication-luatest/bootstrap_strategy_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,26 @@ g_config.test_uuid = function(cg)
end)
end

g_config.after_test('test_uuid', function(cg)
cg.server1:stop()
g_config.before_test('test_name', function(cg)
cg.replica_set = replica_set:new{}
cg.server1 = cg.replica_set:build_and_add_server{
alias = 'server1',
box_cfg = {
bootstrap_strategy = 'config',
bootstrap_leader = 'server1name',
instance_name = 'server1name',
replication = nil,
},
}
end)

g_config.test_name = function(cg)
cg.replica_set:start()
t.helpers.retrying({}, cg.server1.exec, cg.server1, function()
t.assert_equals(box.info.status, 'running', 'The server is running')
end)
end

g_config.before_test('test_replication_without_bootstrap_leader', function(cg)
cg.replica_set = replica_set:new{}
cg.server1 = cg.replica_set:build_and_add_server{
Expand Down Expand Up @@ -335,6 +351,7 @@ end)
local g_config_success = t.group('gh-7999-bootstrap-strategy-config-success', {
{leader = 'server3'},
{leader = uuid3},
{leader = 'server3name'},
})

g_config_success.after_each(function(cg)
Expand All @@ -354,6 +371,7 @@ g_config_success.before_test('test_correct_bootstrap_leader', function(cg)
bootstrap_strategy = 'config',
bootstrap_leader = bootstrap_leader,
instance_uuid = uuid1,
instance_name = 'server1name',
replication = {
server.build_listen_uri('server1', cg.replica_set.id),
server.build_listen_uri('server2', cg.replica_set_a.id),
Expand All @@ -367,13 +385,15 @@ g_config_success.before_test('test_correct_bootstrap_leader', function(cg)
box_cfg = {
replicaset_uuid = uuida,
instance_uuid = uuid2,
instance_name = 'server2name',
}
}
cg.server3 = cg.replica_set_b:build_and_add_server{
alias = 'server3',
box_cfg = {
replicaset_uuid = uuidb,
instance_uuid = uuid3,
instance_name = 'server3name',
},
}
end)
Expand Down Expand Up @@ -418,6 +438,7 @@ g_config_success.before_test('test_wait_only_for_leader', function(cg)
box_cfg = {
replicaset_uuid = uuidb,
instance_uuid = uuid3,
instance_name = 'server3name',
},
}
end)
Expand Down Expand Up @@ -450,8 +471,7 @@ g_config_fail.test_bad_uri_or_uuid = function(cg)
{}, -- empty table.
{'a'}, -- non-empty table.
{3301},
'abracadabra', -- neither a URI or a UUID.
'z2345678-1234-1234-1234-12345678', -- not a UUID.
'1z345678-1234-1234-1234-12345678', -- not a UUID or a name.
}
local errmsg = "Incorrect value for option 'bootstrap_leader':"
local logfile = fio.pathjoin(cfg_failure.workdir, 'cfg_failure.log')
Expand Down

0 comments on commit d7986d8

Please sign in to comment.