diff --git a/.gitignore b/.gitignore index 62e3fa457137617f8250d433053bf6bb75b21f52..7f5982e9987ec714206f5c5e456a1131c69e9d78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,6 @@ .gitignore .gdb_history TAGS -_debug_box -_release_box -_debug_feeder -_release_feeder config.mk lcov *.o @@ -19,7 +15,6 @@ CMakeFiles CMakeCache.txt cmake_install.cmake mod/box/tarantool_box -mod/feeder/tarantool_feeder include/config.h CPackConfig.cmake CPackSourceConfig.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index ac2bda1b96703298804bcb91acf6e51fe1144517..c647bb3b3c3ff1caa7ce5ad509bf89c88faa1ad9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ include(cmake/check_objective_c_compiler.cmake) # and what modules to produce. # set (TARANTOOL_PRODUCT "box") -set (TARANTOOL_MODULES "box" "feeder") +set (TARANTOOL_MODULES "box") # # Set default build type to Debug. This is to ease a developer's diff --git a/cfg/core_cfg.cfg_tmpl b/cfg/core_cfg.cfg_tmpl index ca18e226b7c0e6e370c349ddf4eaa0dce410bb34..b73e138195445e12eb73330fa66791a963b62f39 100644 --- a/cfg/core_cfg.cfg_tmpl +++ b/cfg/core_cfg.cfg_tmpl @@ -1,6 +1,10 @@ # username to switch to username=NULL, ro +# tarantool bind ip address, applies to master +# and replication ports. INADDR_ANY is the default value. +bind_ipaddr="INADDR_ANY", ro + # save core on abort/assert # deprecated; use ulimit instead coredump=0, ro @@ -9,6 +13,9 @@ coredump=0, ro # used for admin's connections admin_port=0, ro +# Replication clients should use this port (bind_ipaddr:replication_port). +replication_port=0, ro + # Log verbosity, possible values: ERROR=1, CRIT=2, WARN=3, INFO=4(default), DEBUG=5 log_level=4 diff --git a/cfg/tarantool_box_cfg.c b/cfg/tarantool_box_cfg.c index 57bd9fc6c32a7d40a9a2f62b27428504e3374b43..4e4d564a1fc3d354d3ae765b18a5faddbaebc442 100644 --- a/cfg/tarantool_box_cfg.c +++ b/cfg/tarantool_box_cfg.c @@ -29,8 +29,10 @@ init_tarantool_cfg(tarantool_cfg *c) { c->__confetti_flags = 0; c->username = NULL; + c->bind_ipaddr = NULL; c->coredump = 0; c->admin_port = 0; + c->replication_port = 0; c->log_level = 0; c->slab_alloc_arena = 0; c->slab_alloc_minimal = 0; @@ -61,9 +63,7 @@ init_tarantool_cfg(tarantool_cfg *c) { c->wal_dir_rescan_delay = 0; c->panic_on_snap_error = 0; c->panic_on_wal_error = 0; - c->remote_hot_standby = 0; - c->wal_feeder_ipaddr = NULL; - c->wal_feeder_port = 0; + c->replication_source = NULL; c->namespace = NULL; } @@ -72,8 +72,11 @@ fill_default_tarantool_cfg(tarantool_cfg *c) { c->__confetti_flags = 0; c->username = NULL; + c->bind_ipaddr = strdup("INADDR_ANY"); + if (c->bind_ipaddr == NULL) return CNF_NOMEMORY; c->coredump = 0; c->admin_port = 0; + c->replication_port = 0; c->log_level = 4; c->slab_alloc_arena = 1; c->slab_alloc_minimal = 64; @@ -107,9 +110,7 @@ fill_default_tarantool_cfg(tarantool_cfg *c) { c->wal_dir_rescan_delay = 0.1; c->panic_on_snap_error = 1; c->panic_on_wal_error = 0; - c->remote_hot_standby = 0; - c->wal_feeder_ipaddr = NULL; - c->wal_feeder_port = 0; + c->replication_source = NULL; c->namespace = NULL; return 0; } @@ -150,12 +151,18 @@ acceptDefault_name__namespace__index__key_field(tarantool_cfg_namespace_index_ke static NameAtom _name__username[] = { { "username", -1, NULL } }; +static NameAtom _name__bind_ipaddr[] = { + { "bind_ipaddr", -1, NULL } +}; static NameAtom _name__coredump[] = { { "coredump", -1, NULL } }; static NameAtom _name__admin_port[] = { { "admin_port", -1, NULL } }; +static NameAtom _name__replication_port[] = { + { "replication_port", -1, NULL } +}; static NameAtom _name__log_level[] = { { "log_level", -1, NULL } }; @@ -246,14 +253,8 @@ static NameAtom _name__panic_on_snap_error[] = { static NameAtom _name__panic_on_wal_error[] = { { "panic_on_wal_error", -1, NULL } }; -static NameAtom _name__remote_hot_standby[] = { - { "remote_hot_standby", -1, NULL } -}; -static NameAtom _name__wal_feeder_ipaddr[] = { - { "wal_feeder_ipaddr", -1, NULL } -}; -static NameAtom _name__wal_feeder_port[] = { - { "wal_feeder_port", -1, NULL } +static NameAtom _name__replication_source[] = { + { "replication_source", -1, NULL } }; static NameAtom _name__namespace[] = { { "namespace", -1, NULL } @@ -344,6 +345,17 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { if (opt->paramValue.stringval && c->username == NULL) return CNF_NOMEMORY; } + else if ( cmpNameAtoms( opt->name, _name__bind_ipaddr) ) { + if (opt->paramType != stringType ) + return CNF_WRONGTYPE; + c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; + errno = 0; + if (check_rdonly && ( (opt->paramValue.stringval == NULL && c->bind_ipaddr == NULL) || strcmp(opt->paramValue.stringval, c->bind_ipaddr) != 0)) + return CNF_RDONLY; + c->bind_ipaddr = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; + if (opt->paramValue.stringval && c->bind_ipaddr == NULL) + return CNF_NOMEMORY; + } else if ( cmpNameAtoms( opt->name, _name__coredump) ) { if (opt->paramType != numberType ) return CNF_WRONGTYPE; @@ -372,6 +384,20 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { return CNF_RDONLY; c->admin_port = i32; } + else if ( cmpNameAtoms( opt->name, _name__replication_port) ) { + if (opt->paramType != numberType ) + return CNF_WRONGTYPE; + c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; + errno = 0; + long int i32 = strtol(opt->paramValue.numberval, NULL, 10); + if (i32 == 0 && errno == EINVAL) + return CNF_WRONGINT; + if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) + return CNF_WRONGRANGE; + if (check_rdonly && c->replication_port != i32) + return CNF_RDONLY; + c->replication_port = i32; + } else if ( cmpNameAtoms( opt->name, _name__log_level) ) { if (opt->paramType != numberType ) return CNF_WRONGTYPE; @@ -752,39 +778,15 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { return CNF_RDONLY; c->panic_on_wal_error = i32; } - else if ( cmpNameAtoms( opt->name, _name__remote_hot_standby) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - long int i32 = strtol(opt->paramValue.numberval, NULL, 10); - if (i32 == 0 && errno == EINVAL) - return CNF_WRONGINT; - if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) - return CNF_WRONGRANGE; - c->remote_hot_standby = i32; - } - else if ( cmpNameAtoms( opt->name, _name__wal_feeder_ipaddr) ) { + else if ( cmpNameAtoms( opt->name, _name__replication_source) ) { if (opt->paramType != stringType ) return CNF_WRONGTYPE; c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; errno = 0; - c->wal_feeder_ipaddr = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; - if (opt->paramValue.stringval && c->wal_feeder_ipaddr == NULL) + c->replication_source = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; + if (opt->paramValue.stringval && c->replication_source == NULL) return CNF_NOMEMORY; } - else if ( cmpNameAtoms( opt->name, _name__wal_feeder_port) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - long int i32 = strtol(opt->paramValue.numberval, NULL, 10); - if (i32 == 0 && errno == EINVAL) - return CNF_WRONGINT; - if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) - return CNF_WRONGRANGE; - c->wal_feeder_port = i32; - } else if ( cmpNameAtoms( opt->name, _name__namespace) ) { if (opt->paramType != arrayType ) return CNF_WRONGTYPE; @@ -1062,8 +1064,10 @@ parse_cfg_buffer_tarantool_cfg(tarantool_cfg *c, char *buffer, int check_rdonly, typedef enum IteratorState { _S_Initial = 0, S_name__username, + S_name__bind_ipaddr, S_name__coredump, S_name__admin_port, + S_name__replication_port, S_name__log_level, S_name__slab_alloc_arena, S_name__slab_alloc_minimal, @@ -1094,9 +1098,7 @@ typedef enum IteratorState { S_name__wal_dir_rescan_delay, S_name__panic_on_snap_error, S_name__panic_on_wal_error, - S_name__remote_hot_standby, - S_name__wal_feeder_ipaddr, - S_name__wal_feeder_port, + S_name__replication_source, S_name__namespace, S_name__namespace__enabled, S_name__namespace__cardinality, @@ -1142,6 +1144,16 @@ tarantool_cfg_iterator_next(tarantool_cfg_iterator_t* i, tarantool_cfg *c, char return NULL; } snprintf(buf, PRINTBUFLEN-1, "username"); + i->state = S_name__bind_ipaddr; + return buf; + case S_name__bind_ipaddr: + *v = (c->bind_ipaddr) ? strdup(c->bind_ipaddr) : NULL; + if (*v == NULL && c->bind_ipaddr) { + free(i); + out_warning(CNF_NOMEMORY, "No memory to output value"); + return NULL; + } + snprintf(buf, PRINTBUFLEN-1, "bind_ipaddr"); i->state = S_name__coredump; return buf; case S_name__coredump: @@ -1164,6 +1176,17 @@ tarantool_cfg_iterator_next(tarantool_cfg_iterator_t* i, tarantool_cfg *c, char } sprintf(*v, "%"PRId32, c->admin_port); snprintf(buf, PRINTBUFLEN-1, "admin_port"); + i->state = S_name__replication_port; + return buf; + case S_name__replication_port: + *v = malloc(32); + if (*v == NULL) { + free(i); + out_warning(CNF_NOMEMORY, "No memory to output value"); + return NULL; + } + sprintf(*v, "%"PRId32, c->replication_port); + snprintf(buf, PRINTBUFLEN-1, "replication_port"); i->state = S_name__log_level; return buf; case S_name__log_level: @@ -1488,38 +1511,16 @@ tarantool_cfg_iterator_next(tarantool_cfg_iterator_t* i, tarantool_cfg *c, char } sprintf(*v, "%"PRId32, c->panic_on_wal_error); snprintf(buf, PRINTBUFLEN-1, "panic_on_wal_error"); - i->state = S_name__remote_hot_standby; - return buf; - case S_name__remote_hot_standby: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%"PRId32, c->remote_hot_standby); - snprintf(buf, PRINTBUFLEN-1, "remote_hot_standby"); - i->state = S_name__wal_feeder_ipaddr; - return buf; - case S_name__wal_feeder_ipaddr: - *v = (c->wal_feeder_ipaddr) ? strdup(c->wal_feeder_ipaddr) : NULL; - if (*v == NULL && c->wal_feeder_ipaddr) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - snprintf(buf, PRINTBUFLEN-1, "wal_feeder_ipaddr"); - i->state = S_name__wal_feeder_port; + i->state = S_name__replication_source; return buf; - case S_name__wal_feeder_port: - *v = malloc(32); - if (*v == NULL) { + case S_name__replication_source: + *v = (c->replication_source) ? strdup(c->replication_source) : NULL; + if (*v == NULL && c->replication_source) { free(i); out_warning(CNF_NOMEMORY, "No memory to output value"); return NULL; } - sprintf(*v, "%"PRId32, c->wal_feeder_port); - snprintf(buf, PRINTBUFLEN-1, "wal_feeder_port"); + snprintf(buf, PRINTBUFLEN-1, "replication_source"); i->state = S_name__namespace; return buf; case S_name__namespace: @@ -1805,8 +1806,12 @@ dup_tarantool_cfg(tarantool_cfg* dst, tarantool_cfg* src) { dst->username = src->username == NULL ? NULL : strdup(src->username); if (src->username != NULL && dst->username == NULL) return CNF_NOMEMORY; + dst->bind_ipaddr = src->bind_ipaddr == NULL ? NULL : strdup(src->bind_ipaddr); + if (src->bind_ipaddr != NULL && dst->bind_ipaddr == NULL) + return CNF_NOMEMORY; dst->coredump = src->coredump; dst->admin_port = src->admin_port; + dst->replication_port = src->replication_port; dst->log_level = src->log_level; dst->slab_alloc_arena = src->slab_alloc_arena; dst->slab_alloc_minimal = src->slab_alloc_minimal; @@ -1849,11 +1854,9 @@ dup_tarantool_cfg(tarantool_cfg* dst, tarantool_cfg* src) { dst->wal_dir_rescan_delay = src->wal_dir_rescan_delay; dst->panic_on_snap_error = src->panic_on_snap_error; dst->panic_on_wal_error = src->panic_on_wal_error; - dst->remote_hot_standby = src->remote_hot_standby; - dst->wal_feeder_ipaddr = src->wal_feeder_ipaddr == NULL ? NULL : strdup(src->wal_feeder_ipaddr); - if (src->wal_feeder_ipaddr != NULL && dst->wal_feeder_ipaddr == NULL) + dst->replication_source = src->replication_source == NULL ? NULL : strdup(src->replication_source); + if (src->replication_source != NULL && dst->replication_source == NULL) return CNF_NOMEMORY; - dst->wal_feeder_port = src->wal_feeder_port; dst->namespace = NULL; if (src->namespace != NULL) { @@ -1916,6 +1919,8 @@ destroy_tarantool_cfg(tarantool_cfg* c) { if (c->username != NULL) free(c->username); + if (c->bind_ipaddr != NULL) + free(c->bind_ipaddr); if (c->work_dir != NULL) free(c->work_dir); if (c->pid_file != NULL) @@ -1928,8 +1933,8 @@ destroy_tarantool_cfg(tarantool_cfg* c) { free(c->wal_dir); if (c->custom_proc_title != NULL) free(c->custom_proc_title); - if (c->wal_feeder_ipaddr != NULL) - free(c->wal_feeder_ipaddr); + if (c->replication_source != NULL) + free(c->replication_source); if (c->namespace != NULL) { i->idx_name__namespace = 0; @@ -1996,6 +2001,11 @@ cmp_tarantool_cfg(tarantool_cfg* c1, tarantool_cfg* c2, int only_check_rdonly) { return diff; } + if (confetti_strcmp(c1->bind_ipaddr, c2->bind_ipaddr) != 0) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->bind_ipaddr"); + + return diff; +} if (c1->coredump != c2->coredump) { snprintf(diff, PRINTBUFLEN - 1, "%s", "c->coredump"); @@ -2006,6 +2016,11 @@ cmp_tarantool_cfg(tarantool_cfg* c1, tarantool_cfg* c2, int only_check_rdonly) { return diff; } + if (c1->replication_port != c2->replication_port) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->replication_port"); + + return diff; + } if (!only_check_rdonly) { if (c1->log_level != c2->log_level) { snprintf(diff, PRINTBUFLEN - 1, "%s", "c->log_level"); @@ -2167,26 +2182,12 @@ cmp_tarantool_cfg(tarantool_cfg* c1, tarantool_cfg* c2, int only_check_rdonly) { return diff; } if (!only_check_rdonly) { - if (c1->remote_hot_standby != c2->remote_hot_standby) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->remote_hot_standby"); - - return diff; - } - } - if (!only_check_rdonly) { - if (confetti_strcmp(c1->wal_feeder_ipaddr, c2->wal_feeder_ipaddr) != 0) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_feeder_ipaddr"); + if (confetti_strcmp(c1->replication_source, c2->replication_source) != 0) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->replication_source"); return diff; } } - if (!only_check_rdonly) { - if (c1->wal_feeder_port != c2->wal_feeder_port) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_feeder_port"); - - return diff; - } - } i1->idx_name__namespace = 0; i2->idx_name__namespace = 0; diff --git a/cfg/tarantool_box_cfg.cfg b/cfg/tarantool_box_cfg.cfg index b5ade814456d550e5152f803864a2c136a907917..3b2e6f843551889a9154ec3c4689613c94220008 100644 --- a/cfg/tarantool_box_cfg.cfg +++ b/cfg/tarantool_box_cfg.cfg @@ -2,6 +2,10 @@ # username to switch to username = NULL +# tarantool bind ip address, applies to master +# and replication ports. INADDR_ANY is the default value. +bind_ipaddr = "INADDR_ANY" + # save core on abort/assert # deprecated; use ulimit instead coredump = 0 @@ -10,6 +14,9 @@ coredump = 0 # used for admin's connections admin_port = 0 +# Replication clients should use this port (bind_ipaddr:replication_port). +replication_port = 0 + # Log verbosity, possible values: ERROR=1, CRIT=2, WARN=3, INFO=4(default), DEBUG=5 log_level = 4 @@ -95,8 +102,10 @@ wal_fsync_delay = 0 # size of WAL writer request buffer wal_writer_inbox_size = 128 -# Local hot standby (if enabled, the server will run in local hot standby -# mode, continuously fetching WAL records from shared local directory). +# Local hot standby (if enabled, the server will run in hot +# standby mode, continuously fetching WAL records from wal_dir, +# until it is able to bind to the primary port. +# In local hot standby mode the server only accepts reads. local_hot_standby = 0 # Delay, in seconds, between successive re-readings of wal_dir. @@ -109,11 +118,12 @@ wal_dir_rescan_delay = 0.1 panic_on_snap_error = 1 panic_on_wal_error = 0 -# Remote hot standby (if enabled, the server will run in hot standby mode -# continuously fetching WAL records from wal_feeder_ipaddr:wal_feeder_port -remote_hot_standby = 0 -wal_feeder_ipaddr = NULL -wal_feeder_port = 0 +# Replication mode (if enabled, the server, once +# bound to the primary port, will connect to +# replication_source (ipaddr:port) and run continously +# fetching records from it.. In replication mode the server +# only accepts reads. +replication_source = NULL namespace = [ { enabled = -1 cardinality = -1 diff --git a/cfg/tarantool_box_cfg.h b/cfg/tarantool_box_cfg.h index e81d06c4c4f958c85d877e7f4a0425e8c7b19d1c..eda7d13bfca328b02ccadb7c9996d698b00456fe 100644 --- a/cfg/tarantool_box_cfg.h +++ b/cfg/tarantool_box_cfg.h @@ -39,6 +39,12 @@ typedef struct tarantool_cfg { /* username to switch to */ char* username; + /* + * tarantool bind ip address, applies to master + * and replication ports. INADDR_ANY is the default value. + */ + char* bind_ipaddr; + /* * save core on abort/assert * deprecated; use ulimit instead @@ -51,6 +57,9 @@ typedef struct tarantool_cfg { */ int32_t admin_port; + /* Replication clients should use this port (bind_ipaddr:replication_port). */ + int32_t replication_port; + /* Log verbosity, possible values: ERROR=1, CRIT=2, WARN=3, INFO=4(default), DEBUG=5 */ int32_t log_level; @@ -145,8 +154,10 @@ typedef struct tarantool_cfg { int32_t wal_writer_inbox_size; /* - * Local hot standby (if enabled, the server will run in local hot standby - * mode, continuously fetching WAL records from shared local directory). + * Local hot standby (if enabled, the server will run in hot + * standby mode, continuously fetching WAL records from wal_dir, + * until it is able to bind to the primary port. + * In local hot standby mode the server only accepts reads. */ int32_t local_hot_standby; @@ -165,12 +176,13 @@ typedef struct tarantool_cfg { int32_t panic_on_wal_error; /* - * Remote hot standby (if enabled, the server will run in hot standby mode - * continuously fetching WAL records from wal_feeder_ipaddr:wal_feeder_port + * Replication mode (if enabled, the server, once + * bound to the primary port, will connect to + * replication_source (ipaddr:port) and run continously + * fetching records from it.. In replication mode the server + * only accepts reads. */ - int32_t remote_hot_standby; - char* wal_feeder_ipaddr; - int32_t wal_feeder_port; + char* replication_source; tarantool_cfg_namespace** namespace; } tarantool_cfg; diff --git a/cfg/tarantool_feeder_cfg.c b/cfg/tarantool_feeder_cfg.c deleted file mode 100644 index 3f5fb82f1f76f89b82bb06505d7c8671b3a8e58f..0000000000000000000000000000000000000000 --- a/cfg/tarantool_feeder_cfg.c +++ /dev/null @@ -1,946 +0,0 @@ -#include <errno.h> -#include <limits.h> -#include <inttypes.h> -#include <math.h> -#include <stdlib.h> -#include <string.h> -#include <stdio.h> - -/* - * Autogenerated file, do not edit it! - */ - - -#include "cfg/warning.h" -#include "cfg/tarantool_feeder_cfg.h" -static int -cmpNameAtoms(NameAtom *a, NameAtom *b) { - while(a && b) { - if (strcasecmp(a->name, b->name) != 0) - return 0; - a = a->next; - b = b->next; - } - return (a == NULL && b == NULL) ? 1 : 0; -} - -void -init_tarantool_cfg(tarantool_cfg *c) { - c->__confetti_flags = 0; - - c->username = NULL; - c->coredump = 0; - c->admin_port = 0; - c->log_level = 0; - c->slab_alloc_arena = 0; - c->slab_alloc_minimal = 0; - c->slab_alloc_factor = 0; - c->work_dir = NULL; - c->pid_file = NULL; - c->logger = NULL; - c->logger_nonblock = 0; - c->io_collect_interval = 0; - c->backlog = 0; - c->readahead = 0; - c->wal_feeder_bind_ipaddr = NULL; - c->wal_feeder_bind_port = 0; - c->wal_feeder_dir = NULL; - c->custom_proc_title = NULL; -} - -int -fill_default_tarantool_cfg(tarantool_cfg *c) { - c->__confetti_flags = 0; - - c->username = NULL; - c->coredump = 0; - c->admin_port = 0; - c->log_level = 4; - c->slab_alloc_arena = 1; - c->slab_alloc_minimal = 64; - c->slab_alloc_factor = 2; - c->work_dir = NULL; - c->pid_file = strdup("tarantool.pid"); - if (c->pid_file == NULL) return CNF_NOMEMORY; - c->logger = NULL; - c->logger_nonblock = 1; - c->io_collect_interval = 0; - c->backlog = 1024; - c->readahead = 16320; - c->wal_feeder_bind_ipaddr = NULL; - c->wal_feeder_bind_port = 0; - c->wal_feeder_dir = NULL; - c->custom_proc_title = NULL; - return 0; -} - -void -swap_tarantool_cfg(struct tarantool_cfg *c1, struct tarantool_cfg *c2) { - struct tarantool_cfg tmpcfg = *c1; - *c1 = *c2; - *c2 = tmpcfg; -} - -static NameAtom _name__username[] = { - { "username", -1, NULL } -}; -static NameAtom _name__coredump[] = { - { "coredump", -1, NULL } -}; -static NameAtom _name__admin_port[] = { - { "admin_port", -1, NULL } -}; -static NameAtom _name__log_level[] = { - { "log_level", -1, NULL } -}; -static NameAtom _name__slab_alloc_arena[] = { - { "slab_alloc_arena", -1, NULL } -}; -static NameAtom _name__slab_alloc_minimal[] = { - { "slab_alloc_minimal", -1, NULL } -}; -static NameAtom _name__slab_alloc_factor[] = { - { "slab_alloc_factor", -1, NULL } -}; -static NameAtom _name__work_dir[] = { - { "work_dir", -1, NULL } -}; -static NameAtom _name__pid_file[] = { - { "pid_file", -1, NULL } -}; -static NameAtom _name__logger[] = { - { "logger", -1, NULL } -}; -static NameAtom _name__logger_nonblock[] = { - { "logger_nonblock", -1, NULL } -}; -static NameAtom _name__io_collect_interval[] = { - { "io_collect_interval", -1, NULL } -}; -static NameAtom _name__backlog[] = { - { "backlog", -1, NULL } -}; -static NameAtom _name__readahead[] = { - { "readahead", -1, NULL } -}; -static NameAtom _name__wal_feeder_bind_ipaddr[] = { - { "wal_feeder_bind_ipaddr", -1, NULL } -}; -static NameAtom _name__wal_feeder_bind_port[] = { - { "wal_feeder_bind_port", -1, NULL } -}; -static NameAtom _name__wal_feeder_dir[] = { - { "wal_feeder_dir", -1, NULL } -}; -static NameAtom _name__custom_proc_title[] = { - { "custom_proc_title", -1, NULL } -}; - -#define ARRAYALLOC(x,n,t,_chk_ro, __flags) do { \ - int l = 0, ar; \ - __typeof__(x) y = (x), t; \ - if ( (n) <= 0 ) return CNF_WRONGINDEX; /* wrong index */ \ - while(y && *y) { \ - l++; y++; \ - } \ - if ( (n) >= (l + 1) ) { \ - if (_chk_ro) return CNF_RDONLY; \ - if ( (x) == NULL ) \ - t = y = malloc( ((n)+1) * sizeof( __typeof__(*(x))) ); \ - else { \ - t = realloc((x), ((n)+1) * sizeof( __typeof__(*(x))) ); \ - y = t + l; \ - } \ - if (t == NULL) return CNF_NOMEMORY; \ - (x) = t; \ - memset(y, 0, (((n)+1) - l) * sizeof( __typeof__(*(x))) ); \ - while ( y - (x) < (n) ) { \ - *y = malloc( sizeof( __typeof__(**(x))) ); \ - if (*y == NULL) return CNF_NOMEMORY; \ - if ( (ar = acceptDefault##t(*y)) != 0 ) return ar; \ - (*y)->__confetti_flags = __flags; \ - y++; \ - } \ - } \ -} while(0) - -static ConfettyError -acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { - - if ( cmpNameAtoms( opt->name, _name__username) ) { - if (opt->paramType != stringType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - if (check_rdonly && ( (opt->paramValue.stringval == NULL && c->username == NULL) || strcmp(opt->paramValue.stringval, c->username) != 0)) - return CNF_RDONLY; - c->username = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; - if (opt->paramValue.stringval && c->username == NULL) - return CNF_NOMEMORY; - } - else if ( cmpNameAtoms( opt->name, _name__coredump) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - long int i32 = strtol(opt->paramValue.numberval, NULL, 10); - if (i32 == 0 && errno == EINVAL) - return CNF_WRONGINT; - if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) - return CNF_WRONGRANGE; - if (check_rdonly && c->coredump != i32) - return CNF_RDONLY; - c->coredump = i32; - } - else if ( cmpNameAtoms( opt->name, _name__admin_port) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - long int i32 = strtol(opt->paramValue.numberval, NULL, 10); - if (i32 == 0 && errno == EINVAL) - return CNF_WRONGINT; - if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) - return CNF_WRONGRANGE; - if (check_rdonly && c->admin_port != i32) - return CNF_RDONLY; - c->admin_port = i32; - } - else if ( cmpNameAtoms( opt->name, _name__log_level) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - long int i32 = strtol(opt->paramValue.numberval, NULL, 10); - if (i32 == 0 && errno == EINVAL) - return CNF_WRONGINT; - if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) - return CNF_WRONGRANGE; - c->log_level = i32; - } - else if ( cmpNameAtoms( opt->name, _name__slab_alloc_arena) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - double dbl = strtod(opt->paramValue.numberval, NULL); - if ( (dbl == 0 || dbl == -HUGE_VAL || dbl == HUGE_VAL) && errno == ERANGE) - return CNF_WRONGRANGE; - if (check_rdonly && c->slab_alloc_arena != dbl) - return CNF_RDONLY; - c->slab_alloc_arena = dbl; - } - else if ( cmpNameAtoms( opt->name, _name__slab_alloc_minimal) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - long int i32 = strtol(opt->paramValue.numberval, NULL, 10); - if (i32 == 0 && errno == EINVAL) - return CNF_WRONGINT; - if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) - return CNF_WRONGRANGE; - if (check_rdonly && c->slab_alloc_minimal != i32) - return CNF_RDONLY; - c->slab_alloc_minimal = i32; - } - else if ( cmpNameAtoms( opt->name, _name__slab_alloc_factor) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - double dbl = strtod(opt->paramValue.numberval, NULL); - if ( (dbl == 0 || dbl == -HUGE_VAL || dbl == HUGE_VAL) && errno == ERANGE) - return CNF_WRONGRANGE; - if (check_rdonly && c->slab_alloc_factor != dbl) - return CNF_RDONLY; - c->slab_alloc_factor = dbl; - } - else if ( cmpNameAtoms( opt->name, _name__work_dir) ) { - if (opt->paramType != stringType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - if (check_rdonly && ( (opt->paramValue.stringval == NULL && c->work_dir == NULL) || strcmp(opt->paramValue.stringval, c->work_dir) != 0)) - return CNF_RDONLY; - c->work_dir = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; - if (opt->paramValue.stringval && c->work_dir == NULL) - return CNF_NOMEMORY; - } - else if ( cmpNameAtoms( opt->name, _name__pid_file) ) { - if (opt->paramType != stringType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - if (check_rdonly && ( (opt->paramValue.stringval == NULL && c->pid_file == NULL) || strcmp(opt->paramValue.stringval, c->pid_file) != 0)) - return CNF_RDONLY; - c->pid_file = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; - if (opt->paramValue.stringval && c->pid_file == NULL) - return CNF_NOMEMORY; - } - else if ( cmpNameAtoms( opt->name, _name__logger) ) { - if (opt->paramType != stringType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - if (check_rdonly && ( (opt->paramValue.stringval == NULL && c->logger == NULL) || strcmp(opt->paramValue.stringval, c->logger) != 0)) - return CNF_RDONLY; - c->logger = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; - if (opt->paramValue.stringval && c->logger == NULL) - return CNF_NOMEMORY; - } - else if ( cmpNameAtoms( opt->name, _name__logger_nonblock) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - long int i32 = strtol(opt->paramValue.numberval, NULL, 10); - if (i32 == 0 && errno == EINVAL) - return CNF_WRONGINT; - if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) - return CNF_WRONGRANGE; - if (check_rdonly && c->logger_nonblock != i32) - return CNF_RDONLY; - c->logger_nonblock = i32; - } - else if ( cmpNameAtoms( opt->name, _name__io_collect_interval) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - double dbl = strtod(opt->paramValue.numberval, NULL); - if ( (dbl == 0 || dbl == -HUGE_VAL || dbl == HUGE_VAL) && errno == ERANGE) - return CNF_WRONGRANGE; - if (check_rdonly && c->io_collect_interval != dbl) - return CNF_RDONLY; - c->io_collect_interval = dbl; - } - else if ( cmpNameAtoms( opt->name, _name__backlog) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - long int i32 = strtol(opt->paramValue.numberval, NULL, 10); - if (i32 == 0 && errno == EINVAL) - return CNF_WRONGINT; - if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) - return CNF_WRONGRANGE; - if (check_rdonly && c->backlog != i32) - return CNF_RDONLY; - c->backlog = i32; - } - else if ( cmpNameAtoms( opt->name, _name__readahead) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - long int i32 = strtol(opt->paramValue.numberval, NULL, 10); - if (i32 == 0 && errno == EINVAL) - return CNF_WRONGINT; - if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) - return CNF_WRONGRANGE; - c->readahead = i32; - } - else if ( cmpNameAtoms( opt->name, _name__wal_feeder_bind_ipaddr) ) { - if (opt->paramType != stringType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - if (check_rdonly && ( (opt->paramValue.stringval == NULL && c->wal_feeder_bind_ipaddr == NULL) || strcmp(opt->paramValue.stringval, c->wal_feeder_bind_ipaddr) != 0)) - return CNF_RDONLY; - c->wal_feeder_bind_ipaddr = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; - if (opt->paramValue.stringval && c->wal_feeder_bind_ipaddr == NULL) - return CNF_NOMEMORY; - } - else if ( cmpNameAtoms( opt->name, _name__wal_feeder_bind_port) ) { - if (opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - long int i32 = strtol(opt->paramValue.numberval, NULL, 10); - if (i32 == 0 && errno == EINVAL) - return CNF_WRONGINT; - if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) - return CNF_WRONGRANGE; - if (check_rdonly && c->wal_feeder_bind_port != i32) - return CNF_RDONLY; - c->wal_feeder_bind_port = i32; - } - else if ( cmpNameAtoms( opt->name, _name__wal_feeder_dir) ) { - if (opt->paramType != stringType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - if (check_rdonly && ( (opt->paramValue.stringval == NULL && c->wal_feeder_dir == NULL) || strcmp(opt->paramValue.stringval, c->wal_feeder_dir) != 0)) - return CNF_RDONLY; - c->wal_feeder_dir = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; - if (opt->paramValue.stringval && c->wal_feeder_dir == NULL) - return CNF_NOMEMORY; - } - else if ( cmpNameAtoms( opt->name, _name__custom_proc_title) ) { - if (opt->paramType != stringType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - if (check_rdonly && ( (opt->paramValue.stringval == NULL && c->custom_proc_title == NULL) || strcmp(opt->paramValue.stringval, c->custom_proc_title) != 0)) - return CNF_RDONLY; - c->custom_proc_title = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; - if (opt->paramValue.stringval && c->custom_proc_title == NULL) - return CNF_NOMEMORY; - } - else { - return CNF_MISSED; - } - return CNF_OK; -} - -static void cleanFlags(tarantool_cfg* c, OptDef* opt); - -#define PRINTBUFLEN 8192 -static char* -dumpOptDef(NameAtom *atom) { - static char buf[PRINTBUFLEN], *ptr; - int i = 0; - - ptr = buf; - while(atom) { - if (i) ptr += snprintf(ptr, PRINTBUFLEN - 1 - (ptr - buf), "."); - ptr += snprintf(ptr, PRINTBUFLEN - 1 - (ptr - buf), "%s", atom->name); - if (atom->index >= 0) - ptr += snprintf(ptr, PRINTBUFLEN - 1 - (ptr - buf), "[%d]", atom->index); - i = 1; - atom = atom->next; - } - return buf; -} - -static void -acceptCfgDef(tarantool_cfg *c, OptDef *opt, int check_rdonly, int *n_accepted, int *n_skipped) { - ConfettyError r; - OptDef *orig_opt = opt; - - if (n_accepted) *n_accepted=0; - if (n_skipped) *n_skipped=0; - - while(opt) { - r = acceptValue(c, opt, check_rdonly); - switch(r) { - case CNF_OK: - if (n_accepted) (*n_accepted)++; - break; - case CNF_MISSED: - out_warning(r, "Could not find '%s' option", dumpOptDef(opt->name)); - if (n_skipped) (*n_skipped)++; - break; - case CNF_WRONGTYPE: - out_warning(r, "Wrong value type for '%s' option", dumpOptDef(opt->name)); - if (n_skipped) (*n_skipped)++; - break; - case CNF_WRONGINDEX: - out_warning(r, "Wrong array index in '%s' option", dumpOptDef(opt->name)); - if (n_skipped) (*n_skipped)++; - break; - case CNF_RDONLY: - out_warning(r, "Could not accept read only '%s' option", dumpOptDef(opt->name)); - if (n_skipped) (*n_skipped)++; - break; - case CNF_WRONGINT: - out_warning(r, "Could not parse integer value for '%s' option", dumpOptDef(opt->name)); - if (n_skipped) (*n_skipped)++; - break; - case CNF_WRONGRANGE: - out_warning(r, "Wrong range for '%s' option", dumpOptDef(opt->name)); - if (n_skipped) (*n_skipped)++; - break; - case CNF_NOMEMORY: - out_warning(r, "Not enough memory to accept '%s' option", dumpOptDef(opt->name)); - if (n_skipped) (*n_skipped)++; - break; - case CNF_NOTSET: - out_warning(r, "Option '%s' is not set (or has a default value)", dumpOptDef(opt->name)); - if (n_skipped) (*n_skipped)++; - break; - default: - out_warning(r, "Unknown error for '%s' option", dumpOptDef(opt->name)); - if (n_skipped) (*n_skipped)++; - break; - } - - opt = opt->next; - } - - cleanFlags(c, orig_opt); -} - -void -parse_cfg_file_tarantool_cfg(tarantool_cfg *c, FILE *fh, int check_rdonly, int *n_accepted, int *n_skipped) { - OptDef *option; - - option = parseCfgDef(fh); - acceptCfgDef(c, option, check_rdonly, n_accepted, n_skipped); - freeCfgDef(option); -} - -void -parse_cfg_buffer_tarantool_cfg(tarantool_cfg *c, char *buffer, int check_rdonly, int *n_accepted, int *n_skipped) { - OptDef *option; - - option = parseCfgDefBuffer(buffer); - acceptCfgDef(c, option, check_rdonly, n_accepted, n_skipped); - freeCfgDef(option); -} - -/************** Iterator **************/ -typedef enum IteratorState { - _S_Initial = 0, - S_name__username, - S_name__coredump, - S_name__admin_port, - S_name__log_level, - S_name__slab_alloc_arena, - S_name__slab_alloc_minimal, - S_name__slab_alloc_factor, - S_name__work_dir, - S_name__pid_file, - S_name__logger, - S_name__logger_nonblock, - S_name__io_collect_interval, - S_name__backlog, - S_name__readahead, - S_name__wal_feeder_bind_ipaddr, - S_name__wal_feeder_bind_port, - S_name__wal_feeder_dir, - S_name__custom_proc_title, - _S_Finished -} IteratorState; - -struct tarantool_cfg_iterator_t { - IteratorState state; -}; - -tarantool_cfg_iterator_t* -tarantool_cfg_iterator_init() { - tarantool_cfg_iterator_t *i = malloc(sizeof(*i)); - if (i == NULL) return NULL; - memset(i, 0, sizeof(*i)); - return i; -} - -char* -tarantool_cfg_iterator_next(tarantool_cfg_iterator_t* i, tarantool_cfg *c, char **v) { - static char buf[PRINTBUFLEN]; - - *v = NULL; - goto again; /* keep compiler quiet */ -again: - switch(i->state) { - case _S_Initial: - case S_name__username: - *v = (c->username) ? strdup(c->username) : NULL; - if (*v == NULL && c->username) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - snprintf(buf, PRINTBUFLEN-1, "username"); - i->state = S_name__coredump; - return buf; - case S_name__coredump: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%"PRId32, c->coredump); - snprintf(buf, PRINTBUFLEN-1, "coredump"); - i->state = S_name__admin_port; - return buf; - case S_name__admin_port: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%"PRId32, c->admin_port); - snprintf(buf, PRINTBUFLEN-1, "admin_port"); - i->state = S_name__log_level; - return buf; - case S_name__log_level: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%"PRId32, c->log_level); - snprintf(buf, PRINTBUFLEN-1, "log_level"); - i->state = S_name__slab_alloc_arena; - return buf; - case S_name__slab_alloc_arena: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%g", c->slab_alloc_arena); - snprintf(buf, PRINTBUFLEN-1, "slab_alloc_arena"); - i->state = S_name__slab_alloc_minimal; - return buf; - case S_name__slab_alloc_minimal: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%"PRId32, c->slab_alloc_minimal); - snprintf(buf, PRINTBUFLEN-1, "slab_alloc_minimal"); - i->state = S_name__slab_alloc_factor; - return buf; - case S_name__slab_alloc_factor: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%g", c->slab_alloc_factor); - snprintf(buf, PRINTBUFLEN-1, "slab_alloc_factor"); - i->state = S_name__work_dir; - return buf; - case S_name__work_dir: - *v = (c->work_dir) ? strdup(c->work_dir) : NULL; - if (*v == NULL && c->work_dir) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - snprintf(buf, PRINTBUFLEN-1, "work_dir"); - i->state = S_name__pid_file; - return buf; - case S_name__pid_file: - *v = (c->pid_file) ? strdup(c->pid_file) : NULL; - if (*v == NULL && c->pid_file) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - snprintf(buf, PRINTBUFLEN-1, "pid_file"); - i->state = S_name__logger; - return buf; - case S_name__logger: - *v = (c->logger) ? strdup(c->logger) : NULL; - if (*v == NULL && c->logger) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - snprintf(buf, PRINTBUFLEN-1, "logger"); - i->state = S_name__logger_nonblock; - return buf; - case S_name__logger_nonblock: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%"PRId32, c->logger_nonblock); - snprintf(buf, PRINTBUFLEN-1, "logger_nonblock"); - i->state = S_name__io_collect_interval; - return buf; - case S_name__io_collect_interval: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%g", c->io_collect_interval); - snprintf(buf, PRINTBUFLEN-1, "io_collect_interval"); - i->state = S_name__backlog; - return buf; - case S_name__backlog: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%"PRId32, c->backlog); - snprintf(buf, PRINTBUFLEN-1, "backlog"); - i->state = S_name__readahead; - return buf; - case S_name__readahead: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%"PRId32, c->readahead); - snprintf(buf, PRINTBUFLEN-1, "readahead"); - i->state = S_name__wal_feeder_bind_ipaddr; - return buf; - case S_name__wal_feeder_bind_ipaddr: - *v = (c->wal_feeder_bind_ipaddr) ? strdup(c->wal_feeder_bind_ipaddr) : NULL; - if (*v == NULL && c->wal_feeder_bind_ipaddr) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - snprintf(buf, PRINTBUFLEN-1, "wal_feeder_bind_ipaddr"); - i->state = S_name__wal_feeder_bind_port; - return buf; - case S_name__wal_feeder_bind_port: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%"PRId32, c->wal_feeder_bind_port); - snprintf(buf, PRINTBUFLEN-1, "wal_feeder_bind_port"); - i->state = S_name__wal_feeder_dir; - return buf; - case S_name__wal_feeder_dir: - *v = (c->wal_feeder_dir) ? strdup(c->wal_feeder_dir) : NULL; - if (*v == NULL && c->wal_feeder_dir) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - snprintf(buf, PRINTBUFLEN-1, "wal_feeder_dir"); - i->state = S_name__custom_proc_title; - return buf; - case S_name__custom_proc_title: - *v = (c->custom_proc_title) ? strdup(c->custom_proc_title) : NULL; - if (*v == NULL && c->custom_proc_title) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - snprintf(buf, PRINTBUFLEN-1, "custom_proc_title"); - i->state = _S_Finished; - return buf; - case _S_Finished: - free(i); - break; - default: - out_warning(CNF_INTERNALERROR, "Unknown state for tarantool_cfg_iterator_t: %d", i->state); - free(i); - } - return NULL; -} - -/************** Checking of required fields **************/ -int -check_cfg_tarantool_cfg(tarantool_cfg *c) { - tarantool_cfg_iterator_t iterator, *i = &iterator; - int res = 0; - - if (c->wal_feeder_bind_ipaddr == NULL) { - res++; - out_warning(CNF_NOTSET, "Option '%s' is not set (or has a default value)", dumpOptDef(_name__wal_feeder_bind_ipaddr)); - } - if (c->wal_feeder_bind_port == 0) { - res++; - out_warning(CNF_NOTSET, "Option '%s' is not set (or has a default value)", dumpOptDef(_name__wal_feeder_bind_port)); - } - if (c->wal_feeder_dir == NULL) { - res++; - out_warning(CNF_NOTSET, "Option '%s' is not set (or has a default value)", dumpOptDef(_name__wal_feeder_dir)); - } - return res; -} - -static void -cleanFlags(tarantool_cfg* c, OptDef* opt) { - tarantool_cfg_iterator_t iterator, *i = &iterator; - -} - -/************** Duplicate config **************/ - -int -dup_tarantool_cfg(tarantool_cfg* dst, tarantool_cfg* src) { - tarantool_cfg_iterator_t iterator, *i = &iterator; - - dst->username = src->username == NULL ? NULL : strdup(src->username); - if (src->username != NULL && dst->username == NULL) - return CNF_NOMEMORY; - dst->coredump = src->coredump; - dst->admin_port = src->admin_port; - dst->log_level = src->log_level; - dst->slab_alloc_arena = src->slab_alloc_arena; - dst->slab_alloc_minimal = src->slab_alloc_minimal; - dst->slab_alloc_factor = src->slab_alloc_factor; - dst->work_dir = src->work_dir == NULL ? NULL : strdup(src->work_dir); - if (src->work_dir != NULL && dst->work_dir == NULL) - return CNF_NOMEMORY; - dst->pid_file = src->pid_file == NULL ? NULL : strdup(src->pid_file); - if (src->pid_file != NULL && dst->pid_file == NULL) - return CNF_NOMEMORY; - dst->logger = src->logger == NULL ? NULL : strdup(src->logger); - if (src->logger != NULL && dst->logger == NULL) - return CNF_NOMEMORY; - dst->logger_nonblock = src->logger_nonblock; - dst->io_collect_interval = src->io_collect_interval; - dst->backlog = src->backlog; - dst->readahead = src->readahead; - dst->wal_feeder_bind_ipaddr = src->wal_feeder_bind_ipaddr == NULL ? NULL : strdup(src->wal_feeder_bind_ipaddr); - if (src->wal_feeder_bind_ipaddr != NULL && dst->wal_feeder_bind_ipaddr == NULL) - return CNF_NOMEMORY; - dst->wal_feeder_bind_port = src->wal_feeder_bind_port; - dst->wal_feeder_dir = src->wal_feeder_dir == NULL ? NULL : strdup(src->wal_feeder_dir); - if (src->wal_feeder_dir != NULL && dst->wal_feeder_dir == NULL) - return CNF_NOMEMORY; - dst->custom_proc_title = src->custom_proc_title == NULL ? NULL : strdup(src->custom_proc_title); - if (src->custom_proc_title != NULL && dst->custom_proc_title == NULL) - return CNF_NOMEMORY; - - return CNF_OK; -} - -/************** Destroy config **************/ - -void -destroy_tarantool_cfg(tarantool_cfg* c) { - tarantool_cfg_iterator_t iterator, *i = &iterator; - - if (c->username != NULL) - free(c->username); - if (c->work_dir != NULL) - free(c->work_dir); - if (c->pid_file != NULL) - free(c->pid_file); - if (c->logger != NULL) - free(c->logger); - if (c->wal_feeder_bind_ipaddr != NULL) - free(c->wal_feeder_bind_ipaddr); - if (c->wal_feeder_dir != NULL) - free(c->wal_feeder_dir); - if (c->custom_proc_title != NULL) - free(c->custom_proc_title); -} - -/************** Compare config **************/ - -int -confetti_strcmp(char *s1, char *s2) { - if (s1 == NULL || s2 == NULL) { - if (s1 != s2) - return s1 == NULL ? -1 : 1; - else - return 0; - } - - return strcmp(s1, s2); -} - -char * -cmp_tarantool_cfg(tarantool_cfg* c1, tarantool_cfg* c2, int only_check_rdonly) { - tarantool_cfg_iterator_t iterator1, iterator2, *i1 = &iterator1, *i2 = &iterator2; - static char diff[PRINTBUFLEN]; - - if (confetti_strcmp(c1->username, c2->username) != 0) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->username"); - - return diff; -} - if (c1->coredump != c2->coredump) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->coredump"); - - return diff; - } - if (c1->admin_port != c2->admin_port) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->admin_port"); - - return diff; - } - if (!only_check_rdonly) { - if (c1->log_level != c2->log_level) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->log_level"); - - return diff; - } - } - if (c1->slab_alloc_arena != c2->slab_alloc_arena) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->slab_alloc_arena"); - - return diff; - } - if (c1->slab_alloc_minimal != c2->slab_alloc_minimal) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->slab_alloc_minimal"); - - return diff; - } - if (c1->slab_alloc_factor != c2->slab_alloc_factor) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->slab_alloc_factor"); - - return diff; - } - if (confetti_strcmp(c1->work_dir, c2->work_dir) != 0) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->work_dir"); - - return diff; -} - if (confetti_strcmp(c1->pid_file, c2->pid_file) != 0) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->pid_file"); - - return diff; -} - if (confetti_strcmp(c1->logger, c2->logger) != 0) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->logger"); - - return diff; -} - if (c1->logger_nonblock != c2->logger_nonblock) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->logger_nonblock"); - - return diff; - } - if (c1->io_collect_interval != c2->io_collect_interval) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->io_collect_interval"); - - return diff; - } - if (c1->backlog != c2->backlog) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->backlog"); - - return diff; - } - if (!only_check_rdonly) { - if (c1->readahead != c2->readahead) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->readahead"); - - return diff; - } - } - if (confetti_strcmp(c1->wal_feeder_bind_ipaddr, c2->wal_feeder_bind_ipaddr) != 0) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_feeder_bind_ipaddr"); - - return diff; -} - if (c1->wal_feeder_bind_port != c2->wal_feeder_bind_port) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_feeder_bind_port"); - - return diff; - } - if (confetti_strcmp(c1->wal_feeder_dir, c2->wal_feeder_dir) != 0) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_feeder_dir"); - - return diff; -} - if (confetti_strcmp(c1->custom_proc_title, c2->custom_proc_title) != 0) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->custom_proc_title"); - - return diff; -} - - return 0; -} - diff --git a/cfg/tarantool_feeder_cfg.cfg b/cfg/tarantool_feeder_cfg.cfg deleted file mode 100644 index c8407c3fb5afddedd81128534fce9ed90cd47525..0000000000000000000000000000000000000000 --- a/cfg/tarantool_feeder_cfg.cfg +++ /dev/null @@ -1,58 +0,0 @@ - -# username to switch to -username = NULL - -# save core on abort/assert -# deprecated; use ulimit instead -coredump = 0 - -# admin port -# used for admin's connections -admin_port = 0 - -# Log verbosity, possible values: ERROR=1, CRIT=2, WARN=3, INFO=4(default), DEBUG=5 -log_level = 4 - -# Size of slab arena in GB -slab_alloc_arena = 1 - -# Size of minimal allocation unit -slab_alloc_minimal = 64 - -# Growth factor, each subsequent unit size is factor * prev unit size -slab_alloc_factor = 2 - -# working directory (daemon will chdir(2) to it) -work_dir = NULL - -# name of pid file -pid_file = "tarantool.pid" - -# logger command will be executed via /bin/sh -c {} -# example: 'exec cronolog /var/log/tarantool/%Y-%m/%Y-%m-%d/tarantool.log' -# example: 'exec extra/logger.pl /var/log/tarantool/tarantool.log' -# when logger is not configured all logging going to STDERR -logger = NULL - -# make logging nonblocking, this potentially can lose some logging data -logger_nonblock = 1 - -# delay between loop iterations -io_collect_interval = 0 - -# size of listen backlog -backlog = 1024 - -# network io readahead -readahead = 16320 - -# feed WAL to remote replicas -# feeder accepts it's clients on wal_feeder_bind_ipaddr:wal_feeder_bind_port -wal_feeder_bind_ipaddr = NULL -wal_feeder_bind_port = 0 - -# Directory with WAL files to serve -wal_feeder_dir = NULL - -# custom proc title is appended after normal -custom_proc_title = NULL diff --git a/cfg/tarantool_feeder_cfg.h b/cfg/tarantool_feeder_cfg.h deleted file mode 100644 index 5ac2d0a5f34e51daf5b7d37bd4b2877a6044444d..0000000000000000000000000000000000000000 --- a/cfg/tarantool_feeder_cfg.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef tarantool_cfg_CFG_H -#define tarantool_cfg_CFG_H - -#include <stdio.h> -#include <sys/types.h> - -/* - * Autogenerated file, do not edit it! - */ - -typedef struct tarantool_cfg { - unsigned char __confetti_flags; - - - /* username to switch to */ - char* username; - - /* - * save core on abort/assert - * deprecated; use ulimit instead - */ - int32_t coredump; - - /* - * admin port - * used for admin's connections - */ - int32_t admin_port; - - /* Log verbosity, possible values: ERROR=1, CRIT=2, WARN=3, INFO=4(default), DEBUG=5 */ - int32_t log_level; - - /* Size of slab arena in GB */ - double slab_alloc_arena; - - /* Size of minimal allocation unit */ - int32_t slab_alloc_minimal; - - /* Growth factor, each subsequent unit size is factor * prev unit size */ - double slab_alloc_factor; - - /* working directory (daemon will chdir(2) to it) */ - char* work_dir; - - /* name of pid file */ - char* pid_file; - - /* - * logger command will be executed via /bin/sh -c {} - * example: 'exec cronolog /var/log/tarantool/%Y-%m/%Y-%m-%d/tarantool.log' - * example: 'exec extra/logger.pl /var/log/tarantool/tarantool.log' - * when logger is not configured all logging going to STDERR - */ - char* logger; - - /* make logging nonblocking, this potentially can lose some logging data */ - int32_t logger_nonblock; - - /* delay between loop iterations */ - double io_collect_interval; - - /* size of listen backlog */ - int32_t backlog; - - /* network io readahead */ - int32_t readahead; - - /* - * feed WAL to remote replicas - * feeder accepts it's clients on wal_feeder_bind_ipaddr:wal_feeder_bind_port - */ - char* wal_feeder_bind_ipaddr; - int32_t wal_feeder_bind_port; - - /* Directory with WAL files to serve */ - char* wal_feeder_dir; - - /* custom proc title is appended after normal */ - char* custom_proc_title; -} tarantool_cfg; - -#ifndef CNF_FLAG_STRUCT_NEW -#define CNF_FLAG_STRUCT_NEW 0x01 -#endif -#ifndef CNF_FLAG_STRUCT_NOTSET -#define CNF_FLAG_STRUCT_NOTSET 0x02 -#endif -#ifndef CNF_STRUCT_DEFINED -#define CNF_STRUCT_DEFINED(s) ((s) != NULL && ((s)->__confetti_flags & CNF_FLAG_STRUCT_NOTSET) == 0) -#endif - -void init_tarantool_cfg(tarantool_cfg *c); - -int fill_default_tarantool_cfg(tarantool_cfg *c); - -void swap_tarantool_cfg(struct tarantool_cfg *c1, struct tarantool_cfg *c2); - -void parse_cfg_file_tarantool_cfg(tarantool_cfg *c, FILE *fh, int check_rdonly, int *n_accepted, int *n_skipped); - -void parse_cfg_buffer_tarantool_cfg(tarantool_cfg *c, char *buffer, int check_rdonly, int *n_accepted, int *n_skipped); - -int check_cfg_tarantool_cfg(tarantool_cfg *c); - -int dup_tarantool_cfg(tarantool_cfg *dst, tarantool_cfg *src); - -void destroy_tarantool_cfg(tarantool_cfg *c); - -char *cmp_tarantool_cfg(tarantool_cfg* c1, tarantool_cfg* c2, int only_check_rdonly); - -typedef struct tarantool_cfg_iterator_t tarantool_cfg_iterator_t; -tarantool_cfg_iterator_t* tarantool_cfg_iterator_init(); -char* tarantool_cfg_iterator_next(tarantool_cfg_iterator_t* i, tarantool_cfg *c, char **v); - -#endif diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index cd698f0e5bb10c6b7533bc9196265c0442710ba1..f154b95e6cad04e6ff0de8fd585ac2d3cf833b2c 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -52,6 +52,7 @@ set (recompiled_core_sources ${CMAKE_SOURCE_DIR}/core/tarantool.m ${CMAKE_SOURCE_DIR}/core/say.m ${CMAKE_SOURCE_DIR}/core/admin.m + ${CMAKE_SOURCE_DIR}/core/replication.m ${CMAKE_SOURCE_DIR}/core/fiber.m PARENT_SCOPE) set (common_sources tbuf.m palloc.m util.m diff --git a/core/admin.m b/core/admin.m index 412dc7b8868b918a84f51db2f8f62170c8c162a5..62d74731f0cbf62a96967c4f81c5a7e0a77dfabb 100644 --- a/core/admin.m +++ b/core/admin.m @@ -1477,7 +1477,7 @@ admin_handler(void *_data __attribute__((unused))) int admin_init(void) { - if (fiber_server(cfg.admin_port, admin_handler, NULL, NULL) == NULL) { + if (fiber_server("admin", cfg.admin_port, admin_handler, NULL, NULL) == NULL) { say_syserror("can't bind to %d", cfg.admin_port); return -1; } diff --git a/core/admin.rl b/core/admin.rl index 81265ecf7a57c87b87a9ca15ec80eb1d978d7141..992b179715146eaf160b32df0dc84ee08d663c14 100644 --- a/core/admin.rl +++ b/core/admin.rl @@ -223,7 +223,7 @@ admin_handler(void *_data __attribute__((unused))) int admin_init(void) { - if (fiber_server(cfg.admin_port, admin_handler, NULL, NULL) == NULL) { + if (fiber_server("admin", cfg.admin_port, admin_handler, NULL, NULL) == NULL) { say_syserror("can't bind to %d", cfg.admin_port); return -1; } diff --git a/core/fiber.m b/core/fiber.m index c0b83055f0f27b7a1e98b7523ff45540203f0dcb..0ccd53a5038d69a561bf13d3349f52aa8c5d7c8e 100644 --- a/core/fiber.m +++ b/core/fiber.m @@ -256,21 +256,21 @@ wait_for_child(pid_t pid) } -static void -fiber_io_start(int events) +void +fiber_io_start(int fd, int events) { ev_io *io = &fiber->io; assert (!ev_is_active(io)); - ev_io_set(io, fiber->fd, events); + ev_io_set(io, fd, events); ev_io_start(io); } /** @note: this is a cancellation point. */ -static void +void fiber_io_yield() { assert(ev_is_active(&fiber->io)); @@ -285,12 +285,12 @@ fiber_io_yield() } } -static void -fiber_io_stop(int events __attribute__((unused))) +void +fiber_io_stop(int fd __attribute__((unused)), int events __attribute__((unused))) { ev_io *io = &fiber->io; - assert(ev_is_active(io) && io->fd == fiber->fd && (io->events & events)); + assert(ev_is_active(io) && io->fd == fd && (io->events & events)); ev_io_stop(io); } @@ -490,7 +490,7 @@ fiber_create(const char *name, int fd, int inbox_size, void (*f) (void *), void if (tarantool_coro_create(&fiber->coro, fiber_loop, NULL) == NULL) return NULL; - fiber->pool = palloc_create_pool(name); + fiber->pool = palloc_create_pool(""); fiber->inbox = palloc(eter_pool, (sizeof(*fiber->inbox) + inbox_size * sizeof(struct tbuf *))); fiber->inbox->size = inbox_size; @@ -581,7 +581,7 @@ fiber_close(void) /* We don't know if IO is active if there was an error. */ if (ev_is_active(&fiber->io)) - fiber_io_stop(-1); + fiber_io_stop(fiber->fd, -1); int r = close(fiber->fd); @@ -675,7 +675,7 @@ fiber_bread(struct tbuf *buf, size_t at_least) ssize_t r; tbuf_ensure(buf, MAX(cfg.readahead, at_least)); - fiber_io_start(EV_READ); + fiber_io_start(fiber->fd, EV_READ); for (;;) { fiber_io_yield(); r = read(fiber->fd, buf->data + buf->len, buf->size - buf->len); @@ -689,7 +689,7 @@ fiber_bread(struct tbuf *buf, size_t at_least) break; } } - fiber_io_stop(EV_READ); + fiber_io_stop(fiber->fd, EV_READ); return r; } @@ -713,7 +713,7 @@ fiber_flush_output(void) struct iovec *iov = iovec(fiber->iov); size_t iov_cnt = fiber->iov_cnt; - fiber_io_start(EV_WRITE); + fiber_io_start(fiber->fd, EV_WRITE); while (iov_cnt > 0) { fiber_io_yield(); bytes += r = writev(fiber->fd, iov, MIN(iov_cnt, IOV_MAX)); @@ -736,7 +736,7 @@ fiber_flush_output(void) } } } - fiber_io_stop(EV_WRITE); + fiber_io_stop(fiber->fd, EV_WRITE); if (r < 0) { size_t rem = 0; @@ -762,7 +762,7 @@ fiber_read(void *buf, size_t count) { ssize_t r, done = 0; - fiber_io_start(EV_READ); + fiber_io_start(fiber->fd, EV_READ); while (count != done) { fiber_io_yield(); @@ -775,7 +775,7 @@ fiber_read(void *buf, size_t count) } done += r; } - fiber_io_stop(EV_READ); + fiber_io_stop(fiber->fd, EV_READ); return done; } @@ -790,7 +790,7 @@ fiber_write(const void *buf, size_t count) int r; unsigned int done = 0; - fiber_io_start(EV_WRITE); + fiber_io_start(fiber->fd, EV_WRITE); while (count != done) { fiber_io_yield(); @@ -802,7 +802,7 @@ fiber_write(const void *buf, size_t count) } done += r; } - fiber_io_stop(EV_WRITE); + fiber_io_stop(fiber->fd, EV_WRITE); return done; } @@ -826,9 +826,9 @@ fiber_connect(struct sockaddr_in *addr) if (errno != EINPROGRESS) goto error; - fiber_io_start(EV_WRITE); + fiber_io_start(fiber->fd, EV_WRITE); fiber_io_yield(); - fiber_io_stop(EV_WRITE); + fiber_io_stop(fiber->fd, EV_WRITE); int error; socklen_t error_size = sizeof(error); @@ -1029,7 +1029,7 @@ struct child * spawn_child(const char *name, int inbox_size, struct tbuf *(*handler) (void *, struct tbuf *), void *state) { - char *proxy_name; + char proxy_name[FIBER_NAME_MAXLEN]; int socks[2]; int pid; @@ -1051,12 +1051,10 @@ spawn_child(const char *name, int inbox_size, struct tbuf *(*handler) (void *, s struct child *c = palloc(eter_pool, sizeof(*c)); c->pid = pid; - proxy_name = palloc(eter_pool, 64); - snprintf(proxy_name, 64, "%s/sock2inbox", name); + snprintf(proxy_name, sizeof(proxy_name), "%s/sock2inbox", name); c->in = fiber_create(proxy_name, socks[1], inbox_size, sock2inbox, NULL); fiber_call(c->in); - proxy_name = palloc(eter_pool, 64); - snprintf(proxy_name, 64, "%s/inbox2sock", name); + snprintf(proxy_name, sizeof(proxy_name), "%s/inbox2sock", name); c->out = fiber_create(proxy_name, socks[1], inbox_size, inbox2sock, NULL); c->out->flags |= FIBER_READING_INBOX; return c; @@ -1071,7 +1069,7 @@ spawn_child(const char *name, int inbox_size, struct tbuf *(*handler) (void *, s close_all_xcpt(2, socks[0], sayfd); snprintf(child_name, sizeof(child_name), "%s/child", name); fiber_set_name(&sched, child_name); - set_proc_title(name); + set_proc_title("%s%s", name, custom_proc_title); say_crit("%s initialized", name); blocking_loop(socks[0], handler, state); } @@ -1082,64 +1080,20 @@ tcp_server_handler(void *data) { struct fiber_server *server = fiber->data; struct fiber *h; - char name[64]; + char name[FIBER_NAME_MAXLEN]; int fd; - bool warning_said = false; int one = 1; - struct sockaddr_in sin; - struct linger ling = { 0, 0 }; - if ((fiber->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { - say_syserror("socket"); + if (fiber_serv_socket(fiber, server->port, true, 0.1) != 0) { + say_error("init server socket on port %i fail", server->port); exit(EX_OSERR); } - if (setsockopt(fiber->fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1 || - setsockopt(fiber->fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one)) == -1 || - setsockopt(fiber->fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) == -1 || - setsockopt(fiber->fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)) == -1) { - say_syserror("setsockopt"); - exit(EX_OSERR); - } - - if (set_nonblock(fiber->fd) == -1) - exit(EX_OSERR); - - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = AF_INET; - sin.sin_port = htons(server->port); - sin.sin_addr.s_addr = INADDR_ANY; - - for (;;) { - if (bind(fiber->fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) { - if (errno == EADDRINUSE) - goto sleep_and_retry; - say_syserror("bind"); - exit(EX_OSERR); - } - if (listen(fiber->fd, cfg.backlog) == -1) { - if (errno == EADDRINUSE) - goto sleep_and_retry; - say_syserror("listen"); - exit(EX_OSERR); - } - - say_info("bound to TCP port %i", server->port); - break; - - sleep_and_retry: - if (!warning_said) { - say_warn("port %i is already in use, " - "will retry binding after 0.1 seconds.", server->port); - warning_said = true; - } - fiber_sleep(0.1); - } - - if (server->on_bind != NULL) + if (server->on_bind != NULL) { server->on_bind(server->data); + } - fiber_io_start(EV_READ); + fiber_io_start(fiber->fd, EV_READ); for (;;) { fiber_io_yield(); @@ -1171,19 +1125,18 @@ tcp_server_handler(void *data) continue; } } - fiber_io_stop(EV_READ); + fiber_io_stop(fiber->fd, EV_READ); } struct fiber * -fiber_server(int port, void (*handler) (void *data), void *data, +fiber_server(const char *name, int port, void (*handler) (void *data), void *data, void (*on_bind) (void *data)) { - char *server_name; + char server_name[FIBER_NAME_MAXLEN]; struct fiber_server *server; struct fiber *s; - server_name = palloc(eter_pool, 64); - snprintf(server_name, 64, "%i/acceptor", port); + snprintf(server_name, sizeof(server_name), "%i/%s", port, name); s = fiber_create(server_name, -1, -1, tcp_server_handler, data); s->data = server = palloc(eter_pool, sizeof(struct fiber_server)); assert(server != NULL); @@ -1195,6 +1148,112 @@ fiber_server(int port, void (*handler) (void *data), void *data, return s; } +/** create new fiber's socket and set standat options. */ +static int +create_socket(struct fiber *fiber) +{ + if (fiber->fd != -1) { + say_error("fiber is already has socket"); + goto create_socket_fail; + } + + fiber->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (fiber->fd == -1) { + say_syserror("socket"); + goto create_socket_fail; + } + + int one = 1; + if (setsockopt(fiber->fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0) { + say_syserror("setsockopt"); + goto create_socket_fail; + } + + struct linger ling = { 0, 0 }; + if (setsockopt(fiber->fd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof(one)) != 0 || + setsockopt(fiber->fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) != 0 || + setsockopt(fiber->fd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling)) != 0) { + say_syserror("setsockopt"); + goto create_socket_fail; + } + + if (set_nonblock(fiber->fd) == -1) { + goto create_socket_fail; + } + + return 0; + +create_socket_fail: + + if (fiber->fd != -1) { + close(fiber->fd); + } + return -1; +} + +/** Create server socket and bind his on port. */ +int +fiber_serv_socket(struct fiber *fiber, unsigned short port, bool retry, ev_tstamp delay) +{ + const ev_tstamp min_delay = 0.001; /* minimal delay is 1 msec */ + struct sockaddr_in sin; + bool warning_said = false; + + if (delay < min_delay) { + delay = min_delay; + } + + if (create_socket(fiber) != 0) { + return -1; + } + + /* clean sockaddr_in struct */ + memset(&sin, 0, sizeof(struct sockaddr_in)); + + /* fill sockaddr_in struct */ + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + if (strcmp(cfg.bind_ipaddr, "INADDR_ANY") == 0) { + sin.sin_addr.s_addr = INADDR_ANY; + } else { + if (!inet_aton(cfg.bind_ipaddr, &sin.sin_addr)) { + say_syserror("inet_aton"); + return -1; + } + } + + while (true) { + if (bind(fiber->fd, (struct sockaddr *)&sin, sizeof(sin)) != 0) { + if (retry && (errno == EADDRINUSE)) { + /* retry mode, try, to bind after delay */ + goto sleep_and_retry; + } + say_syserror("bind"); + return -1; + } + if (listen(fiber->fd, cfg.backlog) != 0) { + if (retry && (errno == EADDRINUSE)) { + /* retry mode, try, to bind after delay */ + goto sleep_and_retry; + } + say_syserror("listen"); + return -1; + } + + say_info("bound to port %i", port); + break; + + sleep_and_retry: + if (!warning_said) { + say_warn("port %i is already in use, " + "will retry binding after %lf seconds.", port, delay); + warning_said = true; + } + fiber_sleep(delay); + } + + return 0; +} void fiber_info(struct tbuf *out) diff --git a/core/log_io.m b/core/log_io.m index 566b4cdbbac5cb5b4cc30e48740e24f839fc3528..58dde06dbaa84a785ab32093b9c20205b2f97652 100644 --- a/core/log_io.m +++ b/core/log_io.m @@ -1239,7 +1239,7 @@ write_to_disk(void *_state, struct tbuf *t) goto fail; } - /* flush stdio buffer to keep feeder in sync */ + /* flush stdio buffer to keep replication in sync */ if (fflush(wal->f) < 0) { say_syserror("can't flush wal"); goto fail; diff --git a/core/log_io_remote.m b/core/log_io_remote.m index 1d54f9603f6fb5df4a918d87d0c58df588e3994f..f8d11e4b4acf1138ac8a54ab07e1e540dad22b3f 100644 --- a/core/log_io_remote.m +++ b/core/log_io_remote.m @@ -39,6 +39,9 @@ #include <say.h> #include <pickle.h> +static int +default_remote_row_handler(struct recovery_state *r, struct tbuf *row); + static u32 row_v11_len(struct tbuf *r) { @@ -83,7 +86,7 @@ remote_read_row(i64 initial_lsn) for (;;) { if (fiber->fd < 0) { if (fiber_connect(fiber->data) < 0) { - err = "can't connect to feeder"; + err = "can't connect to master"; goto err; } @@ -102,8 +105,9 @@ remote_read_row(i64 initial_lsn) goto err; } - say_crit("successfully connected to feeder"); + say_crit("successfully connected to master"); say_crit("starting replication from lsn:%" PRIi64, initial_lsn); + warning_said = false; err = NULL; } @@ -130,18 +134,18 @@ remote_read_row(i64 initial_lsn) static void pull_from_remote(void *state) { - struct remote_state *h = state; + struct recovery_state *r = state; struct tbuf *row; for (;;) { fiber_setcancelstate(true); - row = remote_read_row(h->r->confirmed_lsn + 1); + row = remote_read_row(r->confirmed_lsn + 1); fiber_setcancelstate(false); - h->r->recovery_lag = ev_now() - row_v11(row)->tm; - h->r->recovery_last_update_tstamp = ev_now(); + r->recovery_lag = ev_now() - row_v11(row)->tm; + r->recovery_last_update_tstamp = ev_now(); - if (h->handler(h->r, row) < 0) { + if (default_remote_row_handler(r, row) < 0) { fiber_close(); continue; } @@ -150,7 +154,7 @@ pull_from_remote(void *state) } } -int +static int default_remote_row_handler(struct recovery_state *r, struct tbuf *row) { struct tbuf *data; @@ -177,29 +181,28 @@ default_remote_row_handler(struct recovery_state *r, struct tbuf *row) } void -recovery_follow_remote(struct recovery_state *r, - const char *ip_addr, int port) +recovery_follow_remote(struct recovery_state *r, const char *remote) { - char *name; + char name[FIBER_NAME_MAXLEN]; + char ip_addr[32]; + int port; + int rc; struct fiber *f; struct in_addr server; struct sockaddr_in *addr; - struct remote_state *h; assert(r->remote_recovery == NULL); - say_crit("initializing the replica, WAL feeder %s:%i", ip_addr, port); - name = palloc(eter_pool, 64); - snprintf(name, 64, "replica/%s:%i", ip_addr, port); + say_crit("initializing the replica, WAL master %s", remote); + snprintf(name, sizeof(name), "replica/%s", remote); - h = palloc(eter_pool, sizeof(*h)); - h->r = r; - h->handler = default_remote_row_handler; - - f = fiber_create(name, -1, -1, pull_from_remote, h); + f = fiber_create(name, -1, -1, pull_from_remote, r); if (f == NULL) return; + rc = sscanf(remote, "%31[^:]:%i", ip_addr, &port); + assert(rc == 2); + if (inet_aton(ip_addr, &server) < 0) { say_syserror("inet_aton: %s", ip_addr); return; diff --git a/core/replication.m b/core/replication.m new file mode 100644 index 0000000000000000000000000000000000000000..12b3872f40086e96ce503fb398f21fbfc02774b3 --- /dev/null +++ b/core/replication.m @@ -0,0 +1,653 @@ +/* + * Copyright (C) 2011 Mail.RU + * Copyright (C) 2011 Yuriy Vostrikov + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <replication.h> +#include <say.h> +#include <fiber.h> +#include TARANTOOL_CONFIG +#include <palloc.h> +#include <stddef.h> + +#include <stddef.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <sys/uio.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include "fiber.h" + +/** Replication topology + * ---------------------- + * + * Tarantool replication consists of 3 interacting processes: + * master, spawner and replication relay. + * + * The spawner is created at server start, and master communicates + * with the spawner using a socketpair(2). Replication relays are + * created by the spawner and handle one client connection each. + * + * The master process binds to replication_port and accepts + * incoming connections. This is done in the master to be able to + * correctly handle RELOAD CONFIGURATION, which happens in the + * master, and, in future, perform authentication of replication + * clients. Since the master uses fibers to serve all clients, + * replication acceptor fiber is just one of many fibers in use. + * Once a client socket is accepted, it is sent to the spawner + * process, through the master's end of the socket pair. + * + * The spawner listens on the receiving end of the socket pair and + * for every received socket creates a replication relay, which is + * then responsible for sending write ahead logs to the replica. + * + * Upon shutdown, the master closes its end of the socket pair. + * The spawner then reads EOF from its end, terminates all + * children and exits. + */ +static int master_to_spawner_sock; + +/** replication_port acceptor fiber */ +static void +acceptor_handler(void *data __attribute__((unused))); + +/** Send a file descriptor to replication relay spawner. + * + * @param client_sock the file descriptor to be sent. + */ +static void +acceptor_send_sock(int client_sock); + +/** Replication spawner process */ +static struct spawner { + /** reading end of the socket pair with the master */ + int sock; + /** non-zero if got a terminating signal */ + sig_atomic_t killed; + /** child process count */ + sig_atomic_t child_count; +} spawner; + +/** Initialize spawner process. + * + * @param sock the socket between the main process and the spawner. + */ +static void +spawner_init(int sock); + +/** Spawner main loop. */ +static void +spawner_main_loop(); + +/** Shutdown spawner and all its children. */ +static void +spawner_shutdown(); + +/** Handle SIGINT, SIGTERM, SIGPIPE, SIGHUP. */ +static void +spawner_signal_handler(int signal); + +/** Handle SIGCHLD: collect status of a terminated child. */ +static void +spawner_sigchld_handler(int signal __attribute__((unused))); + +/** Create a replication relay. + * + * @return 0 on success, -1 on error + */ +static int +spawner_create_replication_relay(int client_sock); + +/** Shut down all relays when shutting down the spawner. */ +static void +spawner_shutdown_children(); + +/** Initialize replication relay process. */ +static void +replication_relay_loop(int client_sock); + +/** A libev callback invoked when a relay client socket is ready + * for read. This currently only happens when the client closes + * its socket, and we get an EOF. + */ +static void +replication_relay_recv(struct ev_io *w, int revents); + +/** Send a single row to the client. */ +static int +replication_relay_send_row(struct recovery_state *r __attribute__((unused)), struct tbuf *t); + + +/*-----------------------------------------------------------------------------*/ +/* replication module */ +/*-----------------------------------------------------------------------------*/ + +/** Check replication module configuration. */ +int +replication_check_config(struct tarantool_cfg *config) +{ + if (config->replication_port < 0 || + config->replication_port >= USHRT_MAX) { + say_error("invalid replication port value: %"PRId32, + config->replication_port); + return -1; + } + + return 0; +} + +/** Pre-fork replication spawner process. */ +void +replication_prefork() +{ + if (cfg.replication_port == 0) { + /* replication is not needed, do nothing */ + return; + } + int sockpair[2]; + /* + * Create UNIX sockets to communicate between the main and + * spawner processes. + */ + if (socketpair(PF_LOCAL, SOCK_STREAM, 0, sockpair) != 0) + panic_syserror("socketpair"); + + /* create spawner */ + pid_t pid = fork(); + if (pid == -1) + panic_syserror("fork"); + + if (pid != 0) { + /* parent process: tarantool */ + close(sockpair[1]); + master_to_spawner_sock = sockpair[0]; + if (set_nonblock(master_to_spawner_sock) == -1) + panic("set_nonblock"); + } else { + /* child process: spawner */ + close(sockpair[0]); + /* + * Move to an own process group, to not receive + * signals from the controlling tty. + */ + setpgid(0, 0); + spawner_init(sockpair[1]); + } +} + +/** + * Create a fiber which accepts client connections and pushes them + * to replication spawner. + */ + +void +replication_init() +{ + if (cfg.replication_port == 0) + return; /* replication is not in use */ + + char fiber_name[FIBER_NAME_MAXLEN]; + + /* create acceptor fiber */ + snprintf(fiber_name, FIBER_NAME_MAXLEN, "%i/replication", cfg.replication_port); + + struct fiber *acceptor = fiber_create(fiber_name, -1, -1, acceptor_handler, NULL); + + if (acceptor == NULL) { + panic("create fiber fail"); + } + + fiber_call(acceptor); +} + + +/*-----------------------------------------------------------------------------*/ +/* replication accept/sender fibers */ +/*-----------------------------------------------------------------------------*/ + +/** Replication acceptor fiber handler. */ +static void +acceptor_handler(void *data __attribute__((unused))) +{ + if (fiber_serv_socket(fiber, cfg.replication_port, true, 0.1) != 0) { + panic("can not bind to replication port"); + } + + for (;;) { + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int client_sock = -1; + + /* wait new connection request */ + fiber_io_start(fiber->fd, EV_READ); + fiber_io_yield(); + /* accept connection */ + client_sock = accept(fiber->fd, &addr, &addrlen); + if (client_sock == -1) { + if (errno == EAGAIN && errno == EWOULDBLOCK) { + continue; + } + panic_syserror("accept"); + } + fiber_io_stop(fiber->fd, EV_READ); + say_info("connection from %s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + acceptor_send_sock(client_sock); + } +} + + +/** Send a file descriptor to the spawner. */ +static void +acceptor_send_sock(int client_sock) +{ + struct msghdr msg; + struct iovec iov[1]; + char control_buf[CMSG_SPACE(sizeof(int))]; + struct cmsghdr *control_message = NULL; + int cmd_code = 0; + + iov[0].iov_base = &cmd_code; + iov[0].iov_len = sizeof(cmd_code); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = control_buf; + msg.msg_controllen = sizeof(control_buf); + + control_message = CMSG_FIRSTHDR(&msg); + control_message->cmsg_len = CMSG_LEN(sizeof(int)); + control_message->cmsg_level = SOL_SOCKET; + control_message->cmsg_type = SCM_RIGHTS; + *((int *) CMSG_DATA(control_message)) = client_sock; + + /* wait, when interprocess comm. socket is ready for write */ + fiber_io_start(master_to_spawner_sock, EV_WRITE); + fiber_io_yield(); + /* send client socket to the spawner */ + if (sendmsg(master_to_spawner_sock, &msg, 0) < 0) + say_syserror("sendmsg"); + + fiber_io_stop(master_to_spawner_sock, EV_WRITE); + /* close client socket in the main process */ + close(client_sock); +} + + +/*-----------------------------------------------------------------------------*/ +/* spawner process */ +/*-----------------------------------------------------------------------------*/ + +/** Initialize the spawner. */ + +static void +spawner_init(int sock) +{ + char name[sizeof(fiber->name)]; + struct sigaction sa; + + snprintf(name, sizeof(name), "spawner%s", custom_proc_title); + fiber_set_name(fiber, name); + set_proc_title(name); + + /* init replicator process context */ + spawner.sock = sock; + + /* init signals */ + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + + /* + * The spawner normally does not receive any signals, + * except when sent by a system administrator. + * When the master process terminates, it closes its end + * of the socket pair and this signals to the spawner that + * it's time to die as well. But before exiting, the + * spawner must kill and collect all active replication + * relays. This is why we need to change the default + * signal action here. + */ + sa.sa_handler = spawner_signal_handler; + + if (sigaction(SIGHUP, &sa, NULL) == -1 || + sigaction(SIGINT, &sa, NULL) == -1 || + sigaction(SIGTERM, &sa, NULL) == -1 || + sigaction(SIGPIPE, &sa, NULL) == -1) + say_syserror("sigaction"); + + sa.sa_handler = spawner_sigchld_handler; + + if (sigaction(SIGCHLD, &sa, NULL) == -1) + say_syserror("sigaction"); + + say_crit("initialized"); + spawner_main_loop(); +} + + + +static int +spawner_unpack_cmsg(struct msghdr *msg) +{ + struct cmsghdr *control_message; + for (control_message = CMSG_FIRSTHDR(msg); + control_message != NULL; + control_message = CMSG_NXTHDR(msg, control_message)) + if ((control_message->cmsg_level == SOL_SOCKET) && + (control_message->cmsg_type == SCM_RIGHTS)) + return *((int *) CMSG_DATA(control_message)); + assert(false); + return -1; +} + +/** Replication spawner process main loop. */ +static void +spawner_main_loop() +{ + struct msghdr msg; + struct iovec iov[1]; + char control_buf[CMSG_SPACE(sizeof(int))]; + int cmd_code = 0; + int client_sock; + + iov[0].iov_base = &cmd_code; + iov[0].iov_len = sizeof(cmd_code); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = control_buf; + msg.msg_controllen = sizeof(control_buf); + + while (!spawner.killed) { + int msglen = recvmsg(spawner.sock, &msg, 0); + if (msglen > 0) { + client_sock = spawner_unpack_cmsg(&msg); + spawner_create_replication_relay(client_sock); + } else if (msglen == 0) { /* orderly master shutdown */ + say_info("Exiting: master shutdown"); + break; + } else { /* msglen == -1 */ + if (errno != EINTR) + say_syserror("recvmsg"); + /* continue, the error may be temporary */ + } + } + spawner_shutdown(); +} + +/** Replication spawner shutdown. */ +static void +spawner_shutdown() +{ + /* close socket */ + close(spawner.sock); + + /* kill all children */ + spawner_shutdown_children(); + + exit(EXIT_SUCCESS); +} + +/** Replication spawner signal handler for terminating signals. */ +static void spawner_signal_handler(int signal) +{ + say_info("Exiting: %s", strsignal(signal)); + spawner.killed = signal; +} + +/** Wait for a terminated child. */ +static void +spawner_sigchld_handler(int signo __attribute__((unused))) +{ + do { + int exit_status; + pid_t pid = waitpid(-1, &exit_status, WNOHANG); + switch (pid) { + case -1: + if (errno != ECHILD) + say_syserror("waitpid"); + case 0: /* no more changes in children status */ + return; + default: + spawner.child_count--; + say_info("child finished: pid = %d, exit status = %d", + (int) pid, WEXITSTATUS(exit_status)); + } + } while (spawner.child_count > 0); +} + +/** Create replication client handler process. */ +static int +spawner_create_replication_relay(int client_sock) +{ + pid_t pid = fork(); + + if (pid < 0) { + say_syserror("fork"); + return -1; + } + + if (pid == 0) { + close(spawner.sock); + replication_relay_loop(client_sock); + } else { + spawner.child_count++; + close(client_sock); + say_info("created a replication relay: pid = %d", (int) pid); + } + + return 0; +} + +/** Replicator spawner shutdown: kill and wait for children. */ +static void +spawner_shutdown_children() +{ + int kill_signo = SIGTERM, signo; + sigset_t mask, orig_mask, alarm_mask; + +retry: + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + sigaddset(&mask, SIGALRM); + /* + * We're going to kill the entire process group, which + * we're part of. Handle the signal sent to ourselves. + */ + sigaddset(&mask, kill_signo); + + if (spawner.child_count == 0) + return; + + /* Block SIGCHLD and SIGALRM to avoid races. */ + if (sigprocmask(SIG_BLOCK, &mask, &orig_mask)) { + say_syserror("sigprocmask"); + return; + } + + /* We'll wait for children no longer than 5 sec. */ + alarm(5); + + say_info("sending signal %d to %"PRIu32" children", kill_signo, + (u32) spawner.child_count); + + kill(0, kill_signo); + + say_info("waiting for children for up to 5 seconds"); + + while (spawner.child_count > 0) { + sigwait(&mask, &signo); + if (signo == SIGALRM) { /* timed out */ + break; + } + else if (signo != kill_signo) { + assert(signo == SIGCHLD); + spawner_sigchld_handler(signo); + } + } + + /* Reset the alarm. */ + alarm(0); + + /* Clear possibly pending SIGALRM. */ + sigpending(&alarm_mask); + if (sigismember(&alarm_mask, SIGALRM)) { + sigemptyset(&alarm_mask); + sigaddset(&alarm_mask, SIGALRM); + sigwait(&alarm_mask, &signo); + } + + /* Restore the old mask. */ + if (sigprocmask(SIG_SETMASK, &orig_mask, NULL)) { + say_syserror("sigprocmask"); + return; + } + + if (kill_signo == SIGTERM) { + kill_signo = SIGKILL; + goto retry; + } +} + +/** The main loop of replication client service process. */ +static void +replication_relay_loop(int client_sock) +{ + char name[FIBER_NAME_MAXLEN]; + struct sigaction sa; + struct recovery_state *log_io; + struct tbuf *ver; + i64 lsn; + ssize_t r; + + fiber->has_peer = true; + fiber->fd = client_sock; + + /* set process title and fiber name */ + memset(name, 0, sizeof(name)); + snprintf(name, sizeof(name), "relay/%s", fiber_peer_name(fiber)); + fiber_set_name(fiber, name); + set_proc_title("%s%s", name, custom_proc_title); + + /* init signals */ + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + + /* Reset all signals to their defaults. */ + sa.sa_handler = SIG_DFL; + if (sigaction(SIGCHLD, &sa, NULL) == -1 || + sigaction(SIGHUP, &sa, NULL) == -1 || + sigaction(SIGINT, &sa, NULL) == -1 || + sigaction(SIGTERM, &sa, NULL) == -1) + say_syserror("sigaction"); + + /* Block SIGPIPE, we already handle EPIPE. */ + sa.sa_handler = SIG_IGN; + if (sigaction(SIGPIPE, &sa, NULL) == -1) + say_syserror("sigaction"); + + r = read(fiber->fd, &lsn, sizeof(lsn)); + if (r != sizeof(lsn)) { + if (r < 0) { + panic_syserror("read"); + } + panic("invalid LSN request size: %zu", r); + } + say_info("starting recovery from lsn:%"PRIi64, lsn); + + ver = tbuf_alloc(fiber->pool); + tbuf_append(ver, &default_version, sizeof(default_version)); + replication_relay_send_row(NULL, ver); + + /* init libev events handlers */ + ev_default_loop(0); + + /* init read events */ + struct ev_io sock_read_ev; + int sock_read_fd = fiber->fd; + sock_read_ev.data = (void *)&sock_read_fd; + ev_io_init(&sock_read_ev, replication_relay_recv, sock_read_fd, EV_READ); + ev_io_start(&sock_read_ev); + + /* init reovery porcess */ + log_io = recover_init(NULL, cfg.wal_dir, + replication_relay_send_row, INT32_MAX, 0, 64, RECOVER_READONLY, false); + + recover(log_io, lsn); + recover_follow(log_io, 0.1); + + ev_loop(0); + + say_crit("exiting the relay loop"); + exit(EXIT_SUCCESS); +} + +/** Receive data event to replication socket handler */ +static void +replication_relay_recv(struct ev_io *w, int __attribute__((unused)) revents) +{ + int fd = *((int *)w->data); + u8 data; + + int result = recv(fd, &data, sizeof(data), 0); + + if (result == 0 || (result < 0 && errno == ECONNRESET)) { + say_info("the client has closed its replication socket, exiting"); + exit(EXIT_SUCCESS); + } + if (result < 0) + say_syserror("recv"); + + exit(EXIT_FAILURE); +} + +/** Send to row to client. */ +static int +replication_relay_send_row(struct recovery_state *r __attribute__((unused)), struct tbuf *t) +{ + u8 *data = t->data; + ssize_t bytes, len = t->len; + while (len > 0) { + bytes = write(fiber->fd, data, len); + if (bytes < 0) { + if (errno == EPIPE) { + /* socket closed on opposite site */ + goto shutdown_handler; + } + panic_syserror("write"); + } + len -= bytes; + data += bytes; + } + + say_debug("send row: %" PRIu32 " bytes %s", t->len, tbuf_to_hex(t)); + return 0; +shutdown_handler: + say_info("the client has closed its replication socket, exiting"); + exit(EXIT_SUCCESS); +} + diff --git a/core/tarantool.m b/core/tarantool.m index ab05b24c98ea2b8758671dfc6d17324c69144625..414bc9120036bc7afb6d1bf8389f0f5d2abefa19 100644 --- a/core/tarantool.m +++ b/core/tarantool.m @@ -1,6 +1,6 @@ /* - * Copyright (C) 2010 Mail.RU - * Copyright (C) 2010 Yuriy Vostrikov + * Copyright (C) 2010-2011 Mail.RU + * Copyright (C) 2010-2011 Yuriy Vostrikov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -43,6 +43,7 @@ # include <sys/prctl.h> #endif #include <admin.h> +#include <replication.h> #include <fiber.h> #include <iproto.h> #include <latch.h> @@ -62,6 +63,8 @@ static pid_t master_pid; const char *cfg_filename = DEFAULT_CFG_FILENAME; char *cfg_filename_fullpath = NULL; char *binary_filename; +char *custom_proc_title; + struct tarantool_cfg cfg; struct recovery_state *recovery_state; @@ -97,6 +100,9 @@ load_cfg(struct tarantool_cfg *conf, i32 check_rdonly) if (n_accepted == 0 || n_skipped != 0) return -1; + if (replication_check_config(conf) != 0) + return -1; + return mod_check_config(conf); } @@ -184,7 +190,6 @@ tarantool_uptime(void) return ev_now() - start_time; } -#ifdef STORAGE int snapshot(void *ev, int events __attribute__((unused))) { @@ -227,7 +232,6 @@ snapshot(void *ev, int events __attribute__((unused))) return 0; } -#endif static void sig_int(int signal) @@ -341,9 +345,7 @@ initialize_minimal() int main(int argc, char **argv) { -#ifdef STORAGE const char *cat_filename = NULL; -#endif const char *cfg_paramname = NULL; #ifndef HAVE_LIBC_STACK_END @@ -376,13 +378,11 @@ main(int argc, char **argv) gopt_option('c', GOPT_ARG, gopt_shorts('c'), gopt_longs("config"), "=FILE", "path to configuration file (default: " DEFAULT_CFG_FILENAME ")"), -#ifdef STORAGE gopt_option('C', GOPT_ARG, gopt_shorts(0), gopt_longs("cat"), "=FILE", "cat snapshot file to stdout in readable format and exit"), gopt_option('I', 0, gopt_shorts(0), gopt_longs("init-storage", "init_storage"), NULL, "initialize storage (an empty snapshot file) and exit"), -#endif gopt_option('v', 0, gopt_shorts('v'), gopt_longs("verbose"), NULL, "increase verbosity level in log messages"), gopt_option('B', 0, gopt_shorts('B'), gopt_longs("background"), @@ -483,7 +483,7 @@ main(int argc, char **argv) exit(EX_OSERR); } } else { - say_error("can't swith to %s: i'm not root", cfg.username); + say_error("can't switch to %s: i'm not root", cfg.username); } } @@ -506,7 +506,6 @@ main(int argc, char **argv) #endif } -#ifdef STORAGE if (gopt_arg(opt, 'C', &cat_filename)) { initialize_minimal(); if (access(cat_filename, R_OK) == -1) { @@ -525,7 +524,6 @@ main(int argc, char **argv) snapshot_save(recovery_state, mod_snapshot); exit(EXIT_SUCCESS); } -#endif if (gopt(opt, 'B')) daemonize(1, 1); @@ -535,14 +533,21 @@ main(int argc, char **argv) atexit(remove_pid); } + /* init process title */ + if (cfg.custom_proc_title == NULL) { + custom_proc_title = ""; + } else { + custom_proc_title = palloc(eter_pool, strlen(cfg.custom_proc_title) + 2); + strcat(custom_proc_title, "@"); + strcat(custom_proc_title, cfg.custom_proc_title); + } + say_logger_init(cfg.logger_nonblock); booting = false; -#if defined(UTILITY) - initialize_minimal(); - signal_init(); - mod_init(); -#elif defined(STORAGE) + initialize(cfg.slab_alloc_arena, cfg.slab_alloc_minimal, cfg.slab_alloc_factor); + replication_prefork(); + ev_default_loop(EVFLAG_AUTO); ev_signal *ev_sig; @@ -550,11 +555,12 @@ main(int argc, char **argv) ev_signal_init(ev_sig, (void *)snapshot, SIGUSR1); ev_signal_start(ev_sig); - initialize(cfg.slab_alloc_arena, cfg.slab_alloc_minimal, cfg.slab_alloc_factor); signal_init(); mod_init(); admin_init(); + replication_init(); + prelease(fiber->pool); say_crit("log level %i", cfg.log_level); say_crit("entering event loop"); @@ -564,8 +570,6 @@ main(int argc, char **argv) start_time = ev_now(); ev_loop(0); say_crit("exiting loop"); -#else -#error UTILITY or STORAGE must be defined -#endif + return 0; } diff --git a/include/fiber.h b/include/fiber.h index ab8cd7e679dc7e6265c270bae709fd22a8e827e1..0a85b7e0d64b438e25edc7f70c1990759c7d5b76 100644 --- a/include/fiber.h +++ b/include/fiber.h @@ -42,7 +42,7 @@ #include "exception.h" -#define FIBER_NAME_MAXLEN 16 +#define FIBER_NAME_MAXLEN 32 #define FIBER_READING_INBOX 0x1 /** Can this fiber be cancelled? */ @@ -129,6 +129,16 @@ void fiber_init(void); struct fiber *fiber_create(const char *name, int fd, int inbox_size, void (*f) (void *), void *); void fiber_set_name(struct fiber *fiber, const char *name); void wait_for_child(pid_t pid); + +void +fiber_io_start(int fd, int events); + +void +fiber_io_yield(); + +void +fiber_io_stop(int fd, int events); + void yield(void); void fiber_destroy_all(); @@ -193,10 +203,24 @@ int set_nonblock(int sock); typedef void (*fiber_server_callback)(void *); -struct fiber *fiber_server(int port, +struct fiber *fiber_server(const char *name, int port, fiber_server_callback callback, void *, void (*on_bind) (void *)); +/** + * Create server socket and bind his on port. cfd.bind_ipaddr param using as IP address. + * + * @param type the fiber server type (TCP or UDP) + * @param port the bind ip port. + * @param retry the retry flag, if flag up the function will be try again to bind + * socket after delay. + * @param delay the bind socket retry delay in sec. + * + * @return on success, zero is returned. on error, -1 is returned. + */ +int +fiber_serv_socket(struct fiber *fiber, unsigned short port, bool retry, ev_tstamp delay); + struct child *spawn_child(const char *name, int inbox_size, struct tbuf *(*handler) (void *, struct tbuf *), void *state); diff --git a/include/log_io.h b/include/log_io.h index 1b3214ac91373499d7408f069120bde5f8637be5..a1ce9bd6e3b4bf7beb4cf0c16a8e490336a4343b 100644 --- a/include/log_io.h +++ b/include/log_io.h @@ -124,11 +124,6 @@ struct recovery_state { void *data; }; -struct remote_state { - struct recovery_state *r; - int (*handler) (struct recovery_state * r, struct tbuf *row); -}; - struct wal_write_request { i64 lsn; u32 len; @@ -169,8 +164,7 @@ void recovery_wait_lsn(struct recovery_state *r, i64 lsn); int read_log(const char *filename, row_handler xlog_handler, row_handler snap_handler, void *state); -void recovery_follow_remote(struct recovery_state *r, - const char *ip_addr, int port); +void recovery_follow_remote(struct recovery_state *r, const char *remote); void recovery_stop_remote(struct recovery_state *r); struct log_io_iter; diff --git a/include/replication.h b/include/replication.h new file mode 100644 index 0000000000000000000000000000000000000000..252062c50c728e9cd6dcb3ae2881bb1f7d531314 --- /dev/null +++ b/include/replication.h @@ -0,0 +1,58 @@ +#ifndef TARANTOOL_REPLICATION_H_INCLUDED +#define TARANTOOL_REPLICATION_H_INCLUDED +/* + * Copyright (C) 2011 Mail.RU + * Copyright (C) 2011 Yuriy Vostrikov + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <tarantool.h> +#include <util.h> + +/** + * Check replication configuration. + * + * @param config config file to check. + * + * @return 0 on success, -1 on error + */ +int +replication_check_config(struct tarantool_cfg *config); + +/** + * Pre-fork replication spawner process. + * + * @return None. Panics and exits on error. + */ +void +replication_prefork(); + +/** + * Initialize replication module. + * + * @return None. Panics and exits on error. + */ +void +replication_init(); + +#endif // TARANTOOL_REPLICATION_H_INCLUDED + diff --git a/include/tarantool.h b/include/tarantool.h index 29301ecdb9c8f8ce602ef8086ca4f56a8246a0e5..e446641ea23954a4ec3221c368869fbce024077c 100644 --- a/include/tarantool.h +++ b/include/tarantool.h @@ -46,6 +46,7 @@ extern struct tarantool_cfg cfg; extern const char *cfg_filename; extern bool init_storage, booting; extern char *binary_filename; +extern char *custom_proc_title; i32 reload_cfg(struct tbuf *out); int snapshot(void * /* ev */, int /* events */); const char *tarantool_version(void); diff --git a/mod/CMakeLists.txt b/mod/CMakeLists.txt index b7cc1e1487cdc0f9d5c3596268016da0268c1fbd..c5d680fbeb82b9ae32588d9e6ab5a14eccbc93fc 100644 --- a/mod/CMakeLists.txt +++ b/mod/CMakeLists.txt @@ -9,15 +9,9 @@ function(tarantool_module mod) ${module_sources} ${CMAKE_SOURCE_DIR}/cfg/tarantool_${mod}_cfg.c) - if (mod STREQUAL "feeder") - set (STORAGE_OR_UTILITY "UTILITY") - else() - set (STORAGE_OR_UTILITY "STORAGE") - endif() - add_library(lt${mod} STATIC ${recompiled_core_sources}) set_target_properties(lt${mod} PROPERTIES COMPILE_FLAGS - "${core_cflags} -D${STORAGE_OR_UTILITY} -DTARANTOOL_CONFIG='<cfg/tarantool_${mod}_cfg.h>'") + "${core_cflags} -DTARANTOOL_CONFIG='<cfg/tarantool_${mod}_cfg.h>'") add_dependencies(lt${mod} generate_headers generate_admin_c) target_link_libraries(tarantool_${mod} lt${mod} ${common_libraries}) diff --git a/mod/box/box.m b/mod/box/box.m index ae4e2af7bfde4059e5d8cd311a1339d34bea5e89..dcd1532fbe8c9fbb77fdc6da7521e270e4ddac5c 100644 --- a/mod/box/box.m +++ b/mod/box/box.m @@ -58,8 +58,6 @@ static char status[64] = "unknown"; static int stat_base; STRS(messages, MESSAGES); -static char *custom_proc_title; - /* hooks */ typedef int (*box_hook_t) (struct box_txn * txn); @@ -1172,9 +1170,10 @@ title(const char *fmt, ...) va_end(ap); int ports[] = { cfg.primary_port, cfg.secondary_port, - cfg.memcached_port, cfg.admin_port }; + cfg.memcached_port, cfg.admin_port, + cfg.replication_port }; int *pptr = ports; - char *names[] = { "pri", "sec", "memc", "adm", NULL }; + char *names[] = { "pri", "sec", "memc", "adm", "rpl", NULL }; char **nptr = names; for (; *nptr; nptr++, pptr++) @@ -1189,33 +1188,29 @@ title(const char *fmt, ...) static void box_enter_master_or_replica_mode(struct tarantool_cfg *conf) { - if (conf->remote_hot_standby) { + if (conf->replication_source != NULL) { rw_callback = box_process_ro; recovery_wait_lsn(recovery_state, recovery_state->lsn); - recovery_follow_remote(recovery_state, - conf->wal_feeder_ipaddr, - conf->wal_feeder_port); - - snprintf(status, sizeof(status), "replica/%s:%i%s", - conf->wal_feeder_ipaddr, conf->wal_feeder_port, - custom_proc_title); - title("replica/%s:%i%s", conf->wal_feeder_ipaddr, - conf->wal_feeder_port, custom_proc_title); + recovery_follow_remote(recovery_state, conf->replication_source); + + snprintf(status, sizeof(status), "replica/%s%s", + conf->replication_source, custom_proc_title); + title("replica/%s%s", conf->replication_source, custom_proc_title); } else { rw_callback = box_process_rw; memcached_start_expire(); - snprintf(status, sizeof(status), "primary"); - title("primary"); + snprintf(status, sizeof(status), "primary%s", custom_proc_title); + title("primary%s", custom_proc_title); say_info("I am primary"); } } static void -box_leave_local_hot_standby_mode(void *data __attribute__((unused))) +box_leave_local_standby_mode(void *data __attribute__((unused))) { recover_finalize(recovery_state); @@ -1225,22 +1220,31 @@ box_leave_local_hot_standby_mode(void *data __attribute__((unused))) i32 mod_check_config(struct tarantool_cfg *conf) { - /* local & remote standby can not work together */ - if (conf->remote_hot_standby > 0 && conf->local_hot_standby > 0) { - out_warning(0, "Remote and local hot standby modes " + /* replication & hot standby modes can not work together */ + if (conf->replication_source != NULL && conf->local_hot_standby > 0) { + out_warning(0, "replication and local hot standby modes " "can't be enabled simultaneously"); return -1; } - /* in the remote_hot_standby mode wal_feeder_ipaddr and wal_feeder_port must be defiend */ - if (conf->remote_hot_standby && - (conf->wal_feeder_ipaddr == NULL || conf->wal_feeder_port == 0)) { - out_warning(0, "wal_feeder_ipaddr & wal_feeder_port " - "must be provided in remote_hot_standby mode"); - return -1; + /* check replication mode */ + if (conf->replication_source != NULL) { + /* check replication port */ + char ip_addr[32]; + int port; + + if (sscanf(conf->replication_source, "%31[^:]:%i", + ip_addr, &port) != 2) { + out_warning(0, "replication source IP address is not recognized"); + return -1; + } + if (port <= 0 || port >= USHRT_MAX) { + out_warning(0, "invalid replication source port value: %i", port); + return -1; + } } - /* check primary ports */ + /* check primary port */ if (conf->primary_port != 0 && (conf->primary_port <= 0 || conf->primary_port >= USHRT_MAX)) { out_warning(0, "invalid primary port value: %i", conf->primary_port); @@ -1393,22 +1397,22 @@ mod_check_config(struct tarantool_cfg *conf) i32 mod_reload_config(struct tarantool_cfg *old_conf, struct tarantool_cfg *new_conf) { - if (old_conf->remote_hot_standby != new_conf->remote_hot_standby || - (old_conf->remote_hot_standby != 0 && - (strcmp(old_conf->wal_feeder_ipaddr, - new_conf->wal_feeder_ipaddr) != 0 || - old_conf->wal_feeder_port != new_conf->wal_feeder_port))) { + bool old_is_replica = old_conf->replication_source != NULL; + bool new_is_replica = new_conf->replication_source != NULL; + + if (old_is_replica != new_is_replica || + (old_is_replica && + (strcmp(old_conf->replication_source, new_conf->replication_source) != 0))) { if (recovery_state->finalize != true) { out_warning(0, "Could not propagate %s before local recovery finished", - old_conf->remote_hot_standby == true ? "slave to master" : + old_is_replica == true ? "slave to master" : "master to slave"); return -1; } - if (old_conf->remote_hot_standby == 0 && - new_conf->remote_hot_standby != 0) + if (!old_is_replica && new_is_replica) memcached_stop_expire(); if (recovery_state->remote_recovery) @@ -1425,15 +1429,6 @@ mod_init(void) { static iproto_callback ro_callback = box_process_ro; - /* init process title */ - if (cfg.custom_proc_title == NULL) - custom_proc_title = ""; - else { - custom_proc_title = palloc(eter_pool, strlen(cfg.custom_proc_title) + 2); - strcat(custom_proc_title, "@"); - strcat(custom_proc_title, cfg.custom_proc_title); - } - title("loading"); /* initialization namespaces */ @@ -1473,21 +1468,22 @@ mod_init(void) title("hot_standby"); } - /* run memcached server */ - if (cfg.memcached_port != 0) - fiber_server(cfg.memcached_port, memcached_handler, NULL, NULL); + /* run primary server */ + if (cfg.primary_port != 0) + fiber_server("primary", cfg.primary_port, + (fiber_server_callback) iproto_interact, + &rw_callback, box_leave_local_standby_mode); /* run secondary server */ if (cfg.secondary_port != 0) - fiber_server(cfg.secondary_port, + fiber_server("secondary", cfg.secondary_port, (fiber_server_callback) iproto_interact, &ro_callback, NULL); - /* run primary server */ - if (cfg.primary_port != 0) - fiber_server(cfg.primary_port, - (fiber_server_callback) iproto_interact, - &rw_callback, box_leave_local_hot_standby_mode); + /* run memcached server */ + if (cfg.memcached_port != 0) + fiber_server("memcached", cfg.memcached_port, + memcached_handler, NULL, NULL); } int diff --git a/mod/box/box_cfg.cfg_tmpl b/mod/box/box_cfg.cfg_tmpl index 3ab9b3fbfbed6962a26934f6a1e1275becb28da9..b2592128c8d4d5afd98473931b5742462bbed29a 100644 --- a/mod/box/box_cfg.cfg_tmpl +++ b/mod/box/box_cfg.cfg_tmpl @@ -45,8 +45,10 @@ wal_fsync_delay=0, ro # size of WAL writer request buffer wal_writer_inbox_size=128, ro -# Local hot standby (if enabled, the server will run in local hot standby -# mode, continuously fetching WAL records from shared local directory). +# Local hot standby (if enabled, the server will run in hot +# standby mode, continuously fetching WAL records from wal_dir, +# until it is able to bind to the primary port. +# In local hot standby mode the server only accepts reads. local_hot_standby=0, ro # Delay, in seconds, between successive re-readings of wal_dir. # The re-scan is necessary to discover new WAL files or snapshots. @@ -59,12 +61,12 @@ wal_dir_rescan_delay=0.1, ro panic_on_snap_error=1, ro panic_on_wal_error=0, ro -# Remote hot standby (if enabled, the server will run in hot standby mode -# continuously fetching WAL records from wal_feeder_ipaddr:wal_feeder_port -remote_hot_standby=0 -wal_feeder_ipaddr=NULL -wal_feeder_port=0 - +# Replication mode (if enabled, the server, once +# bound to the primary port, will connect to +# replication_source (ipaddr:port) and run continously +# fetching records from it.. In replication mode the server +# only accepts reads. +replication_source=NULL namespace = [ { diff --git a/mod/feeder/CMakeLists.txt b/mod/feeder/CMakeLists.txt deleted file mode 100644 index 4852343fe75f602983ae07dca3c1f6329c7346c9..0000000000000000000000000000000000000000 --- a/mod/feeder/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -tarantool_module("feeder" feeder.m) diff --git a/mod/feeder/feeder.m b/mod/feeder/feeder.m deleted file mode 100644 index 0aa184da2ec91f8dfc44df4e26d09b938309b4f4..0000000000000000000000000000000000000000 --- a/mod/feeder/feeder.m +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (C) 2010 Mail.RU - * Copyright (C) 2010 Yuriy Vostrikov - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> - -#include <fiber.h> -#include <util.h> -#include "cfg/tarantool_feeder_cfg.h" -#include "palloc.h" -#include "log_io.h" -#include "say.h" -#include "tarantool.h" - -const char *mod_name = "Feeder"; -static char *custom_proc_title; - -static int -send_row(struct recovery_state *r __attribute__((unused)), struct tbuf *t) -{ - u8 *data = t->data; - ssize_t bytes, len = t->len; - while (len > 0) { - bytes = write(fiber->fd, data, len); - if (bytes < 0) { - say_syserror("write"); - exit(EXIT_SUCCESS); - } - len -= bytes; - data += bytes; - } - - say_debug("send row: %" PRIu32 " bytes %s", t->len, tbuf_to_hex(t)); - - return 0; -} - -static void -recover_feed_slave(int sock) -{ - struct recovery_state *log_io; - struct tbuf *ver; - i64 lsn; - ssize_t r; - - fiber->has_peer = true; - fiber->fd = sock; - fiber_set_name(fiber, "feeder"); - set_proc_title("replication_relay%s %s", custom_proc_title, fiber_peer_name(fiber)); - - ev_default_loop(0); - - r = read(fiber->fd, &lsn, sizeof(lsn)); - if (r != sizeof(lsn)) { - if (r < 0) - say_syserror("read"); - exit(EXIT_SUCCESS); - } - - ver = tbuf_alloc(fiber->pool); - tbuf_append(ver, &default_version, sizeof(default_version)); - send_row(NULL, ver); - - log_io = recover_init(NULL, cfg.wal_feeder_dir, - send_row, INT32_MAX, 0, 64, RECOVER_READONLY, false); - - recover(log_io, lsn); - recover_follow(log_io, 0.1); - ev_loop(0); -} - -i32 -mod_check_config(struct tarantool_cfg *conf __attribute__((unused))) -{ - return 0; -} - -i32 -mod_reload_config(struct tarantool_cfg *old_conf __attribute__((unused)), - struct tarantool_cfg *new_conf __attribute__((unused))) -{ - return 0; -} - -void -mod_init(void) -{ - int server, client; - struct sockaddr_in server_addr; - int one = 1; - - if (cfg.wal_feeder_bind_port == 0) - panic("can't start feeder without wal_feeder_bind_port"); - - if (cfg.wal_feeder_dir == NULL) - panic("can't start feeder without wal_feeder_dir"); - - if (cfg.custom_proc_title == NULL) - custom_proc_title = ""; - else { - custom_proc_title = palloc(eter_pool, strlen(cfg.custom_proc_title) + 2); - strcat(custom_proc_title, "@"); - strcat(custom_proc_title, cfg.custom_proc_title); - } - - set_proc_title("replication_server%s %s:%i", - custom_proc_title, - cfg.wal_feeder_bind_ipaddr == NULL ? "ANY" : cfg.wal_feeder_bind_ipaddr, - cfg.wal_feeder_bind_port); - - server = socket(AF_INET, SOCK_STREAM, 0); - if (server < 0) { - say_syserror("socket"); - goto exit; - } - - memset(&server_addr, 0, sizeof(server_addr)); - - server_addr.sin_family = AF_INET; - if (cfg.wal_feeder_bind_ipaddr == NULL) { - server_addr.sin_addr.s_addr = INADDR_ANY; - } else { - server_addr.sin_addr.s_addr = inet_addr(cfg.wal_feeder_bind_ipaddr); - if (server_addr.sin_addr.s_addr == INADDR_NONE) - panic("inet_addr: %s'", cfg.wal_feeder_bind_ipaddr); - } - server_addr.sin_port = htons(cfg.wal_feeder_bind_port); - - if (setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) { - say_syserror("setsockopt"); - goto exit; - } - - if (bind(server, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { - say_syserror("bind"); - goto exit; - } - - listen(server, 5); - - for (;;) { - pid_t child; - client = accept(server, NULL, NULL); - if (client < 0) { - say_syserror("accept"); - continue; - } - child = fork(); - if (child < 0) { - say_syserror("fork"); - continue; - } - if (child == 0) - recover_feed_slave(client); - else - close(client); - } - exit: - exit(EXIT_FAILURE); -} - -void -mod_exec(char *str __attribute__((unused)), int len __attribute__((unused)), - struct tbuf *out) -{ - tbuf_printf(out, "Unimplemented"); -} diff --git a/mod/feeder/feeder_cfg.cfg_tmpl b/mod/feeder/feeder_cfg.cfg_tmpl deleted file mode 100644 index ae0dfb4da7e96e9c51ab15f3c1ed4b94866e7d4e..0000000000000000000000000000000000000000 --- a/mod/feeder/feeder_cfg.cfg_tmpl +++ /dev/null @@ -1,11 +0,0 @@ - -# feed WAL to remote replicas -# feeder accepts it's clients on wal_feeder_bind_ipaddr:wal_feeder_bind_port -wal_feeder_bind_ipaddr=NULL, ro, required -wal_feeder_bind_port=0, ro, required - -# Directory with WAL files to serve -wal_feeder_dir=NULL, ro, required - -# custom proc title is appended after normal -custom_proc_title=NULL, ro diff --git a/test/box/show.result b/test/box/show.result index ed96c04e25574cfe1304e5b26427a1409812a767..074eaae954252c8760b09cfdd1095a1da77e909b 100644 --- a/test/box/show.result +++ b/test/box/show.result @@ -28,8 +28,10 @@ show configuration --- configuration: username: (null) + bind_ipaddr: "INADDR_ANY" coredump: "0" admin_port: "33015" + replication_port: "0" log_level: "4" slab_alloc_arena: "0.1" slab_alloc_minimal: "64" @@ -60,9 +62,7 @@ configuration: wal_dir_rescan_delay: "0.1" panic_on_snap_error: "1" panic_on_wal_error: "0" - remote_hot_standby: "0" - wal_feeder_ipaddr: (null) - wal_feeder_port: "0" + replication_source: (null) namespace[0].enabled: "1" namespace[0].cardinality: "-1" namespace[0].estimated_rows: "0" diff --git a/test/box_replication/tarantool_beholder_to_slave.cfg b/test/box_replication/cfg/hot_standby.cfg similarity index 66% rename from test/box_replication/tarantool_beholder_to_slave.cfg rename to test/box_replication/cfg/hot_standby.cfg index 9b97eba8a467cbdecdfe2286c2f1f3bb4ae18e00..9d559d6443e34c9df4c26d4f21cda39f75a3837d 100644 --- a/test/box_replication/tarantool_beholder_to_slave.cfg +++ b/test/box_replication/cfg/hot_standby.cfg @@ -1,17 +1,20 @@ -slab_alloc_arena=0.05 pid_file = "tarantool.pid" +logger="cat - >> tarantool.log" + +bind_ipaddr="INADDR_ANY" + +wal_dir="../" +snap_dir="../" primary_port = 33013 secondary_port = 33024 admin_port = 33025 -logger="tee -a tarantool.log" +replication_port=33016 +custom_proc_title="hot_standby" + namespace[0].enabled = 1 namespace[0].index[0].type = "HASH" namespace[0].index[0].unique = 1 namespace[0].index[0].key_field[0].fieldno = 0 namespace[0].index[0].key_field[0].type = "NUM" - -remote_hot_standby = 1 -wal_feeder_ipaddr = "127.0.0.1" -wal_feeder_port = 33116 diff --git a/test/box_replication/tarantool.cfg b/test/box_replication/cfg/master.cfg similarity index 71% rename from test/box_replication/tarantool.cfg rename to test/box_replication/cfg/master.cfg index 9f75124040313b3cb13d4cdbdc1771d286e746dd..603e36ed80a57012b17e64d895c4d4f90d3463a4 100644 --- a/test/box_replication/tarantool.cfg +++ b/test/box_replication/cfg/master.cfg @@ -1,13 +1,18 @@ -slab_alloc_arena=0.05 pid_file = "tarantool.pid" +logger="cat - >> tarantool.log" + +bind_ipaddr="INADDR_ANY" primary_port = 33013 secondary_port = 33014 admin_port = 33015 -logger="tee -a tarantool.log" +replication_port=33016 +custom_proc_title="master" + namespace[0].enabled = 1 namespace[0].index[0].type = "HASH" namespace[0].index[0].unique = 1 namespace[0].index[0].key_field[0].fieldno = 0 namespace[0].index[0].key_field[0].type = "NUM" + diff --git a/test/box_replication/tarantool_to_slave.cfg b/test/box_replication/cfg/master_to_replica.cfg similarity index 65% rename from test/box_replication/tarantool_to_slave.cfg rename to test/box_replication/cfg/master_to_replica.cfg index fe58a84e4108d2fc959a332d1a6a74f5e08857f8..172daaca513f4a57482f5d64e24cf87a3d2a1bd1 100644 --- a/test/box_replication/tarantool_to_slave.cfg +++ b/test/box_replication/cfg/master_to_replica.cfg @@ -1,17 +1,19 @@ -slab_alloc_arena=0.05 pid_file = "tarantool.pid" +logger="cat - >> tarantool.log" + +bind_ipaddr="INADDR_ANY" primary_port = 33013 secondary_port = 33014 admin_port = 33015 -logger="tee -a tarantool.log" +replication_port=33016 +custom_proc_title="master" + namespace[0].enabled = 1 namespace[0].index[0].type = "HASH" namespace[0].index[0].unique = 1 namespace[0].index[0].key_field[0].fieldno = 0 namespace[0].index[0].key_field[0].type = "NUM" -remote_hot_standby = 1 -wal_feeder_ipaddr = "127.0.0.1" -wal_feeder_port = 33116 +replication_source = "127.0.0.1:33116" diff --git a/test/box_replication/tarantool_slave.cfg b/test/box_replication/cfg/replica.cfg similarity index 65% rename from test/box_replication/tarantool_slave.cfg rename to test/box_replication/cfg/replica.cfg index 0630c863552a63ff3d788347eb7b884020251f6f..a3d5898b04f6e5c5e3980289cc92705d79615706 100644 --- a/test/box_replication/tarantool_slave.cfg +++ b/test/box_replication/cfg/replica.cfg @@ -1,17 +1,19 @@ -slab_alloc_arena=0.05 pid_file = "tarantool.pid" +logger="cat - >> tarantool.log" + +bind_ipaddr="INADDR_ANY" primary_port = 33113 secondary_port = 33114 admin_port = 33115 -logger="tee -a tarantool.log" +replication_port=33116 +custom_proc_title="replica" + namespace[0].enabled = 1 namespace[0].index[0].type = "HASH" namespace[0].index[0].unique = 1 namespace[0].index[0].key_field[0].fieldno = 0 namespace[0].index[0].key_field[0].type = "NUM" -remote_hot_standby = 1 -wal_feeder_ipaddr = "127.0.0.1" -wal_feeder_port = 33016 +replication_source = "127.0.0.1:33016" diff --git a/test/box_replication/tarantool_slave_to_master.cfg b/test/box_replication/cfg/replica_to_master.cfg similarity index 71% rename from test/box_replication/tarantool_slave_to_master.cfg rename to test/box_replication/cfg/replica_to_master.cfg index 33eaa9799bb24ba56ed5df8a76eaaa153e6dd366..68bde6cc5cfb362b32fcaa2acd4ebd91f21f1f89 100644 --- a/test/box_replication/tarantool_slave_to_master.cfg +++ b/test/box_replication/cfg/replica_to_master.cfg @@ -1,11 +1,15 @@ -slab_alloc_arena=0.05 pid_file = "tarantool.pid" +logger="cat - >> tarantool.log" + +bind_ipaddr="INADDR_ANY" primary_port = 33113 secondary_port = 33114 admin_port = 33115 -logger="tee -a tarantool.log" +replication_port=33116 +custom_proc_title="replica" + namespace[0].enabled = 1 namespace[0].index[0].type = "HASH" namespace[0].index[0].unique = 1 diff --git a/test/box_replication/common.result b/test/box_replication/common.result deleted file mode 100644 index 36aeaa44d0cc95857c0d5bc5b9cebea34cae3fcc..0000000000000000000000000000000000000000 --- a/test/box_replication/common.result +++ /dev/null @@ -1,149 +0,0 @@ - -# -# Insert several tuples. -# - -insert into t0 values (1, 'the tuple #1') -Insert OK, 1 row affected -insert into t0 values (2, 'the tuple #2') -Insert OK, 1 row affected -insert into t0 values (3, 'the tuple #3') -Insert OK, 1 row affected -insert into t0 values (4, 'the tuple #4') -Insert OK, 1 row affected - -# -# Reconfigure slave to replicate from secondary feeder. -# - -reload configuration ---- -ok -... - -# -# Insert more tuples. -# - -insert into t0 values (5, 'the tuple #5') -Insert OK, 1 row affected -insert into t0 values (6, 'the tuple #6') -Insert OK, 1 row affected -insert into t0 values (7, 'the tuple #7') -Insert OK, 1 row affected -insert into t0 values (8, 'the tuple #8') -Insert OK, 1 row affected -insert into t0 values (9, 'the tuple #9') -Insert OK, 1 row affected - -# -# Select from master. -# - -select * from t0 where k0 = 1 -Found 1 tuple: -[1, 'the tuple #1'] -select * from t0 where k0 = 2 -Found 1 tuple: -[2, 'the tuple #2'] -select * from t0 where k0 = 3 -Found 1 tuple: -[3, 'the tuple #3'] -select * from t0 where k0 = 4 -Found 1 tuple: -[4, 'the tuple #4'] -select * from t0 where k0 = 5 -Found 1 tuple: -[5, 'the tuple #5'] -select * from t0 where k0 = 6 -Found 1 tuple: -[6, 'the tuple #6'] -select * from t0 where k0 = 7 -Found 1 tuple: -[7, 'the tuple #7'] -select * from t0 where k0 = 8 -Found 1 tuple: -[8, 'the tuple #8'] -select * from t0 where k0 = 9 -Found 1 tuple: -[9, 'the tuple #9'] - -# -# Select from slave. -# - -select * from t0 where k0 = 1 -Found 1 tuple: -[1, 'the tuple #1'] -select * from t0 where k0 = 2 -Found 1 tuple: -[2, 'the tuple #2'] -select * from t0 where k0 = 3 -Found 1 tuple: -[3, 'the tuple #3'] -select * from t0 where k0 = 4 -Found 1 tuple: -[4, 'the tuple #4'] -select * from t0 where k0 = 5 -Found 1 tuple: -[5, 'the tuple #5'] -select * from t0 where k0 = 6 -Found 1 tuple: -[6, 'the tuple #6'] -select * from t0 where k0 = 7 -Found 1 tuple: -[7, 'the tuple #7'] -select * from t0 where k0 = 8 -Found 1 tuple: -[8, 'the tuple #8'] -select * from t0 where k0 = 9 -Found 1 tuple: -[9, 'the tuple #9'] - -# -# Try to insert into slave. -# - -insert into t0 values (100, 'the tuple #100') -An error occurred: ER_NONMASTER, 'Non master connection, but it should be�' - -# -# Propagate slave to master. -# - -reload configuration ---- -ok -... - -# -# Try to insert into slave after it was propagated to master. -# - -insert into t0 values (100, 'the tuple #100') -Insert OK, 1 row affected -select * from t0 where k0 = 100 -Found 1 tuple: -[100, 'the tuple #100'] - -# -# Try to propagate beholder to slave. -# - -reload configuration ---- -fail: - - Could not propagate master to slave before local recovery finished -... - -# -# Propagate master to slave. -# - -reload configuration ---- -ok -... -select * from t0 where k0 = 100 -Found 1 tuple: -[100, 'the tuple #100'] diff --git a/test/box_replication/common.test b/test/box_replication/common.test deleted file mode 100644 index 461d04edcd533a13d16b1f1c49d7abb46b4df3ba..0000000000000000000000000000000000000000 --- a/test/box_replication/common.test +++ /dev/null @@ -1,139 +0,0 @@ -import os -from lib.tarantool_box_server import TarantoolBoxServer -from lib.tarantool_feeder_server import TarantoolFeederServer - -master = server - -# Startup master beholder. -beholder = TarantoolBoxServer() -beholder.deploy("box_replication/tarantool_beholder.cfg", - beholder.find_exe(self.args.builddir), - os.path.join(self.args.vardir, "beholder")) - -# Startup master feeder. -feeder = TarantoolFeederServer() -feeder.deploy("box_replication/feeder.cfg", - feeder.find_exe(self.args.builddir), - os.path.join(self.args.vardir, "feeder")) - -# Startup secondary master feeder. -secondary_feeder = TarantoolFeederServer() -secondary_feeder.deploy("box_replication/feeder_secondary.cfg", - secondary_feeder.find_exe(self.args.builddir), - os.path.join(self.args.vardir, "feeder_secondary")) - -# Startup replication server. -slave = TarantoolBoxServer() -slave.deploy("box_replication/tarantool_slave.cfg", - slave.find_exe(self.args.builddir), - os.path.join(self.args.vardir, "slave")) -# Startup replication feeder. -slave_feeder = TarantoolFeederServer() -slave_feeder.deploy("box_replication/feeder_slave.cfg", - slave_feeder.find_exe(self.args.builddir), - os.path.join(self.args.vardir, "slave/feeder")) - -print """ -# -# Insert several tuples. -# -""" -for i in range(1, 5): - master.sql.execute("insert into t0 values ({0}, 'the tuple #{0}')".format(i), - silent=False) - -slave.wait_lsn(5) - -print """ -# -# Reconfigure slave to replicate from secondary feeder. -# -""" -slave.reconfigure("box_replication/tarantool_slave_secondary_feeder_replication.cfg") -feeder.stop() -feeder.cleanup(True) - -print """ -# -# Insert more tuples. -# -""" -for i in range(5, 10): - master.sql.execute("insert into t0 values ({0}, 'the tuple #{0}')".format(i), - silent=False) - -print """ -# -# Select from master. -# -""" -for i in range(1, 10): - master.sql.execute("select * from t0 where k0 = {0}".format(i), - silent=False) - -slave.wait_lsn(10) - -print """ -# -# Select from slave. -# -""" -for i in range(1,10): - slave.sql.execute("select * from t0 where k0 = {0}".format(i), - silent=False) - -print """ -# -# Try to insert into slave. -# -""" -slave.sql.execute("insert into t0 values (100, 'the tuple #100')", - silent=False) - -print """ -# -# Propagate slave to master. -# -""" -slave.reconfigure("box_replication/tarantool_slave_to_master.cfg") - -print """ -# -# Try to insert into slave after it was propagated to master. -# -""" -slave.sql.execute("insert into t0 values (100, 'the tuple #100')", - silent=False) -slave.sql.execute("select * from t0 where k0 = 100", - silent=False) - -print """ -# -# Try to propagate beholder to slave. -# -""" -beholder.reconfigure("box_replication/tarantool_beholder_to_slave.cfg") - -print """ -# -# Propagate master to slave. -# -""" -master.reconfigure("box_replication/tarantool_to_slave.cfg") -master.wait_lsn(11) -master.sql.execute("select * from t0 where k0 = 100", - silent=False) - -# Cleanup. -beholder.stop() -beholder.cleanup(True) -secondary_feeder.stop() -secondary_feeder.cleanup(True) -slave_feeder.stop() -slave_feeder.cleanup(True) -slave.stop() -slave.cleanup(True) -server.stop() -server.deploy(self.suite_ini["config"]) - -# vim: syntax=python diff --git a/test/box_replication/consistent.result b/test/box_replication/consistent.result new file mode 100644 index 0000000000000000000000000000000000000000..ae17a90459000c646fd6601b532a320e5eeb1b8a --- /dev/null +++ b/test/box_replication/consistent.result @@ -0,0 +1,685 @@ +insert to master [0, 10) entries +insert into t0 values (0, 'mater 0') +Insert OK, 1 row affected +insert into t0 values (1, 'mater 1') +Insert OK, 1 row affected +insert into t0 values (2, 'mater 2') +Insert OK, 1 row affected +insert into t0 values (3, 'mater 3') +Insert OK, 1 row affected +insert into t0 values (4, 'mater 4') +Insert OK, 1 row affected +insert into t0 values (5, 'mater 5') +Insert OK, 1 row affected +insert into t0 values (6, 'mater 6') +Insert OK, 1 row affected +insert into t0 values (7, 'mater 7') +Insert OK, 1 row affected +insert into t0 values (8, 'mater 8') +Insert OK, 1 row affected +insert into t0 values (9, 'mater 9') +Insert OK, 1 row affected +select from replica [0, 10) entries +select * from t0 where k0 = 0 +Found 1 tuple: +[0, 'mater 0'] +select * from t0 where k0 = 1 +Found 1 tuple: +[1, 'mater 1'] +select * from t0 where k0 = 2 +Found 1 tuple: +[2, 'mater 2'] +select * from t0 where k0 = 3 +Found 1 tuple: +[3, 'mater 3'] +select * from t0 where k0 = 4 +Found 1 tuple: +[4, 'mater 4'] +select * from t0 where k0 = 5 +Found 1 tuple: +[5, 'mater 5'] +select * from t0 where k0 = 6 +Found 1 tuple: +[6, 'mater 6'] +select * from t0 where k0 = 7 +Found 1 tuple: +[7, 'mater 7'] +select * from t0 where k0 = 8 +Found 1 tuple: +[8, 'mater 8'] +select * from t0 where k0 = 9 +Found 1 tuple: +[9, 'mater 9'] +master lsn = 11 +replica lsn = 11 + +# +# mater lsn > replica lsn +# + + +# reconfigure replica to master + +reload configuration +--- +ok +... +insert to master [10, 20) entries +insert into t0 values (10, 'mater 10') +Insert OK, 1 row affected +insert into t0 values (11, 'mater 11') +Insert OK, 1 row affected +insert into t0 values (12, 'mater 12') +Insert OK, 1 row affected +insert into t0 values (13, 'mater 13') +Insert OK, 1 row affected +insert into t0 values (14, 'mater 14') +Insert OK, 1 row affected +insert into t0 values (15, 'mater 15') +Insert OK, 1 row affected +insert into t0 values (16, 'mater 16') +Insert OK, 1 row affected +insert into t0 values (17, 'mater 17') +Insert OK, 1 row affected +insert into t0 values (18, 'mater 18') +Insert OK, 1 row affected +insert into t0 values (19, 'mater 19') +Insert OK, 1 row affected +select from master [10, 20) entries +select * from t0 where k0 = 10 +Found 1 tuple: +[10, 'mater 10'] +select * from t0 where k0 = 11 +Found 1 tuple: +[11, 'mater 11'] +select * from t0 where k0 = 12 +Found 1 tuple: +[12, 'mater 12'] +select * from t0 where k0 = 13 +Found 1 tuple: +[13, 'mater 13'] +select * from t0 where k0 = 14 +Found 1 tuple: +[14, 'mater 14'] +select * from t0 where k0 = 15 +Found 1 tuple: +[15, 'mater 15'] +select * from t0 where k0 = 16 +Found 1 tuple: +[16, 'mater 16'] +select * from t0 where k0 = 17 +Found 1 tuple: +[17, 'mater 17'] +select * from t0 where k0 = 18 +Found 1 tuple: +[18, 'mater 18'] +select * from t0 where k0 = 19 +Found 1 tuple: +[19, 'mater 19'] +insert to replica [10, 15) entries +insert into t0 values (10, 'replica 10') +Insert OK, 1 row affected +insert into t0 values (11, 'replica 11') +Insert OK, 1 row affected +insert into t0 values (12, 'replica 12') +Insert OK, 1 row affected +insert into t0 values (13, 'replica 13') +Insert OK, 1 row affected +insert into t0 values (14, 'replica 14') +Insert OK, 1 row affected +select from replica [10, 15) entries +select * from t0 where k0 = 10 +Found 1 tuple: +[10, 'replica 10'] +select * from t0 where k0 = 11 +Found 1 tuple: +[11, 'replica 11'] +select * from t0 where k0 = 12 +Found 1 tuple: +[12, 'replica 12'] +select * from t0 where k0 = 13 +Found 1 tuple: +[13, 'replica 13'] +select * from t0 where k0 = 14 +Found 1 tuple: +[14, 'replica 14'] +master lsn = 21 +replica lsn = 16 + +# rollback replica + +reload configuration +--- +ok +... +select from replica [10, 20) entries +select * from t0 where k0 = 10 +Found 1 tuple: +[10, 'replica 10'] +select * from t0 where k0 = 11 +Found 1 tuple: +[11, 'replica 11'] +select * from t0 where k0 = 12 +Found 1 tuple: +[12, 'replica 12'] +select * from t0 where k0 = 13 +Found 1 tuple: +[13, 'replica 13'] +select * from t0 where k0 = 14 +Found 1 tuple: +[14, 'replica 14'] +select * from t0 where k0 = 15 +Found 1 tuple: +[15, 'mater 15'] +select * from t0 where k0 = 16 +Found 1 tuple: +[16, 'mater 16'] +select * from t0 where k0 = 17 +Found 1 tuple: +[17, 'mater 17'] +select * from t0 where k0 = 18 +Found 1 tuple: +[18, 'mater 18'] +select * from t0 where k0 = 19 +Found 1 tuple: +[19, 'mater 19'] +master lsn = 21 +replica lsn = 21 + +# +# master lsn == replica lsn +# + + +# reconfigure replica to master + +reload configuration +--- +ok +... +insert to master [20, 30) entries +insert into t0 values (20, 'mater 20') +Insert OK, 1 row affected +insert into t0 values (21, 'mater 21') +Insert OK, 1 row affected +insert into t0 values (22, 'mater 22') +Insert OK, 1 row affected +insert into t0 values (23, 'mater 23') +Insert OK, 1 row affected +insert into t0 values (24, 'mater 24') +Insert OK, 1 row affected +insert into t0 values (25, 'mater 25') +Insert OK, 1 row affected +insert into t0 values (26, 'mater 26') +Insert OK, 1 row affected +insert into t0 values (27, 'mater 27') +Insert OK, 1 row affected +insert into t0 values (28, 'mater 28') +Insert OK, 1 row affected +insert into t0 values (29, 'mater 29') +Insert OK, 1 row affected +select from master [20, 30) entries +select * from t0 where k0 = 20 +Found 1 tuple: +[20, 'mater 20'] +select * from t0 where k0 = 21 +Found 1 tuple: +[21, 'mater 21'] +select * from t0 where k0 = 22 +Found 1 tuple: +[22, 'mater 22'] +select * from t0 where k0 = 23 +Found 1 tuple: +[23, 'mater 23'] +select * from t0 where k0 = 24 +Found 1 tuple: +[24, 'mater 24'] +select * from t0 where k0 = 25 +Found 1 tuple: +[25, 'mater 25'] +select * from t0 where k0 = 26 +Found 1 tuple: +[26, 'mater 26'] +select * from t0 where k0 = 27 +Found 1 tuple: +[27, 'mater 27'] +select * from t0 where k0 = 28 +Found 1 tuple: +[28, 'mater 28'] +select * from t0 where k0 = 29 +Found 1 tuple: +[29, 'mater 29'] +insert to replica [20, 30) entries +insert into t0 values (20, 'replica 20') +Insert OK, 1 row affected +insert into t0 values (21, 'replica 21') +Insert OK, 1 row affected +insert into t0 values (22, 'replica 22') +Insert OK, 1 row affected +insert into t0 values (23, 'replica 23') +Insert OK, 1 row affected +insert into t0 values (24, 'replica 24') +Insert OK, 1 row affected +insert into t0 values (25, 'replica 25') +Insert OK, 1 row affected +insert into t0 values (26, 'replica 26') +Insert OK, 1 row affected +insert into t0 values (27, 'replica 27') +Insert OK, 1 row affected +insert into t0 values (28, 'replica 28') +Insert OK, 1 row affected +insert into t0 values (29, 'replica 29') +Insert OK, 1 row affected +select from replica [20, 30) entries +select * from t0 where k0 = 20 +Found 1 tuple: +[20, 'replica 20'] +select * from t0 where k0 = 21 +Found 1 tuple: +[21, 'replica 21'] +select * from t0 where k0 = 22 +Found 1 tuple: +[22, 'replica 22'] +select * from t0 where k0 = 23 +Found 1 tuple: +[23, 'replica 23'] +select * from t0 where k0 = 24 +Found 1 tuple: +[24, 'replica 24'] +select * from t0 where k0 = 25 +Found 1 tuple: +[25, 'replica 25'] +select * from t0 where k0 = 26 +Found 1 tuple: +[26, 'replica 26'] +select * from t0 where k0 = 27 +Found 1 tuple: +[27, 'replica 27'] +select * from t0 where k0 = 28 +Found 1 tuple: +[28, 'replica 28'] +select * from t0 where k0 = 29 +Found 1 tuple: +[29, 'replica 29'] +master lsn = 31 +replica lsn = 31 + +# rollback replica + +reload configuration +--- +ok +... +select from replica [20, 30) entries +select * from t0 where k0 = 20 +Found 1 tuple: +[20, 'replica 20'] +select * from t0 where k0 = 21 +Found 1 tuple: +[21, 'replica 21'] +select * from t0 where k0 = 22 +Found 1 tuple: +[22, 'replica 22'] +select * from t0 where k0 = 23 +Found 1 tuple: +[23, 'replica 23'] +select * from t0 where k0 = 24 +Found 1 tuple: +[24, 'replica 24'] +select * from t0 where k0 = 25 +Found 1 tuple: +[25, 'replica 25'] +select * from t0 where k0 = 26 +Found 1 tuple: +[26, 'replica 26'] +select * from t0 where k0 = 27 +Found 1 tuple: +[27, 'replica 27'] +select * from t0 where k0 = 28 +Found 1 tuple: +[28, 'replica 28'] +select * from t0 where k0 = 29 +Found 1 tuple: +[29, 'replica 29'] +master lsn = 31 +replica lsn = 31 + +# +# mater lsn < replica lsn +# + + +#reconfigure replica to master + +reload configuration +--- +ok +... +insert to master [30, 40) entries +insert into t0 values (30, 'mater 30') +Insert OK, 1 row affected +insert into t0 values (31, 'mater 31') +Insert OK, 1 row affected +insert into t0 values (32, 'mater 32') +Insert OK, 1 row affected +insert into t0 values (33, 'mater 33') +Insert OK, 1 row affected +insert into t0 values (34, 'mater 34') +Insert OK, 1 row affected +insert into t0 values (35, 'mater 35') +Insert OK, 1 row affected +insert into t0 values (36, 'mater 36') +Insert OK, 1 row affected +insert into t0 values (37, 'mater 37') +Insert OK, 1 row affected +insert into t0 values (38, 'mater 38') +Insert OK, 1 row affected +insert into t0 values (39, 'mater 39') +Insert OK, 1 row affected +select from master [30, 40) entries +select * from t0 where k0 = 30 +Found 1 tuple: +[30, 'mater 30'] +select * from t0 where k0 = 31 +Found 1 tuple: +[31, 'mater 31'] +select * from t0 where k0 = 32 +Found 1 tuple: +[32, 'mater 32'] +select * from t0 where k0 = 33 +Found 1 tuple: +[33, 'mater 33'] +select * from t0 where k0 = 34 +Found 1 tuple: +[34, 'mater 34'] +select * from t0 where k0 = 35 +Found 1 tuple: +[35, 'mater 35'] +select * from t0 where k0 = 36 +Found 1 tuple: +[36, 'mater 36'] +select * from t0 where k0 = 37 +Found 1 tuple: +[37, 'mater 37'] +select * from t0 where k0 = 38 +Found 1 tuple: +[38, 'mater 38'] +select * from t0 where k0 = 39 +Found 1 tuple: +[39, 'mater 39'] +insert to replica [30, 50) entries +insert into t0 values (30, 'replica 30') +Insert OK, 1 row affected +insert into t0 values (31, 'replica 31') +Insert OK, 1 row affected +insert into t0 values (32, 'replica 32') +Insert OK, 1 row affected +insert into t0 values (33, 'replica 33') +Insert OK, 1 row affected +insert into t0 values (34, 'replica 34') +Insert OK, 1 row affected +insert into t0 values (35, 'replica 35') +Insert OK, 1 row affected +insert into t0 values (36, 'replica 36') +Insert OK, 1 row affected +insert into t0 values (37, 'replica 37') +Insert OK, 1 row affected +insert into t0 values (38, 'replica 38') +Insert OK, 1 row affected +insert into t0 values (39, 'replica 39') +Insert OK, 1 row affected +insert into t0 values (40, 'replica 40') +Insert OK, 1 row affected +insert into t0 values (41, 'replica 41') +Insert OK, 1 row affected +insert into t0 values (42, 'replica 42') +Insert OK, 1 row affected +insert into t0 values (43, 'replica 43') +Insert OK, 1 row affected +insert into t0 values (44, 'replica 44') +Insert OK, 1 row affected +insert into t0 values (45, 'replica 45') +Insert OK, 1 row affected +insert into t0 values (46, 'replica 46') +Insert OK, 1 row affected +insert into t0 values (47, 'replica 47') +Insert OK, 1 row affected +insert into t0 values (48, 'replica 48') +Insert OK, 1 row affected +insert into t0 values (49, 'replica 49') +Insert OK, 1 row affected +select from replica [30, 50) entries +select * from t0 where k0 = 30 +Found 1 tuple: +[30, 'replica 30'] +select * from t0 where k0 = 31 +Found 1 tuple: +[31, 'replica 31'] +select * from t0 where k0 = 32 +Found 1 tuple: +[32, 'replica 32'] +select * from t0 where k0 = 33 +Found 1 tuple: +[33, 'replica 33'] +select * from t0 where k0 = 34 +Found 1 tuple: +[34, 'replica 34'] +select * from t0 where k0 = 35 +Found 1 tuple: +[35, 'replica 35'] +select * from t0 where k0 = 36 +Found 1 tuple: +[36, 'replica 36'] +select * from t0 where k0 = 37 +Found 1 tuple: +[37, 'replica 37'] +select * from t0 where k0 = 38 +Found 1 tuple: +[38, 'replica 38'] +select * from t0 where k0 = 39 +Found 1 tuple: +[39, 'replica 39'] +select * from t0 where k0 = 40 +Found 1 tuple: +[40, 'replica 40'] +select * from t0 where k0 = 41 +Found 1 tuple: +[41, 'replica 41'] +select * from t0 where k0 = 42 +Found 1 tuple: +[42, 'replica 42'] +select * from t0 where k0 = 43 +Found 1 tuple: +[43, 'replica 43'] +select * from t0 where k0 = 44 +Found 1 tuple: +[44, 'replica 44'] +select * from t0 where k0 = 45 +Found 1 tuple: +[45, 'replica 45'] +select * from t0 where k0 = 46 +Found 1 tuple: +[46, 'replica 46'] +select * from t0 where k0 = 47 +Found 1 tuple: +[47, 'replica 47'] +select * from t0 where k0 = 48 +Found 1 tuple: +[48, 'replica 48'] +select * from t0 where k0 = 49 +Found 1 tuple: +[49, 'replica 49'] +master lsn = 41 +replica lsn = 51 + +# rollback replica + +reload configuration +--- +ok +... +select from replica [30, 50) entries +select * from t0 where k0 = 30 +Found 1 tuple: +[30, 'replica 30'] +select * from t0 where k0 = 31 +Found 1 tuple: +[31, 'replica 31'] +select * from t0 where k0 = 32 +Found 1 tuple: +[32, 'replica 32'] +select * from t0 where k0 = 33 +Found 1 tuple: +[33, 'replica 33'] +select * from t0 where k0 = 34 +Found 1 tuple: +[34, 'replica 34'] +select * from t0 where k0 = 35 +Found 1 tuple: +[35, 'replica 35'] +select * from t0 where k0 = 36 +Found 1 tuple: +[36, 'replica 36'] +select * from t0 where k0 = 37 +Found 1 tuple: +[37, 'replica 37'] +select * from t0 where k0 = 38 +Found 1 tuple: +[38, 'replica 38'] +select * from t0 where k0 = 39 +Found 1 tuple: +[39, 'replica 39'] +select * from t0 where k0 = 40 +Found 1 tuple: +[40, 'replica 40'] +select * from t0 where k0 = 41 +Found 1 tuple: +[41, 'replica 41'] +select * from t0 where k0 = 42 +Found 1 tuple: +[42, 'replica 42'] +select * from t0 where k0 = 43 +Found 1 tuple: +[43, 'replica 43'] +select * from t0 where k0 = 44 +Found 1 tuple: +[44, 'replica 44'] +select * from t0 where k0 = 45 +Found 1 tuple: +[45, 'replica 45'] +select * from t0 where k0 = 46 +Found 1 tuple: +[46, 'replica 46'] +select * from t0 where k0 = 47 +Found 1 tuple: +[47, 'replica 47'] +select * from t0 where k0 = 48 +Found 1 tuple: +[48, 'replica 48'] +select * from t0 where k0 = 49 +Found 1 tuple: +[49, 'replica 49'] +insert to master [40, 60) entries +insert into t0 values (40, 'master 40') +Insert OK, 1 row affected +insert into t0 values (41, 'master 41') +Insert OK, 1 row affected +insert into t0 values (42, 'master 42') +Insert OK, 1 row affected +insert into t0 values (43, 'master 43') +Insert OK, 1 row affected +insert into t0 values (44, 'master 44') +Insert OK, 1 row affected +insert into t0 values (45, 'master 45') +Insert OK, 1 row affected +insert into t0 values (46, 'master 46') +Insert OK, 1 row affected +insert into t0 values (47, 'master 47') +Insert OK, 1 row affected +insert into t0 values (48, 'master 48') +Insert OK, 1 row affected +insert into t0 values (49, 'master 49') +Insert OK, 1 row affected +insert into t0 values (50, 'master 50') +Insert OK, 1 row affected +insert into t0 values (51, 'master 51') +Insert OK, 1 row affected +insert into t0 values (52, 'master 52') +Insert OK, 1 row affected +insert into t0 values (53, 'master 53') +Insert OK, 1 row affected +insert into t0 values (54, 'master 54') +Insert OK, 1 row affected +insert into t0 values (55, 'master 55') +Insert OK, 1 row affected +insert into t0 values (56, 'master 56') +Insert OK, 1 row affected +insert into t0 values (57, 'master 57') +Insert OK, 1 row affected +insert into t0 values (58, 'master 58') +Insert OK, 1 row affected +insert into t0 values (59, 'master 59') +Insert OK, 1 row affected +select from replica [40, 60) entries +select * from t0 where k0 = 40 +Found 1 tuple: +[40, 'replica 40'] +select * from t0 where k0 = 41 +Found 1 tuple: +[41, 'replica 41'] +select * from t0 where k0 = 42 +Found 1 tuple: +[42, 'replica 42'] +select * from t0 where k0 = 43 +Found 1 tuple: +[43, 'replica 43'] +select * from t0 where k0 = 44 +Found 1 tuple: +[44, 'replica 44'] +select * from t0 where k0 = 45 +Found 1 tuple: +[45, 'replica 45'] +select * from t0 where k0 = 46 +Found 1 tuple: +[46, 'replica 46'] +select * from t0 where k0 = 47 +Found 1 tuple: +[47, 'replica 47'] +select * from t0 where k0 = 48 +Found 1 tuple: +[48, 'replica 48'] +select * from t0 where k0 = 49 +Found 1 tuple: +[49, 'replica 49'] +select * from t0 where k0 = 50 +Found 1 tuple: +[50, 'master 50'] +select * from t0 where k0 = 51 +Found 1 tuple: +[51, 'master 51'] +select * from t0 where k0 = 52 +Found 1 tuple: +[52, 'master 52'] +select * from t0 where k0 = 53 +Found 1 tuple: +[53, 'master 53'] +select * from t0 where k0 = 54 +Found 1 tuple: +[54, 'master 54'] +select * from t0 where k0 = 55 +Found 1 tuple: +[55, 'master 55'] +select * from t0 where k0 = 56 +Found 1 tuple: +[56, 'master 56'] +select * from t0 where k0 = 57 +Found 1 tuple: +[57, 'master 57'] +select * from t0 where k0 = 58 +Found 1 tuple: +[58, 'master 58'] +select * from t0 where k0 = 59 +Found 1 tuple: +[59, 'master 59'] +master lsn = 61 +replica lsn = 61 diff --git a/test/box_replication/consistent.test b/test/box_replication/consistent.test new file mode 100644 index 0000000000000000000000000000000000000000..16ab112aeb55f3eccd80f35d182791b774056758 --- /dev/null +++ b/test/box_replication/consistent.test @@ -0,0 +1,162 @@ +# encoding: tarantool +import os +import time +from lib.tarantool_box_server import TarantoolBoxServer + +ID_BEGIN = 0 +ID_STEP = 10 + +def insert_tuples(server, begin, end, msg = "tuple"): + for i in range(begin, end): + server.sql.execute("insert into t0 values (%d, '%s %d')" % (i, msg, i), silent=False) + +def select_tuples(server, begin, end): + # the last lsn is end id + 1 + server.wait_lsn(end + 1) + for i in range(begin, end): + server.sql.execute("select * from t0 where k0 = %d" % i, silent=False) + +# master server +master = server + +# replica server +replica = TarantoolBoxServer() +replica.deploy("box_replication/cfg/replica.cfg", + replica.find_exe(self.args.builddir), + os.path.join(self.args.vardir, "replica")) + +# Id counter +id = 0 + + +print "insert to master [%d, %d) entries" % (id, id + ID_STEP) +insert_tuples(master, id, id + ID_STEP, "mater") + +print "select from replica [%d, %d) entries" % (id, id + ID_STEP) +select_tuples(replica, id, id + ID_STEP) +id += ID_STEP + +print "master lsn = %s" % master.get_param("lsn") +print "replica lsn = %s" % replica.get_param("lsn") + + +print """ +# +# mater lsn > replica lsn +# +""" +print """ +# reconfigure replica to master +""" +replica.reconfigure("box_replication/cfg/replica_to_master.cfg") + +print "insert to master [%d, %d) entries" % (id, id + ID_STEP) +insert_tuples(master, id, id + ID_STEP, "mater") +print "select from master [%d, %d) entries" % (id, id + ID_STEP) +select_tuples(master, id, id + ID_STEP) + +print "insert to replica [%d, %d) entries" % (id, id + (ID_STEP / 2)) +insert_tuples(replica, id, id + (ID_STEP / 2), "replica") +print "select from replica [%d, %d) entries" % (id, id + (ID_STEP / 2)) +select_tuples(replica, id, id + (ID_STEP / 2)) + +print "master lsn = %s" % master.get_param("lsn") +print "replica lsn = %s" % replica.get_param("lsn") + +print """ +# rollback replica +""" +replica.reconfigure("box_replication/cfg/replica.cfg") + +print "select from replica [%d, %d) entries" % (id, id + ID_STEP) +select_tuples(replica, id, id + ID_STEP) +id += ID_STEP + +print "master lsn = %s" % master.get_param("lsn") +print "replica lsn = %s" % replica.get_param("lsn") + + +print """ +# +# master lsn == replica lsn +# +""" +print """ +# reconfigure replica to master +""" +replica.reconfigure("box_replication/cfg/replica_to_master.cfg") + +print "insert to master [%d, %d) entries" % (id, id + ID_STEP) +insert_tuples(master, id, id + ID_STEP, "mater") +print "select from master [%d, %d) entries" % (id, id + ID_STEP) +select_tuples(master, id, id + ID_STEP) + +print "insert to replica [%d, %d) entries" % (id, id + ID_STEP) +insert_tuples(replica, id, id + ID_STEP, "replica") +print "select from replica [%d, %d) entries" % (id, id + ID_STEP) +select_tuples(replica, id, id + ID_STEP) + +print "master lsn = %s" % master.get_param("lsn") +print "replica lsn = %s" % replica.get_param("lsn") + +print """ +# rollback replica +""" +replica.reconfigure("box_replication/cfg/replica.cfg") + +print "select from replica [%d, %d) entries" % (id, id + ID_STEP) +select_tuples(replica, id, id + ID_STEP) +id += ID_STEP + +print "master lsn = %s" % master.get_param("lsn") +print "replica lsn = %s" % replica.get_param("lsn") + + +print """ +# +# mater lsn < replica lsn +# +""" +print """ +#reconfigure replica to master +""" +replica.reconfigure("box_replication/cfg/replica_to_master.cfg") + +print "insert to master [%d, %d) entries" % (id, id + ID_STEP) +insert_tuples(master, id, id + ID_STEP, "mater") +print "select from master [%d, %d) entries" % (id, id + ID_STEP) +select_tuples(master, id, id + ID_STEP) + +print "insert to replica [%d, %d) entries" % (id, id + (ID_STEP * 2)) +insert_tuples(replica, id, id + (ID_STEP * 2), "replica") +print "select from replica [%d, %d) entries" % (id, id + (ID_STEP * 2)) +select_tuples(replica, id, id + (ID_STEP * 2)) + +print "master lsn = %s" % master.get_param("lsn") +print "replica lsn = %s" % replica.get_param("lsn") + +print """ +# rollback replica +""" +replica.reconfigure("box_replication/cfg/replica.cfg") + +print "select from replica [%d, %d) entries" % (id, id + (ID_STEP * 2)) +select_tuples(replica, id, id + (ID_STEP * 2)) +id += ID_STEP + +print "insert to master [%d, %d) entries" % (id, id + (ID_STEP * 2)) +insert_tuples(master, id, id + (ID_STEP * 2), "master") + +print "select from replica [%d, %d) entries" % (id, id + (ID_STEP * 2)) +select_tuples(replica, id, id + (ID_STEP * 2)) + +print "master lsn = %s" % master.get_param("lsn") +print "replica lsn = %s" % replica.get_param("lsn") + +# Cleanup. +replica.stop() +replica.cleanup(True) +server.stop() +server.deploy(self.suite_ini["config"]) + +# vim: syntax=python diff --git a/test/box_replication/feeder.cfg b/test/box_replication/feeder.cfg deleted file mode 100644 index 90b488bca00e8be0418ff4dc7d4a91b091169902..0000000000000000000000000000000000000000 --- a/test/box_replication/feeder.cfg +++ /dev/null @@ -1,8 +0,0 @@ -pid_file = "tarantool.pid" - -logger="tee -a tarantool.log" - -wal_feeder_bind_ipaddr = "127.0.0.1" -wal_feeder_bind_port = 33016 - -wal_feeder_dir = "../" diff --git a/test/box_replication/feeder_secondary.cfg b/test/box_replication/feeder_secondary.cfg deleted file mode 100644 index 83f9c44440203d6146647dcb8dd8b82dcfa4e69d..0000000000000000000000000000000000000000 --- a/test/box_replication/feeder_secondary.cfg +++ /dev/null @@ -1,8 +0,0 @@ -pid_file = "tarantool.pid" - -logger="tee -a tarantool.log" - -wal_feeder_bind_ipaddr = "127.0.0.1" -wal_feeder_bind_port = 33026 - -wal_feeder_dir = "../" diff --git a/test/box_replication/feeder_slave.cfg b/test/box_replication/feeder_slave.cfg deleted file mode 100644 index 39c6e32caa4439c903de2c58d813085d66791768..0000000000000000000000000000000000000000 --- a/test/box_replication/feeder_slave.cfg +++ /dev/null @@ -1,8 +0,0 @@ -pid_file = "tarantool.pid" - -logger="tee -a tarantool.log" - -wal_feeder_bind_ipaddr = "127.0.0.1" -wal_feeder_bind_port = 33116 - -wal_feeder_dir = "../" diff --git a/test/box_replication/hot_standby.result b/test/box_replication/hot_standby.result new file mode 100644 index 0000000000000000000000000000000000000000..9522df29edfa28c7469326482d06d52799b83181 --- /dev/null +++ b/test/box_replication/hot_standby.result @@ -0,0 +1,181 @@ + +# Insert 10 tuples to master + +insert into t0 values (1, 'the tuple 1') +Insert OK, 1 row affected +insert into t0 values (2, 'the tuple 2') +Insert OK, 1 row affected +insert into t0 values (3, 'the tuple 3') +Insert OK, 1 row affected +insert into t0 values (4, 'the tuple 4') +Insert OK, 1 row affected +insert into t0 values (5, 'the tuple 5') +Insert OK, 1 row affected +insert into t0 values (6, 'the tuple 6') +Insert OK, 1 row affected +insert into t0 values (7, 'the tuple 7') +Insert OK, 1 row affected +insert into t0 values (8, 'the tuple 8') +Insert OK, 1 row affected +insert into t0 values (9, 'the tuple 9') +Insert OK, 1 row affected +insert into t0 values (10, 'the tuple 10') +Insert OK, 1 row affected + +# Select 10 tuples from master + +select * from t0 where k0 = 1 +Found 1 tuple: +[1, 'the tuple 1'] +select * from t0 where k0 = 2 +Found 1 tuple: +[2, 'the tuple 2'] +select * from t0 where k0 = 3 +Found 1 tuple: +[3, 'the tuple 3'] +select * from t0 where k0 = 4 +Found 1 tuple: +[4, 'the tuple 4'] +select * from t0 where k0 = 5 +Found 1 tuple: +[5, 'the tuple 5'] +select * from t0 where k0 = 6 +Found 1 tuple: +[6, 'the tuple 6'] +select * from t0 where k0 = 7 +Found 1 tuple: +[7, 'the tuple 7'] +select * from t0 where k0 = 8 +Found 1 tuple: +[8, 'the tuple 8'] +select * from t0 where k0 = 9 +Found 1 tuple: +[9, 'the tuple 9'] +select * from t0 where k0 = 10 +Found 1 tuple: +[10, 'the tuple 10'] + +# Select 10 tuples from replica + +select * from t0 where k0 = 1 +Found 1 tuple: +[1, 'the tuple 1'] +select * from t0 where k0 = 2 +Found 1 tuple: +[2, 'the tuple 2'] +select * from t0 where k0 = 3 +Found 1 tuple: +[3, 'the tuple 3'] +select * from t0 where k0 = 4 +Found 1 tuple: +[4, 'the tuple 4'] +select * from t0 where k0 = 5 +Found 1 tuple: +[5, 'the tuple 5'] +select * from t0 where k0 = 6 +Found 1 tuple: +[6, 'the tuple 6'] +select * from t0 where k0 = 7 +Found 1 tuple: +[7, 'the tuple 7'] +select * from t0 where k0 = 8 +Found 1 tuple: +[8, 'the tuple 8'] +select * from t0 where k0 = 9 +Found 1 tuple: +[9, 'the tuple 9'] +select * from t0 where k0 = 10 +Found 1 tuple: +[10, 'the tuple 10'] + +# Shutdown master server (now the hot_standby must be a primary server) + + +# Insert 10 tuples to hot_standby + +insert into t0 values (11, 'the tuple 11') +Insert OK, 1 row affected +insert into t0 values (12, 'the tuple 12') +Insert OK, 1 row affected +insert into t0 values (13, 'the tuple 13') +Insert OK, 1 row affected +insert into t0 values (14, 'the tuple 14') +Insert OK, 1 row affected +insert into t0 values (15, 'the tuple 15') +Insert OK, 1 row affected +insert into t0 values (16, 'the tuple 16') +Insert OK, 1 row affected +insert into t0 values (17, 'the tuple 17') +Insert OK, 1 row affected +insert into t0 values (18, 'the tuple 18') +Insert OK, 1 row affected +insert into t0 values (19, 'the tuple 19') +Insert OK, 1 row affected +insert into t0 values (20, 'the tuple 20') +Insert OK, 1 row affected + +# Select 10 tuples from hot_standby + +select * from t0 where k0 = 11 +Found 1 tuple: +[11, 'the tuple 11'] +select * from t0 where k0 = 12 +Found 1 tuple: +[12, 'the tuple 12'] +select * from t0 where k0 = 13 +Found 1 tuple: +[13, 'the tuple 13'] +select * from t0 where k0 = 14 +Found 1 tuple: +[14, 'the tuple 14'] +select * from t0 where k0 = 15 +Found 1 tuple: +[15, 'the tuple 15'] +select * from t0 where k0 = 16 +Found 1 tuple: +[16, 'the tuple 16'] +select * from t0 where k0 = 17 +Found 1 tuple: +[17, 'the tuple 17'] +select * from t0 where k0 = 18 +Found 1 tuple: +[18, 'the tuple 18'] +select * from t0 where k0 = 19 +Found 1 tuple: +[19, 'the tuple 19'] +select * from t0 where k0 = 20 +Found 1 tuple: +[20, 'the tuple 20'] + +# Select 10 tuples from replica + +select * from t0 where k0 = 11 +Found 1 tuple: +[11, 'the tuple 11'] +select * from t0 where k0 = 12 +Found 1 tuple: +[12, 'the tuple 12'] +select * from t0 where k0 = 13 +Found 1 tuple: +[13, 'the tuple 13'] +select * from t0 where k0 = 14 +Found 1 tuple: +[14, 'the tuple 14'] +select * from t0 where k0 = 15 +Found 1 tuple: +[15, 'the tuple 15'] +select * from t0 where k0 = 16 +Found 1 tuple: +[16, 'the tuple 16'] +select * from t0 where k0 = 17 +Found 1 tuple: +[17, 'the tuple 17'] +select * from t0 where k0 = 18 +Found 1 tuple: +[18, 'the tuple 18'] +select * from t0 where k0 = 19 +Found 1 tuple: +[19, 'the tuple 19'] +select * from t0 where k0 = 20 +Found 1 tuple: +[20, 'the tuple 20'] diff --git a/test/box_replication/hot_standby.test b/test/box_replication/hot_standby.test new file mode 100644 index 0000000000000000000000000000000000000000..b1053fb5d8ff7e111cabf81b33bbc25140a8fe4f --- /dev/null +++ b/test/box_replication/hot_standby.test @@ -0,0 +1,85 @@ +import os +import time +from lib.tarantool_box_server import TarantoolBoxServer + +# master server +master = server + +# hot standby server +hot_standby = TarantoolBoxServer() +hot_standby.deploy("box_replication/cfg/hot_standby.cfg", + hot_standby.find_exe(self.args.builddir), + os.path.join(self.args.vardir, "hot_standby"), need_init=False) + +# replica server +replica = TarantoolBoxServer() +replica.deploy("box_replication/cfg/replica.cfg", + replica.find_exe(self.args.builddir), + os.path.join(self.args.vardir, "replica")) + +# Begin tuple id +id = 1 + + +print """ +# Insert 10 tuples to master +""" +for i in range(id, id + 10): + master.sql.execute("insert into t0 values (%d, 'the tuple %d')" % (i, i), silent=False) + + +print """ +# Select 10 tuples from master +""" +for i in range(id, id + 10): + master.sql.execute("select * from t0 where k0 = %d" % i, silent=False) + + +print """ +# Select 10 tuples from replica +""" +replica.wait_lsn(11) +for i in range(id, id + 10): + replica.sql.execute("select * from t0 where k0 = %d" % i, silent=False) + + +print """ +# Shutdown master server (now the hot_standby must be a primary server) +""" +server.stop() + +id += 10 + +# White while hot_standby server not bind masters ports +time.sleep(0.2) + +print """ +# Insert 10 tuples to hot_standby +""" +for i in range(id, id + 10): + hot_standby.sql.execute("insert into t0 values (%d, 'the tuple %d')" % (i, i), silent=False) + + +print """ +# Select 10 tuples from hot_standby +""" +for i in range(id, id + 10): + hot_standby.sql.execute("select * from t0 where k0 = %d" % i, silent=False) + + +print """ +# Select 10 tuples from replica +""" +replica.wait_lsn(21) +for i in range(id, id + 10): + replica.sql.execute("select * from t0 where k0 = %d" % i, silent=False) + + +# Cleanup. +hot_standby.stop() +hot_standby.cleanup(True) +replica.stop() +replica.cleanup(True) +server.deploy(self.suite_ini["config"]) + +# vim: syntax=python diff --git a/test/box_replication/suite.ini b/test/box_replication/suite.ini index 830fb400442f24d3681d713b03769b882f0a7ca7..a8c85f387be74c96d7680906e5fab6e6ac934fe8 100644 --- a/test/box_replication/suite.ini +++ b/test/box_replication/suite.ini @@ -1,3 +1,3 @@ [default] description = tarantool/box, replication -config = tarantool.cfg +config = cfg/master.cfg diff --git a/test/box_replication/swap.result b/test/box_replication/swap.result new file mode 100644 index 0000000000000000000000000000000000000000..7ec1f839e09a26132c07fdc9a73ebedb9e3e9086 --- /dev/null +++ b/test/box_replication/swap.result @@ -0,0 +1,2380 @@ +test 0 iteration +insert into t0 values (0, 'tuple 0') +Insert OK, 1 row affected +insert into t0 values (1, 'tuple 1') +Insert OK, 1 row affected +insert into t0 values (2, 'tuple 2') +Insert OK, 1 row affected +insert into t0 values (3, 'tuple 3') +Insert OK, 1 row affected +insert into t0 values (4, 'tuple 4') +Insert OK, 1 row affected +select * from t0 where k0 = 0 +Found 1 tuple: +[0, 'tuple 0'] +select * from t0 where k0 = 1 +Found 1 tuple: +[1, 'tuple 1'] +select * from t0 where k0 = 2 +Found 1 tuple: +[2, 'tuple 2'] +select * from t0 where k0 = 3 +Found 1 tuple: +[3, 'tuple 3'] +select * from t0 where k0 = 4 +Found 1 tuple: +[4, 'tuple 4'] +insert into t0 values (5, 'tuple 5') +Insert OK, 1 row affected +insert into t0 values (6, 'tuple 6') +Insert OK, 1 row affected +insert into t0 values (7, 'tuple 7') +Insert OK, 1 row affected +insert into t0 values (8, 'tuple 8') +Insert OK, 1 row affected +insert into t0 values (9, 'tuple 9') +Insert OK, 1 row affected +select * from t0 where k0 = 5 +Found 1 tuple: +[5, 'tuple 5'] +select * from t0 where k0 = 6 +Found 1 tuple: +[6, 'tuple 6'] +select * from t0 where k0 = 7 +Found 1 tuple: +[7, 'tuple 7'] +select * from t0 where k0 = 8 +Found 1 tuple: +[8, 'tuple 8'] +select * from t0 where k0 = 9 +Found 1 tuple: +[9, 'tuple 9'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (10, 'tuple 10') +Insert OK, 1 row affected +insert into t0 values (11, 'tuple 11') +Insert OK, 1 row affected +insert into t0 values (12, 'tuple 12') +Insert OK, 1 row affected +insert into t0 values (13, 'tuple 13') +Insert OK, 1 row affected +insert into t0 values (14, 'tuple 14') +Insert OK, 1 row affected +select * from t0 where k0 = 10 +Found 1 tuple: +[10, 'tuple 10'] +select * from t0 where k0 = 11 +Found 1 tuple: +[11, 'tuple 11'] +select * from t0 where k0 = 12 +Found 1 tuple: +[12, 'tuple 12'] +select * from t0 where k0 = 13 +Found 1 tuple: +[13, 'tuple 13'] +select * from t0 where k0 = 14 +Found 1 tuple: +[14, 'tuple 14'] +insert into t0 values (15, 'tuple 15') +Insert OK, 1 row affected +insert into t0 values (16, 'tuple 16') +Insert OK, 1 row affected +insert into t0 values (17, 'tuple 17') +Insert OK, 1 row affected +insert into t0 values (18, 'tuple 18') +Insert OK, 1 row affected +insert into t0 values (19, 'tuple 19') +Insert OK, 1 row affected +select * from t0 where k0 = 15 +Found 1 tuple: +[15, 'tuple 15'] +select * from t0 where k0 = 16 +Found 1 tuple: +[16, 'tuple 16'] +select * from t0 where k0 = 17 +Found 1 tuple: +[17, 'tuple 17'] +select * from t0 where k0 = 18 +Found 1 tuple: +[18, 'tuple 18'] +select * from t0 where k0 = 19 +Found 1 tuple: +[19, 'tuple 19'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 1 iteration +insert into t0 values (20, 'tuple 20') +Insert OK, 1 row affected +insert into t0 values (21, 'tuple 21') +Insert OK, 1 row affected +insert into t0 values (22, 'tuple 22') +Insert OK, 1 row affected +insert into t0 values (23, 'tuple 23') +Insert OK, 1 row affected +insert into t0 values (24, 'tuple 24') +Insert OK, 1 row affected +select * from t0 where k0 = 20 +Found 1 tuple: +[20, 'tuple 20'] +select * from t0 where k0 = 21 +Found 1 tuple: +[21, 'tuple 21'] +select * from t0 where k0 = 22 +Found 1 tuple: +[22, 'tuple 22'] +select * from t0 where k0 = 23 +Found 1 tuple: +[23, 'tuple 23'] +select * from t0 where k0 = 24 +Found 1 tuple: +[24, 'tuple 24'] +insert into t0 values (25, 'tuple 25') +Insert OK, 1 row affected +insert into t0 values (26, 'tuple 26') +Insert OK, 1 row affected +insert into t0 values (27, 'tuple 27') +Insert OK, 1 row affected +insert into t0 values (28, 'tuple 28') +Insert OK, 1 row affected +insert into t0 values (29, 'tuple 29') +Insert OK, 1 row affected +select * from t0 where k0 = 25 +Found 1 tuple: +[25, 'tuple 25'] +select * from t0 where k0 = 26 +Found 1 tuple: +[26, 'tuple 26'] +select * from t0 where k0 = 27 +Found 1 tuple: +[27, 'tuple 27'] +select * from t0 where k0 = 28 +Found 1 tuple: +[28, 'tuple 28'] +select * from t0 where k0 = 29 +Found 1 tuple: +[29, 'tuple 29'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (30, 'tuple 30') +Insert OK, 1 row affected +insert into t0 values (31, 'tuple 31') +Insert OK, 1 row affected +insert into t0 values (32, 'tuple 32') +Insert OK, 1 row affected +insert into t0 values (33, 'tuple 33') +Insert OK, 1 row affected +insert into t0 values (34, 'tuple 34') +Insert OK, 1 row affected +select * from t0 where k0 = 30 +Found 1 tuple: +[30, 'tuple 30'] +select * from t0 where k0 = 31 +Found 1 tuple: +[31, 'tuple 31'] +select * from t0 where k0 = 32 +Found 1 tuple: +[32, 'tuple 32'] +select * from t0 where k0 = 33 +Found 1 tuple: +[33, 'tuple 33'] +select * from t0 where k0 = 34 +Found 1 tuple: +[34, 'tuple 34'] +insert into t0 values (35, 'tuple 35') +Insert OK, 1 row affected +insert into t0 values (36, 'tuple 36') +Insert OK, 1 row affected +insert into t0 values (37, 'tuple 37') +Insert OK, 1 row affected +insert into t0 values (38, 'tuple 38') +Insert OK, 1 row affected +insert into t0 values (39, 'tuple 39') +Insert OK, 1 row affected +select * from t0 where k0 = 35 +Found 1 tuple: +[35, 'tuple 35'] +select * from t0 where k0 = 36 +Found 1 tuple: +[36, 'tuple 36'] +select * from t0 where k0 = 37 +Found 1 tuple: +[37, 'tuple 37'] +select * from t0 where k0 = 38 +Found 1 tuple: +[38, 'tuple 38'] +select * from t0 where k0 = 39 +Found 1 tuple: +[39, 'tuple 39'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 2 iteration +insert into t0 values (40, 'tuple 40') +Insert OK, 1 row affected +insert into t0 values (41, 'tuple 41') +Insert OK, 1 row affected +insert into t0 values (42, 'tuple 42') +Insert OK, 1 row affected +insert into t0 values (43, 'tuple 43') +Insert OK, 1 row affected +insert into t0 values (44, 'tuple 44') +Insert OK, 1 row affected +select * from t0 where k0 = 40 +Found 1 tuple: +[40, 'tuple 40'] +select * from t0 where k0 = 41 +Found 1 tuple: +[41, 'tuple 41'] +select * from t0 where k0 = 42 +Found 1 tuple: +[42, 'tuple 42'] +select * from t0 where k0 = 43 +Found 1 tuple: +[43, 'tuple 43'] +select * from t0 where k0 = 44 +Found 1 tuple: +[44, 'tuple 44'] +insert into t0 values (45, 'tuple 45') +Insert OK, 1 row affected +insert into t0 values (46, 'tuple 46') +Insert OK, 1 row affected +insert into t0 values (47, 'tuple 47') +Insert OK, 1 row affected +insert into t0 values (48, 'tuple 48') +Insert OK, 1 row affected +insert into t0 values (49, 'tuple 49') +Insert OK, 1 row affected +select * from t0 where k0 = 45 +Found 1 tuple: +[45, 'tuple 45'] +select * from t0 where k0 = 46 +Found 1 tuple: +[46, 'tuple 46'] +select * from t0 where k0 = 47 +Found 1 tuple: +[47, 'tuple 47'] +select * from t0 where k0 = 48 +Found 1 tuple: +[48, 'tuple 48'] +select * from t0 where k0 = 49 +Found 1 tuple: +[49, 'tuple 49'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (50, 'tuple 50') +Insert OK, 1 row affected +insert into t0 values (51, 'tuple 51') +Insert OK, 1 row affected +insert into t0 values (52, 'tuple 52') +Insert OK, 1 row affected +insert into t0 values (53, 'tuple 53') +Insert OK, 1 row affected +insert into t0 values (54, 'tuple 54') +Insert OK, 1 row affected +select * from t0 where k0 = 50 +Found 1 tuple: +[50, 'tuple 50'] +select * from t0 where k0 = 51 +Found 1 tuple: +[51, 'tuple 51'] +select * from t0 where k0 = 52 +Found 1 tuple: +[52, 'tuple 52'] +select * from t0 where k0 = 53 +Found 1 tuple: +[53, 'tuple 53'] +select * from t0 where k0 = 54 +Found 1 tuple: +[54, 'tuple 54'] +insert into t0 values (55, 'tuple 55') +Insert OK, 1 row affected +insert into t0 values (56, 'tuple 56') +Insert OK, 1 row affected +insert into t0 values (57, 'tuple 57') +Insert OK, 1 row affected +insert into t0 values (58, 'tuple 58') +Insert OK, 1 row affected +insert into t0 values (59, 'tuple 59') +Insert OK, 1 row affected +select * from t0 where k0 = 55 +Found 1 tuple: +[55, 'tuple 55'] +select * from t0 where k0 = 56 +Found 1 tuple: +[56, 'tuple 56'] +select * from t0 where k0 = 57 +Found 1 tuple: +[57, 'tuple 57'] +select * from t0 where k0 = 58 +Found 1 tuple: +[58, 'tuple 58'] +select * from t0 where k0 = 59 +Found 1 tuple: +[59, 'tuple 59'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 3 iteration +insert into t0 values (60, 'tuple 60') +Insert OK, 1 row affected +insert into t0 values (61, 'tuple 61') +Insert OK, 1 row affected +insert into t0 values (62, 'tuple 62') +Insert OK, 1 row affected +insert into t0 values (63, 'tuple 63') +Insert OK, 1 row affected +insert into t0 values (64, 'tuple 64') +Insert OK, 1 row affected +select * from t0 where k0 = 60 +Found 1 tuple: +[60, 'tuple 60'] +select * from t0 where k0 = 61 +Found 1 tuple: +[61, 'tuple 61'] +select * from t0 where k0 = 62 +Found 1 tuple: +[62, 'tuple 62'] +select * from t0 where k0 = 63 +Found 1 tuple: +[63, 'tuple 63'] +select * from t0 where k0 = 64 +Found 1 tuple: +[64, 'tuple 64'] +insert into t0 values (65, 'tuple 65') +Insert OK, 1 row affected +insert into t0 values (66, 'tuple 66') +Insert OK, 1 row affected +insert into t0 values (67, 'tuple 67') +Insert OK, 1 row affected +insert into t0 values (68, 'tuple 68') +Insert OK, 1 row affected +insert into t0 values (69, 'tuple 69') +Insert OK, 1 row affected +select * from t0 where k0 = 65 +Found 1 tuple: +[65, 'tuple 65'] +select * from t0 where k0 = 66 +Found 1 tuple: +[66, 'tuple 66'] +select * from t0 where k0 = 67 +Found 1 tuple: +[67, 'tuple 67'] +select * from t0 where k0 = 68 +Found 1 tuple: +[68, 'tuple 68'] +select * from t0 where k0 = 69 +Found 1 tuple: +[69, 'tuple 69'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (70, 'tuple 70') +Insert OK, 1 row affected +insert into t0 values (71, 'tuple 71') +Insert OK, 1 row affected +insert into t0 values (72, 'tuple 72') +Insert OK, 1 row affected +insert into t0 values (73, 'tuple 73') +Insert OK, 1 row affected +insert into t0 values (74, 'tuple 74') +Insert OK, 1 row affected +select * from t0 where k0 = 70 +Found 1 tuple: +[70, 'tuple 70'] +select * from t0 where k0 = 71 +Found 1 tuple: +[71, 'tuple 71'] +select * from t0 where k0 = 72 +Found 1 tuple: +[72, 'tuple 72'] +select * from t0 where k0 = 73 +Found 1 tuple: +[73, 'tuple 73'] +select * from t0 where k0 = 74 +Found 1 tuple: +[74, 'tuple 74'] +insert into t0 values (75, 'tuple 75') +Insert OK, 1 row affected +insert into t0 values (76, 'tuple 76') +Insert OK, 1 row affected +insert into t0 values (77, 'tuple 77') +Insert OK, 1 row affected +insert into t0 values (78, 'tuple 78') +Insert OK, 1 row affected +insert into t0 values (79, 'tuple 79') +Insert OK, 1 row affected +select * from t0 where k0 = 75 +Found 1 tuple: +[75, 'tuple 75'] +select * from t0 where k0 = 76 +Found 1 tuple: +[76, 'tuple 76'] +select * from t0 where k0 = 77 +Found 1 tuple: +[77, 'tuple 77'] +select * from t0 where k0 = 78 +Found 1 tuple: +[78, 'tuple 78'] +select * from t0 where k0 = 79 +Found 1 tuple: +[79, 'tuple 79'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 4 iteration +insert into t0 values (80, 'tuple 80') +Insert OK, 1 row affected +insert into t0 values (81, 'tuple 81') +Insert OK, 1 row affected +insert into t0 values (82, 'tuple 82') +Insert OK, 1 row affected +insert into t0 values (83, 'tuple 83') +Insert OK, 1 row affected +insert into t0 values (84, 'tuple 84') +Insert OK, 1 row affected +select * from t0 where k0 = 80 +Found 1 tuple: +[80, 'tuple 80'] +select * from t0 where k0 = 81 +Found 1 tuple: +[81, 'tuple 81'] +select * from t0 where k0 = 82 +Found 1 tuple: +[82, 'tuple 82'] +select * from t0 where k0 = 83 +Found 1 tuple: +[83, 'tuple 83'] +select * from t0 where k0 = 84 +Found 1 tuple: +[84, 'tuple 84'] +insert into t0 values (85, 'tuple 85') +Insert OK, 1 row affected +insert into t0 values (86, 'tuple 86') +Insert OK, 1 row affected +insert into t0 values (87, 'tuple 87') +Insert OK, 1 row affected +insert into t0 values (88, 'tuple 88') +Insert OK, 1 row affected +insert into t0 values (89, 'tuple 89') +Insert OK, 1 row affected +select * from t0 where k0 = 85 +Found 1 tuple: +[85, 'tuple 85'] +select * from t0 where k0 = 86 +Found 1 tuple: +[86, 'tuple 86'] +select * from t0 where k0 = 87 +Found 1 tuple: +[87, 'tuple 87'] +select * from t0 where k0 = 88 +Found 1 tuple: +[88, 'tuple 88'] +select * from t0 where k0 = 89 +Found 1 tuple: +[89, 'tuple 89'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (90, 'tuple 90') +Insert OK, 1 row affected +insert into t0 values (91, 'tuple 91') +Insert OK, 1 row affected +insert into t0 values (92, 'tuple 92') +Insert OK, 1 row affected +insert into t0 values (93, 'tuple 93') +Insert OK, 1 row affected +insert into t0 values (94, 'tuple 94') +Insert OK, 1 row affected +select * from t0 where k0 = 90 +Found 1 tuple: +[90, 'tuple 90'] +select * from t0 where k0 = 91 +Found 1 tuple: +[91, 'tuple 91'] +select * from t0 where k0 = 92 +Found 1 tuple: +[92, 'tuple 92'] +select * from t0 where k0 = 93 +Found 1 tuple: +[93, 'tuple 93'] +select * from t0 where k0 = 94 +Found 1 tuple: +[94, 'tuple 94'] +insert into t0 values (95, 'tuple 95') +Insert OK, 1 row affected +insert into t0 values (96, 'tuple 96') +Insert OK, 1 row affected +insert into t0 values (97, 'tuple 97') +Insert OK, 1 row affected +insert into t0 values (98, 'tuple 98') +Insert OK, 1 row affected +insert into t0 values (99, 'tuple 99') +Insert OK, 1 row affected +select * from t0 where k0 = 95 +Found 1 tuple: +[95, 'tuple 95'] +select * from t0 where k0 = 96 +Found 1 tuple: +[96, 'tuple 96'] +select * from t0 where k0 = 97 +Found 1 tuple: +[97, 'tuple 97'] +select * from t0 where k0 = 98 +Found 1 tuple: +[98, 'tuple 98'] +select * from t0 where k0 = 99 +Found 1 tuple: +[99, 'tuple 99'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 5 iteration +insert into t0 values (100, 'tuple 100') +Insert OK, 1 row affected +insert into t0 values (101, 'tuple 101') +Insert OK, 1 row affected +insert into t0 values (102, 'tuple 102') +Insert OK, 1 row affected +insert into t0 values (103, 'tuple 103') +Insert OK, 1 row affected +insert into t0 values (104, 'tuple 104') +Insert OK, 1 row affected +select * from t0 where k0 = 100 +Found 1 tuple: +[100, 'tuple 100'] +select * from t0 where k0 = 101 +Found 1 tuple: +[101, 'tuple 101'] +select * from t0 where k0 = 102 +Found 1 tuple: +[102, 'tuple 102'] +select * from t0 where k0 = 103 +Found 1 tuple: +[103, 'tuple 103'] +select * from t0 where k0 = 104 +Found 1 tuple: +[104, 'tuple 104'] +insert into t0 values (105, 'tuple 105') +Insert OK, 1 row affected +insert into t0 values (106, 'tuple 106') +Insert OK, 1 row affected +insert into t0 values (107, 'tuple 107') +Insert OK, 1 row affected +insert into t0 values (108, 'tuple 108') +Insert OK, 1 row affected +insert into t0 values (109, 'tuple 109') +Insert OK, 1 row affected +select * from t0 where k0 = 105 +Found 1 tuple: +[105, 'tuple 105'] +select * from t0 where k0 = 106 +Found 1 tuple: +[106, 'tuple 106'] +select * from t0 where k0 = 107 +Found 1 tuple: +[107, 'tuple 107'] +select * from t0 where k0 = 108 +Found 1 tuple: +[108, 'tuple 108'] +select * from t0 where k0 = 109 +Found 1 tuple: +[109, 'tuple 109'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (110, 'tuple 110') +Insert OK, 1 row affected +insert into t0 values (111, 'tuple 111') +Insert OK, 1 row affected +insert into t0 values (112, 'tuple 112') +Insert OK, 1 row affected +insert into t0 values (113, 'tuple 113') +Insert OK, 1 row affected +insert into t0 values (114, 'tuple 114') +Insert OK, 1 row affected +select * from t0 where k0 = 110 +Found 1 tuple: +[110, 'tuple 110'] +select * from t0 where k0 = 111 +Found 1 tuple: +[111, 'tuple 111'] +select * from t0 where k0 = 112 +Found 1 tuple: +[112, 'tuple 112'] +select * from t0 where k0 = 113 +Found 1 tuple: +[113, 'tuple 113'] +select * from t0 where k0 = 114 +Found 1 tuple: +[114, 'tuple 114'] +insert into t0 values (115, 'tuple 115') +Insert OK, 1 row affected +insert into t0 values (116, 'tuple 116') +Insert OK, 1 row affected +insert into t0 values (117, 'tuple 117') +Insert OK, 1 row affected +insert into t0 values (118, 'tuple 118') +Insert OK, 1 row affected +insert into t0 values (119, 'tuple 119') +Insert OK, 1 row affected +select * from t0 where k0 = 115 +Found 1 tuple: +[115, 'tuple 115'] +select * from t0 where k0 = 116 +Found 1 tuple: +[116, 'tuple 116'] +select * from t0 where k0 = 117 +Found 1 tuple: +[117, 'tuple 117'] +select * from t0 where k0 = 118 +Found 1 tuple: +[118, 'tuple 118'] +select * from t0 where k0 = 119 +Found 1 tuple: +[119, 'tuple 119'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 6 iteration +insert into t0 values (120, 'tuple 120') +Insert OK, 1 row affected +insert into t0 values (121, 'tuple 121') +Insert OK, 1 row affected +insert into t0 values (122, 'tuple 122') +Insert OK, 1 row affected +insert into t0 values (123, 'tuple 123') +Insert OK, 1 row affected +insert into t0 values (124, 'tuple 124') +Insert OK, 1 row affected +select * from t0 where k0 = 120 +Found 1 tuple: +[120, 'tuple 120'] +select * from t0 where k0 = 121 +Found 1 tuple: +[121, 'tuple 121'] +select * from t0 where k0 = 122 +Found 1 tuple: +[122, 'tuple 122'] +select * from t0 where k0 = 123 +Found 1 tuple: +[123, 'tuple 123'] +select * from t0 where k0 = 124 +Found 1 tuple: +[124, 'tuple 124'] +insert into t0 values (125, 'tuple 125') +Insert OK, 1 row affected +insert into t0 values (126, 'tuple 126') +Insert OK, 1 row affected +insert into t0 values (127, 'tuple 127') +Insert OK, 1 row affected +insert into t0 values (128, 'tuple 128') +Insert OK, 1 row affected +insert into t0 values (129, 'tuple 129') +Insert OK, 1 row affected +select * from t0 where k0 = 125 +Found 1 tuple: +[125, 'tuple 125'] +select * from t0 where k0 = 126 +Found 1 tuple: +[126, 'tuple 126'] +select * from t0 where k0 = 127 +Found 1 tuple: +[127, 'tuple 127'] +select * from t0 where k0 = 128 +Found 1 tuple: +[128, 'tuple 128'] +select * from t0 where k0 = 129 +Found 1 tuple: +[129, 'tuple 129'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (130, 'tuple 130') +Insert OK, 1 row affected +insert into t0 values (131, 'tuple 131') +Insert OK, 1 row affected +insert into t0 values (132, 'tuple 132') +Insert OK, 1 row affected +insert into t0 values (133, 'tuple 133') +Insert OK, 1 row affected +insert into t0 values (134, 'tuple 134') +Insert OK, 1 row affected +select * from t0 where k0 = 130 +Found 1 tuple: +[130, 'tuple 130'] +select * from t0 where k0 = 131 +Found 1 tuple: +[131, 'tuple 131'] +select * from t0 where k0 = 132 +Found 1 tuple: +[132, 'tuple 132'] +select * from t0 where k0 = 133 +Found 1 tuple: +[133, 'tuple 133'] +select * from t0 where k0 = 134 +Found 1 tuple: +[134, 'tuple 134'] +insert into t0 values (135, 'tuple 135') +Insert OK, 1 row affected +insert into t0 values (136, 'tuple 136') +Insert OK, 1 row affected +insert into t0 values (137, 'tuple 137') +Insert OK, 1 row affected +insert into t0 values (138, 'tuple 138') +Insert OK, 1 row affected +insert into t0 values (139, 'tuple 139') +Insert OK, 1 row affected +select * from t0 where k0 = 135 +Found 1 tuple: +[135, 'tuple 135'] +select * from t0 where k0 = 136 +Found 1 tuple: +[136, 'tuple 136'] +select * from t0 where k0 = 137 +Found 1 tuple: +[137, 'tuple 137'] +select * from t0 where k0 = 138 +Found 1 tuple: +[138, 'tuple 138'] +select * from t0 where k0 = 139 +Found 1 tuple: +[139, 'tuple 139'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 7 iteration +insert into t0 values (140, 'tuple 140') +Insert OK, 1 row affected +insert into t0 values (141, 'tuple 141') +Insert OK, 1 row affected +insert into t0 values (142, 'tuple 142') +Insert OK, 1 row affected +insert into t0 values (143, 'tuple 143') +Insert OK, 1 row affected +insert into t0 values (144, 'tuple 144') +Insert OK, 1 row affected +select * from t0 where k0 = 140 +Found 1 tuple: +[140, 'tuple 140'] +select * from t0 where k0 = 141 +Found 1 tuple: +[141, 'tuple 141'] +select * from t0 where k0 = 142 +Found 1 tuple: +[142, 'tuple 142'] +select * from t0 where k0 = 143 +Found 1 tuple: +[143, 'tuple 143'] +select * from t0 where k0 = 144 +Found 1 tuple: +[144, 'tuple 144'] +insert into t0 values (145, 'tuple 145') +Insert OK, 1 row affected +insert into t0 values (146, 'tuple 146') +Insert OK, 1 row affected +insert into t0 values (147, 'tuple 147') +Insert OK, 1 row affected +insert into t0 values (148, 'tuple 148') +Insert OK, 1 row affected +insert into t0 values (149, 'tuple 149') +Insert OK, 1 row affected +select * from t0 where k0 = 145 +Found 1 tuple: +[145, 'tuple 145'] +select * from t0 where k0 = 146 +Found 1 tuple: +[146, 'tuple 146'] +select * from t0 where k0 = 147 +Found 1 tuple: +[147, 'tuple 147'] +select * from t0 where k0 = 148 +Found 1 tuple: +[148, 'tuple 148'] +select * from t0 where k0 = 149 +Found 1 tuple: +[149, 'tuple 149'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (150, 'tuple 150') +Insert OK, 1 row affected +insert into t0 values (151, 'tuple 151') +Insert OK, 1 row affected +insert into t0 values (152, 'tuple 152') +Insert OK, 1 row affected +insert into t0 values (153, 'tuple 153') +Insert OK, 1 row affected +insert into t0 values (154, 'tuple 154') +Insert OK, 1 row affected +select * from t0 where k0 = 150 +Found 1 tuple: +[150, 'tuple 150'] +select * from t0 where k0 = 151 +Found 1 tuple: +[151, 'tuple 151'] +select * from t0 where k0 = 152 +Found 1 tuple: +[152, 'tuple 152'] +select * from t0 where k0 = 153 +Found 1 tuple: +[153, 'tuple 153'] +select * from t0 where k0 = 154 +Found 1 tuple: +[154, 'tuple 154'] +insert into t0 values (155, 'tuple 155') +Insert OK, 1 row affected +insert into t0 values (156, 'tuple 156') +Insert OK, 1 row affected +insert into t0 values (157, 'tuple 157') +Insert OK, 1 row affected +insert into t0 values (158, 'tuple 158') +Insert OK, 1 row affected +insert into t0 values (159, 'tuple 159') +Insert OK, 1 row affected +select * from t0 where k0 = 155 +Found 1 tuple: +[155, 'tuple 155'] +select * from t0 where k0 = 156 +Found 1 tuple: +[156, 'tuple 156'] +select * from t0 where k0 = 157 +Found 1 tuple: +[157, 'tuple 157'] +select * from t0 where k0 = 158 +Found 1 tuple: +[158, 'tuple 158'] +select * from t0 where k0 = 159 +Found 1 tuple: +[159, 'tuple 159'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 8 iteration +insert into t0 values (160, 'tuple 160') +Insert OK, 1 row affected +insert into t0 values (161, 'tuple 161') +Insert OK, 1 row affected +insert into t0 values (162, 'tuple 162') +Insert OK, 1 row affected +insert into t0 values (163, 'tuple 163') +Insert OK, 1 row affected +insert into t0 values (164, 'tuple 164') +Insert OK, 1 row affected +select * from t0 where k0 = 160 +Found 1 tuple: +[160, 'tuple 160'] +select * from t0 where k0 = 161 +Found 1 tuple: +[161, 'tuple 161'] +select * from t0 where k0 = 162 +Found 1 tuple: +[162, 'tuple 162'] +select * from t0 where k0 = 163 +Found 1 tuple: +[163, 'tuple 163'] +select * from t0 where k0 = 164 +Found 1 tuple: +[164, 'tuple 164'] +insert into t0 values (165, 'tuple 165') +Insert OK, 1 row affected +insert into t0 values (166, 'tuple 166') +Insert OK, 1 row affected +insert into t0 values (167, 'tuple 167') +Insert OK, 1 row affected +insert into t0 values (168, 'tuple 168') +Insert OK, 1 row affected +insert into t0 values (169, 'tuple 169') +Insert OK, 1 row affected +select * from t0 where k0 = 165 +Found 1 tuple: +[165, 'tuple 165'] +select * from t0 where k0 = 166 +Found 1 tuple: +[166, 'tuple 166'] +select * from t0 where k0 = 167 +Found 1 tuple: +[167, 'tuple 167'] +select * from t0 where k0 = 168 +Found 1 tuple: +[168, 'tuple 168'] +select * from t0 where k0 = 169 +Found 1 tuple: +[169, 'tuple 169'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (170, 'tuple 170') +Insert OK, 1 row affected +insert into t0 values (171, 'tuple 171') +Insert OK, 1 row affected +insert into t0 values (172, 'tuple 172') +Insert OK, 1 row affected +insert into t0 values (173, 'tuple 173') +Insert OK, 1 row affected +insert into t0 values (174, 'tuple 174') +Insert OK, 1 row affected +select * from t0 where k0 = 170 +Found 1 tuple: +[170, 'tuple 170'] +select * from t0 where k0 = 171 +Found 1 tuple: +[171, 'tuple 171'] +select * from t0 where k0 = 172 +Found 1 tuple: +[172, 'tuple 172'] +select * from t0 where k0 = 173 +Found 1 tuple: +[173, 'tuple 173'] +select * from t0 where k0 = 174 +Found 1 tuple: +[174, 'tuple 174'] +insert into t0 values (175, 'tuple 175') +Insert OK, 1 row affected +insert into t0 values (176, 'tuple 176') +Insert OK, 1 row affected +insert into t0 values (177, 'tuple 177') +Insert OK, 1 row affected +insert into t0 values (178, 'tuple 178') +Insert OK, 1 row affected +insert into t0 values (179, 'tuple 179') +Insert OK, 1 row affected +select * from t0 where k0 = 175 +Found 1 tuple: +[175, 'tuple 175'] +select * from t0 where k0 = 176 +Found 1 tuple: +[176, 'tuple 176'] +select * from t0 where k0 = 177 +Found 1 tuple: +[177, 'tuple 177'] +select * from t0 where k0 = 178 +Found 1 tuple: +[178, 'tuple 178'] +select * from t0 where k0 = 179 +Found 1 tuple: +[179, 'tuple 179'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 9 iteration +insert into t0 values (180, 'tuple 180') +Insert OK, 1 row affected +insert into t0 values (181, 'tuple 181') +Insert OK, 1 row affected +insert into t0 values (182, 'tuple 182') +Insert OK, 1 row affected +insert into t0 values (183, 'tuple 183') +Insert OK, 1 row affected +insert into t0 values (184, 'tuple 184') +Insert OK, 1 row affected +select * from t0 where k0 = 180 +Found 1 tuple: +[180, 'tuple 180'] +select * from t0 where k0 = 181 +Found 1 tuple: +[181, 'tuple 181'] +select * from t0 where k0 = 182 +Found 1 tuple: +[182, 'tuple 182'] +select * from t0 where k0 = 183 +Found 1 tuple: +[183, 'tuple 183'] +select * from t0 where k0 = 184 +Found 1 tuple: +[184, 'tuple 184'] +insert into t0 values (185, 'tuple 185') +Insert OK, 1 row affected +insert into t0 values (186, 'tuple 186') +Insert OK, 1 row affected +insert into t0 values (187, 'tuple 187') +Insert OK, 1 row affected +insert into t0 values (188, 'tuple 188') +Insert OK, 1 row affected +insert into t0 values (189, 'tuple 189') +Insert OK, 1 row affected +select * from t0 where k0 = 185 +Found 1 tuple: +[185, 'tuple 185'] +select * from t0 where k0 = 186 +Found 1 tuple: +[186, 'tuple 186'] +select * from t0 where k0 = 187 +Found 1 tuple: +[187, 'tuple 187'] +select * from t0 where k0 = 188 +Found 1 tuple: +[188, 'tuple 188'] +select * from t0 where k0 = 189 +Found 1 tuple: +[189, 'tuple 189'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (190, 'tuple 190') +Insert OK, 1 row affected +insert into t0 values (191, 'tuple 191') +Insert OK, 1 row affected +insert into t0 values (192, 'tuple 192') +Insert OK, 1 row affected +insert into t0 values (193, 'tuple 193') +Insert OK, 1 row affected +insert into t0 values (194, 'tuple 194') +Insert OK, 1 row affected +select * from t0 where k0 = 190 +Found 1 tuple: +[190, 'tuple 190'] +select * from t0 where k0 = 191 +Found 1 tuple: +[191, 'tuple 191'] +select * from t0 where k0 = 192 +Found 1 tuple: +[192, 'tuple 192'] +select * from t0 where k0 = 193 +Found 1 tuple: +[193, 'tuple 193'] +select * from t0 where k0 = 194 +Found 1 tuple: +[194, 'tuple 194'] +insert into t0 values (195, 'tuple 195') +Insert OK, 1 row affected +insert into t0 values (196, 'tuple 196') +Insert OK, 1 row affected +insert into t0 values (197, 'tuple 197') +Insert OK, 1 row affected +insert into t0 values (198, 'tuple 198') +Insert OK, 1 row affected +insert into t0 values (199, 'tuple 199') +Insert OK, 1 row affected +select * from t0 where k0 = 195 +Found 1 tuple: +[195, 'tuple 195'] +select * from t0 where k0 = 196 +Found 1 tuple: +[196, 'tuple 196'] +select * from t0 where k0 = 197 +Found 1 tuple: +[197, 'tuple 197'] +select * from t0 where k0 = 198 +Found 1 tuple: +[198, 'tuple 198'] +select * from t0 where k0 = 199 +Found 1 tuple: +[199, 'tuple 199'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 10 iteration +insert into t0 values (200, 'tuple 200') +Insert OK, 1 row affected +insert into t0 values (201, 'tuple 201') +Insert OK, 1 row affected +insert into t0 values (202, 'tuple 202') +Insert OK, 1 row affected +insert into t0 values (203, 'tuple 203') +Insert OK, 1 row affected +insert into t0 values (204, 'tuple 204') +Insert OK, 1 row affected +select * from t0 where k0 = 200 +Found 1 tuple: +[200, 'tuple 200'] +select * from t0 where k0 = 201 +Found 1 tuple: +[201, 'tuple 201'] +select * from t0 where k0 = 202 +Found 1 tuple: +[202, 'tuple 202'] +select * from t0 where k0 = 203 +Found 1 tuple: +[203, 'tuple 203'] +select * from t0 where k0 = 204 +Found 1 tuple: +[204, 'tuple 204'] +insert into t0 values (205, 'tuple 205') +Insert OK, 1 row affected +insert into t0 values (206, 'tuple 206') +Insert OK, 1 row affected +insert into t0 values (207, 'tuple 207') +Insert OK, 1 row affected +insert into t0 values (208, 'tuple 208') +Insert OK, 1 row affected +insert into t0 values (209, 'tuple 209') +Insert OK, 1 row affected +select * from t0 where k0 = 205 +Found 1 tuple: +[205, 'tuple 205'] +select * from t0 where k0 = 206 +Found 1 tuple: +[206, 'tuple 206'] +select * from t0 where k0 = 207 +Found 1 tuple: +[207, 'tuple 207'] +select * from t0 where k0 = 208 +Found 1 tuple: +[208, 'tuple 208'] +select * from t0 where k0 = 209 +Found 1 tuple: +[209, 'tuple 209'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (210, 'tuple 210') +Insert OK, 1 row affected +insert into t0 values (211, 'tuple 211') +Insert OK, 1 row affected +insert into t0 values (212, 'tuple 212') +Insert OK, 1 row affected +insert into t0 values (213, 'tuple 213') +Insert OK, 1 row affected +insert into t0 values (214, 'tuple 214') +Insert OK, 1 row affected +select * from t0 where k0 = 210 +Found 1 tuple: +[210, 'tuple 210'] +select * from t0 where k0 = 211 +Found 1 tuple: +[211, 'tuple 211'] +select * from t0 where k0 = 212 +Found 1 tuple: +[212, 'tuple 212'] +select * from t0 where k0 = 213 +Found 1 tuple: +[213, 'tuple 213'] +select * from t0 where k0 = 214 +Found 1 tuple: +[214, 'tuple 214'] +insert into t0 values (215, 'tuple 215') +Insert OK, 1 row affected +insert into t0 values (216, 'tuple 216') +Insert OK, 1 row affected +insert into t0 values (217, 'tuple 217') +Insert OK, 1 row affected +insert into t0 values (218, 'tuple 218') +Insert OK, 1 row affected +insert into t0 values (219, 'tuple 219') +Insert OK, 1 row affected +select * from t0 where k0 = 215 +Found 1 tuple: +[215, 'tuple 215'] +select * from t0 where k0 = 216 +Found 1 tuple: +[216, 'tuple 216'] +select * from t0 where k0 = 217 +Found 1 tuple: +[217, 'tuple 217'] +select * from t0 where k0 = 218 +Found 1 tuple: +[218, 'tuple 218'] +select * from t0 where k0 = 219 +Found 1 tuple: +[219, 'tuple 219'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 11 iteration +insert into t0 values (220, 'tuple 220') +Insert OK, 1 row affected +insert into t0 values (221, 'tuple 221') +Insert OK, 1 row affected +insert into t0 values (222, 'tuple 222') +Insert OK, 1 row affected +insert into t0 values (223, 'tuple 223') +Insert OK, 1 row affected +insert into t0 values (224, 'tuple 224') +Insert OK, 1 row affected +select * from t0 where k0 = 220 +Found 1 tuple: +[220, 'tuple 220'] +select * from t0 where k0 = 221 +Found 1 tuple: +[221, 'tuple 221'] +select * from t0 where k0 = 222 +Found 1 tuple: +[222, 'tuple 222'] +select * from t0 where k0 = 223 +Found 1 tuple: +[223, 'tuple 223'] +select * from t0 where k0 = 224 +Found 1 tuple: +[224, 'tuple 224'] +insert into t0 values (225, 'tuple 225') +Insert OK, 1 row affected +insert into t0 values (226, 'tuple 226') +Insert OK, 1 row affected +insert into t0 values (227, 'tuple 227') +Insert OK, 1 row affected +insert into t0 values (228, 'tuple 228') +Insert OK, 1 row affected +insert into t0 values (229, 'tuple 229') +Insert OK, 1 row affected +select * from t0 where k0 = 225 +Found 1 tuple: +[225, 'tuple 225'] +select * from t0 where k0 = 226 +Found 1 tuple: +[226, 'tuple 226'] +select * from t0 where k0 = 227 +Found 1 tuple: +[227, 'tuple 227'] +select * from t0 where k0 = 228 +Found 1 tuple: +[228, 'tuple 228'] +select * from t0 where k0 = 229 +Found 1 tuple: +[229, 'tuple 229'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (230, 'tuple 230') +Insert OK, 1 row affected +insert into t0 values (231, 'tuple 231') +Insert OK, 1 row affected +insert into t0 values (232, 'tuple 232') +Insert OK, 1 row affected +insert into t0 values (233, 'tuple 233') +Insert OK, 1 row affected +insert into t0 values (234, 'tuple 234') +Insert OK, 1 row affected +select * from t0 where k0 = 230 +Found 1 tuple: +[230, 'tuple 230'] +select * from t0 where k0 = 231 +Found 1 tuple: +[231, 'tuple 231'] +select * from t0 where k0 = 232 +Found 1 tuple: +[232, 'tuple 232'] +select * from t0 where k0 = 233 +Found 1 tuple: +[233, 'tuple 233'] +select * from t0 where k0 = 234 +Found 1 tuple: +[234, 'tuple 234'] +insert into t0 values (235, 'tuple 235') +Insert OK, 1 row affected +insert into t0 values (236, 'tuple 236') +Insert OK, 1 row affected +insert into t0 values (237, 'tuple 237') +Insert OK, 1 row affected +insert into t0 values (238, 'tuple 238') +Insert OK, 1 row affected +insert into t0 values (239, 'tuple 239') +Insert OK, 1 row affected +select * from t0 where k0 = 235 +Found 1 tuple: +[235, 'tuple 235'] +select * from t0 where k0 = 236 +Found 1 tuple: +[236, 'tuple 236'] +select * from t0 where k0 = 237 +Found 1 tuple: +[237, 'tuple 237'] +select * from t0 where k0 = 238 +Found 1 tuple: +[238, 'tuple 238'] +select * from t0 where k0 = 239 +Found 1 tuple: +[239, 'tuple 239'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 12 iteration +insert into t0 values (240, 'tuple 240') +Insert OK, 1 row affected +insert into t0 values (241, 'tuple 241') +Insert OK, 1 row affected +insert into t0 values (242, 'tuple 242') +Insert OK, 1 row affected +insert into t0 values (243, 'tuple 243') +Insert OK, 1 row affected +insert into t0 values (244, 'tuple 244') +Insert OK, 1 row affected +select * from t0 where k0 = 240 +Found 1 tuple: +[240, 'tuple 240'] +select * from t0 where k0 = 241 +Found 1 tuple: +[241, 'tuple 241'] +select * from t0 where k0 = 242 +Found 1 tuple: +[242, 'tuple 242'] +select * from t0 where k0 = 243 +Found 1 tuple: +[243, 'tuple 243'] +select * from t0 where k0 = 244 +Found 1 tuple: +[244, 'tuple 244'] +insert into t0 values (245, 'tuple 245') +Insert OK, 1 row affected +insert into t0 values (246, 'tuple 246') +Insert OK, 1 row affected +insert into t0 values (247, 'tuple 247') +Insert OK, 1 row affected +insert into t0 values (248, 'tuple 248') +Insert OK, 1 row affected +insert into t0 values (249, 'tuple 249') +Insert OK, 1 row affected +select * from t0 where k0 = 245 +Found 1 tuple: +[245, 'tuple 245'] +select * from t0 where k0 = 246 +Found 1 tuple: +[246, 'tuple 246'] +select * from t0 where k0 = 247 +Found 1 tuple: +[247, 'tuple 247'] +select * from t0 where k0 = 248 +Found 1 tuple: +[248, 'tuple 248'] +select * from t0 where k0 = 249 +Found 1 tuple: +[249, 'tuple 249'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (250, 'tuple 250') +Insert OK, 1 row affected +insert into t0 values (251, 'tuple 251') +Insert OK, 1 row affected +insert into t0 values (252, 'tuple 252') +Insert OK, 1 row affected +insert into t0 values (253, 'tuple 253') +Insert OK, 1 row affected +insert into t0 values (254, 'tuple 254') +Insert OK, 1 row affected +select * from t0 where k0 = 250 +Found 1 tuple: +[250, 'tuple 250'] +select * from t0 where k0 = 251 +Found 1 tuple: +[251, 'tuple 251'] +select * from t0 where k0 = 252 +Found 1 tuple: +[252, 'tuple 252'] +select * from t0 where k0 = 253 +Found 1 tuple: +[253, 'tuple 253'] +select * from t0 where k0 = 254 +Found 1 tuple: +[254, 'tuple 254'] +insert into t0 values (255, 'tuple 255') +Insert OK, 1 row affected +insert into t0 values (256, 'tuple 256') +Insert OK, 1 row affected +insert into t0 values (257, 'tuple 257') +Insert OK, 1 row affected +insert into t0 values (258, 'tuple 258') +Insert OK, 1 row affected +insert into t0 values (259, 'tuple 259') +Insert OK, 1 row affected +select * from t0 where k0 = 255 +Found 1 tuple: +[255, 'tuple 255'] +select * from t0 where k0 = 256 +Found 1 tuple: +[256, 'tuple 256'] +select * from t0 where k0 = 257 +Found 1 tuple: +[257, 'tuple 257'] +select * from t0 where k0 = 258 +Found 1 tuple: +[258, 'tuple 258'] +select * from t0 where k0 = 259 +Found 1 tuple: +[259, 'tuple 259'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 13 iteration +insert into t0 values (260, 'tuple 260') +Insert OK, 1 row affected +insert into t0 values (261, 'tuple 261') +Insert OK, 1 row affected +insert into t0 values (262, 'tuple 262') +Insert OK, 1 row affected +insert into t0 values (263, 'tuple 263') +Insert OK, 1 row affected +insert into t0 values (264, 'tuple 264') +Insert OK, 1 row affected +select * from t0 where k0 = 260 +Found 1 tuple: +[260, 'tuple 260'] +select * from t0 where k0 = 261 +Found 1 tuple: +[261, 'tuple 261'] +select * from t0 where k0 = 262 +Found 1 tuple: +[262, 'tuple 262'] +select * from t0 where k0 = 263 +Found 1 tuple: +[263, 'tuple 263'] +select * from t0 where k0 = 264 +Found 1 tuple: +[264, 'tuple 264'] +insert into t0 values (265, 'tuple 265') +Insert OK, 1 row affected +insert into t0 values (266, 'tuple 266') +Insert OK, 1 row affected +insert into t0 values (267, 'tuple 267') +Insert OK, 1 row affected +insert into t0 values (268, 'tuple 268') +Insert OK, 1 row affected +insert into t0 values (269, 'tuple 269') +Insert OK, 1 row affected +select * from t0 where k0 = 265 +Found 1 tuple: +[265, 'tuple 265'] +select * from t0 where k0 = 266 +Found 1 tuple: +[266, 'tuple 266'] +select * from t0 where k0 = 267 +Found 1 tuple: +[267, 'tuple 267'] +select * from t0 where k0 = 268 +Found 1 tuple: +[268, 'tuple 268'] +select * from t0 where k0 = 269 +Found 1 tuple: +[269, 'tuple 269'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (270, 'tuple 270') +Insert OK, 1 row affected +insert into t0 values (271, 'tuple 271') +Insert OK, 1 row affected +insert into t0 values (272, 'tuple 272') +Insert OK, 1 row affected +insert into t0 values (273, 'tuple 273') +Insert OK, 1 row affected +insert into t0 values (274, 'tuple 274') +Insert OK, 1 row affected +select * from t0 where k0 = 270 +Found 1 tuple: +[270, 'tuple 270'] +select * from t0 where k0 = 271 +Found 1 tuple: +[271, 'tuple 271'] +select * from t0 where k0 = 272 +Found 1 tuple: +[272, 'tuple 272'] +select * from t0 where k0 = 273 +Found 1 tuple: +[273, 'tuple 273'] +select * from t0 where k0 = 274 +Found 1 tuple: +[274, 'tuple 274'] +insert into t0 values (275, 'tuple 275') +Insert OK, 1 row affected +insert into t0 values (276, 'tuple 276') +Insert OK, 1 row affected +insert into t0 values (277, 'tuple 277') +Insert OK, 1 row affected +insert into t0 values (278, 'tuple 278') +Insert OK, 1 row affected +insert into t0 values (279, 'tuple 279') +Insert OK, 1 row affected +select * from t0 where k0 = 275 +Found 1 tuple: +[275, 'tuple 275'] +select * from t0 where k0 = 276 +Found 1 tuple: +[276, 'tuple 276'] +select * from t0 where k0 = 277 +Found 1 tuple: +[277, 'tuple 277'] +select * from t0 where k0 = 278 +Found 1 tuple: +[278, 'tuple 278'] +select * from t0 where k0 = 279 +Found 1 tuple: +[279, 'tuple 279'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 14 iteration +insert into t0 values (280, 'tuple 280') +Insert OK, 1 row affected +insert into t0 values (281, 'tuple 281') +Insert OK, 1 row affected +insert into t0 values (282, 'tuple 282') +Insert OK, 1 row affected +insert into t0 values (283, 'tuple 283') +Insert OK, 1 row affected +insert into t0 values (284, 'tuple 284') +Insert OK, 1 row affected +select * from t0 where k0 = 280 +Found 1 tuple: +[280, 'tuple 280'] +select * from t0 where k0 = 281 +Found 1 tuple: +[281, 'tuple 281'] +select * from t0 where k0 = 282 +Found 1 tuple: +[282, 'tuple 282'] +select * from t0 where k0 = 283 +Found 1 tuple: +[283, 'tuple 283'] +select * from t0 where k0 = 284 +Found 1 tuple: +[284, 'tuple 284'] +insert into t0 values (285, 'tuple 285') +Insert OK, 1 row affected +insert into t0 values (286, 'tuple 286') +Insert OK, 1 row affected +insert into t0 values (287, 'tuple 287') +Insert OK, 1 row affected +insert into t0 values (288, 'tuple 288') +Insert OK, 1 row affected +insert into t0 values (289, 'tuple 289') +Insert OK, 1 row affected +select * from t0 where k0 = 285 +Found 1 tuple: +[285, 'tuple 285'] +select * from t0 where k0 = 286 +Found 1 tuple: +[286, 'tuple 286'] +select * from t0 where k0 = 287 +Found 1 tuple: +[287, 'tuple 287'] +select * from t0 where k0 = 288 +Found 1 tuple: +[288, 'tuple 288'] +select * from t0 where k0 = 289 +Found 1 tuple: +[289, 'tuple 289'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (290, 'tuple 290') +Insert OK, 1 row affected +insert into t0 values (291, 'tuple 291') +Insert OK, 1 row affected +insert into t0 values (292, 'tuple 292') +Insert OK, 1 row affected +insert into t0 values (293, 'tuple 293') +Insert OK, 1 row affected +insert into t0 values (294, 'tuple 294') +Insert OK, 1 row affected +select * from t0 where k0 = 290 +Found 1 tuple: +[290, 'tuple 290'] +select * from t0 where k0 = 291 +Found 1 tuple: +[291, 'tuple 291'] +select * from t0 where k0 = 292 +Found 1 tuple: +[292, 'tuple 292'] +select * from t0 where k0 = 293 +Found 1 tuple: +[293, 'tuple 293'] +select * from t0 where k0 = 294 +Found 1 tuple: +[294, 'tuple 294'] +insert into t0 values (295, 'tuple 295') +Insert OK, 1 row affected +insert into t0 values (296, 'tuple 296') +Insert OK, 1 row affected +insert into t0 values (297, 'tuple 297') +Insert OK, 1 row affected +insert into t0 values (298, 'tuple 298') +Insert OK, 1 row affected +insert into t0 values (299, 'tuple 299') +Insert OK, 1 row affected +select * from t0 where k0 = 295 +Found 1 tuple: +[295, 'tuple 295'] +select * from t0 where k0 = 296 +Found 1 tuple: +[296, 'tuple 296'] +select * from t0 where k0 = 297 +Found 1 tuple: +[297, 'tuple 297'] +select * from t0 where k0 = 298 +Found 1 tuple: +[298, 'tuple 298'] +select * from t0 where k0 = 299 +Found 1 tuple: +[299, 'tuple 299'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 15 iteration +insert into t0 values (300, 'tuple 300') +Insert OK, 1 row affected +insert into t0 values (301, 'tuple 301') +Insert OK, 1 row affected +insert into t0 values (302, 'tuple 302') +Insert OK, 1 row affected +insert into t0 values (303, 'tuple 303') +Insert OK, 1 row affected +insert into t0 values (304, 'tuple 304') +Insert OK, 1 row affected +select * from t0 where k0 = 300 +Found 1 tuple: +[300, 'tuple 300'] +select * from t0 where k0 = 301 +Found 1 tuple: +[301, 'tuple 301'] +select * from t0 where k0 = 302 +Found 1 tuple: +[302, 'tuple 302'] +select * from t0 where k0 = 303 +Found 1 tuple: +[303, 'tuple 303'] +select * from t0 where k0 = 304 +Found 1 tuple: +[304, 'tuple 304'] +insert into t0 values (305, 'tuple 305') +Insert OK, 1 row affected +insert into t0 values (306, 'tuple 306') +Insert OK, 1 row affected +insert into t0 values (307, 'tuple 307') +Insert OK, 1 row affected +insert into t0 values (308, 'tuple 308') +Insert OK, 1 row affected +insert into t0 values (309, 'tuple 309') +Insert OK, 1 row affected +select * from t0 where k0 = 305 +Found 1 tuple: +[305, 'tuple 305'] +select * from t0 where k0 = 306 +Found 1 tuple: +[306, 'tuple 306'] +select * from t0 where k0 = 307 +Found 1 tuple: +[307, 'tuple 307'] +select * from t0 where k0 = 308 +Found 1 tuple: +[308, 'tuple 308'] +select * from t0 where k0 = 309 +Found 1 tuple: +[309, 'tuple 309'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (310, 'tuple 310') +Insert OK, 1 row affected +insert into t0 values (311, 'tuple 311') +Insert OK, 1 row affected +insert into t0 values (312, 'tuple 312') +Insert OK, 1 row affected +insert into t0 values (313, 'tuple 313') +Insert OK, 1 row affected +insert into t0 values (314, 'tuple 314') +Insert OK, 1 row affected +select * from t0 where k0 = 310 +Found 1 tuple: +[310, 'tuple 310'] +select * from t0 where k0 = 311 +Found 1 tuple: +[311, 'tuple 311'] +select * from t0 where k0 = 312 +Found 1 tuple: +[312, 'tuple 312'] +select * from t0 where k0 = 313 +Found 1 tuple: +[313, 'tuple 313'] +select * from t0 where k0 = 314 +Found 1 tuple: +[314, 'tuple 314'] +insert into t0 values (315, 'tuple 315') +Insert OK, 1 row affected +insert into t0 values (316, 'tuple 316') +Insert OK, 1 row affected +insert into t0 values (317, 'tuple 317') +Insert OK, 1 row affected +insert into t0 values (318, 'tuple 318') +Insert OK, 1 row affected +insert into t0 values (319, 'tuple 319') +Insert OK, 1 row affected +select * from t0 where k0 = 315 +Found 1 tuple: +[315, 'tuple 315'] +select * from t0 where k0 = 316 +Found 1 tuple: +[316, 'tuple 316'] +select * from t0 where k0 = 317 +Found 1 tuple: +[317, 'tuple 317'] +select * from t0 where k0 = 318 +Found 1 tuple: +[318, 'tuple 318'] +select * from t0 where k0 = 319 +Found 1 tuple: +[319, 'tuple 319'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 16 iteration +insert into t0 values (320, 'tuple 320') +Insert OK, 1 row affected +insert into t0 values (321, 'tuple 321') +Insert OK, 1 row affected +insert into t0 values (322, 'tuple 322') +Insert OK, 1 row affected +insert into t0 values (323, 'tuple 323') +Insert OK, 1 row affected +insert into t0 values (324, 'tuple 324') +Insert OK, 1 row affected +select * from t0 where k0 = 320 +Found 1 tuple: +[320, 'tuple 320'] +select * from t0 where k0 = 321 +Found 1 tuple: +[321, 'tuple 321'] +select * from t0 where k0 = 322 +Found 1 tuple: +[322, 'tuple 322'] +select * from t0 where k0 = 323 +Found 1 tuple: +[323, 'tuple 323'] +select * from t0 where k0 = 324 +Found 1 tuple: +[324, 'tuple 324'] +insert into t0 values (325, 'tuple 325') +Insert OK, 1 row affected +insert into t0 values (326, 'tuple 326') +Insert OK, 1 row affected +insert into t0 values (327, 'tuple 327') +Insert OK, 1 row affected +insert into t0 values (328, 'tuple 328') +Insert OK, 1 row affected +insert into t0 values (329, 'tuple 329') +Insert OK, 1 row affected +select * from t0 where k0 = 325 +Found 1 tuple: +[325, 'tuple 325'] +select * from t0 where k0 = 326 +Found 1 tuple: +[326, 'tuple 326'] +select * from t0 where k0 = 327 +Found 1 tuple: +[327, 'tuple 327'] +select * from t0 where k0 = 328 +Found 1 tuple: +[328, 'tuple 328'] +select * from t0 where k0 = 329 +Found 1 tuple: +[329, 'tuple 329'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (330, 'tuple 330') +Insert OK, 1 row affected +insert into t0 values (331, 'tuple 331') +Insert OK, 1 row affected +insert into t0 values (332, 'tuple 332') +Insert OK, 1 row affected +insert into t0 values (333, 'tuple 333') +Insert OK, 1 row affected +insert into t0 values (334, 'tuple 334') +Insert OK, 1 row affected +select * from t0 where k0 = 330 +Found 1 tuple: +[330, 'tuple 330'] +select * from t0 where k0 = 331 +Found 1 tuple: +[331, 'tuple 331'] +select * from t0 where k0 = 332 +Found 1 tuple: +[332, 'tuple 332'] +select * from t0 where k0 = 333 +Found 1 tuple: +[333, 'tuple 333'] +select * from t0 where k0 = 334 +Found 1 tuple: +[334, 'tuple 334'] +insert into t0 values (335, 'tuple 335') +Insert OK, 1 row affected +insert into t0 values (336, 'tuple 336') +Insert OK, 1 row affected +insert into t0 values (337, 'tuple 337') +Insert OK, 1 row affected +insert into t0 values (338, 'tuple 338') +Insert OK, 1 row affected +insert into t0 values (339, 'tuple 339') +Insert OK, 1 row affected +select * from t0 where k0 = 335 +Found 1 tuple: +[335, 'tuple 335'] +select * from t0 where k0 = 336 +Found 1 tuple: +[336, 'tuple 336'] +select * from t0 where k0 = 337 +Found 1 tuple: +[337, 'tuple 337'] +select * from t0 where k0 = 338 +Found 1 tuple: +[338, 'tuple 338'] +select * from t0 where k0 = 339 +Found 1 tuple: +[339, 'tuple 339'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 17 iteration +insert into t0 values (340, 'tuple 340') +Insert OK, 1 row affected +insert into t0 values (341, 'tuple 341') +Insert OK, 1 row affected +insert into t0 values (342, 'tuple 342') +Insert OK, 1 row affected +insert into t0 values (343, 'tuple 343') +Insert OK, 1 row affected +insert into t0 values (344, 'tuple 344') +Insert OK, 1 row affected +select * from t0 where k0 = 340 +Found 1 tuple: +[340, 'tuple 340'] +select * from t0 where k0 = 341 +Found 1 tuple: +[341, 'tuple 341'] +select * from t0 where k0 = 342 +Found 1 tuple: +[342, 'tuple 342'] +select * from t0 where k0 = 343 +Found 1 tuple: +[343, 'tuple 343'] +select * from t0 where k0 = 344 +Found 1 tuple: +[344, 'tuple 344'] +insert into t0 values (345, 'tuple 345') +Insert OK, 1 row affected +insert into t0 values (346, 'tuple 346') +Insert OK, 1 row affected +insert into t0 values (347, 'tuple 347') +Insert OK, 1 row affected +insert into t0 values (348, 'tuple 348') +Insert OK, 1 row affected +insert into t0 values (349, 'tuple 349') +Insert OK, 1 row affected +select * from t0 where k0 = 345 +Found 1 tuple: +[345, 'tuple 345'] +select * from t0 where k0 = 346 +Found 1 tuple: +[346, 'tuple 346'] +select * from t0 where k0 = 347 +Found 1 tuple: +[347, 'tuple 347'] +select * from t0 where k0 = 348 +Found 1 tuple: +[348, 'tuple 348'] +select * from t0 where k0 = 349 +Found 1 tuple: +[349, 'tuple 349'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (350, 'tuple 350') +Insert OK, 1 row affected +insert into t0 values (351, 'tuple 351') +Insert OK, 1 row affected +insert into t0 values (352, 'tuple 352') +Insert OK, 1 row affected +insert into t0 values (353, 'tuple 353') +Insert OK, 1 row affected +insert into t0 values (354, 'tuple 354') +Insert OK, 1 row affected +select * from t0 where k0 = 350 +Found 1 tuple: +[350, 'tuple 350'] +select * from t0 where k0 = 351 +Found 1 tuple: +[351, 'tuple 351'] +select * from t0 where k0 = 352 +Found 1 tuple: +[352, 'tuple 352'] +select * from t0 where k0 = 353 +Found 1 tuple: +[353, 'tuple 353'] +select * from t0 where k0 = 354 +Found 1 tuple: +[354, 'tuple 354'] +insert into t0 values (355, 'tuple 355') +Insert OK, 1 row affected +insert into t0 values (356, 'tuple 356') +Insert OK, 1 row affected +insert into t0 values (357, 'tuple 357') +Insert OK, 1 row affected +insert into t0 values (358, 'tuple 358') +Insert OK, 1 row affected +insert into t0 values (359, 'tuple 359') +Insert OK, 1 row affected +select * from t0 where k0 = 355 +Found 1 tuple: +[355, 'tuple 355'] +select * from t0 where k0 = 356 +Found 1 tuple: +[356, 'tuple 356'] +select * from t0 where k0 = 357 +Found 1 tuple: +[357, 'tuple 357'] +select * from t0 where k0 = 358 +Found 1 tuple: +[358, 'tuple 358'] +select * from t0 where k0 = 359 +Found 1 tuple: +[359, 'tuple 359'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 18 iteration +insert into t0 values (360, 'tuple 360') +Insert OK, 1 row affected +insert into t0 values (361, 'tuple 361') +Insert OK, 1 row affected +insert into t0 values (362, 'tuple 362') +Insert OK, 1 row affected +insert into t0 values (363, 'tuple 363') +Insert OK, 1 row affected +insert into t0 values (364, 'tuple 364') +Insert OK, 1 row affected +select * from t0 where k0 = 360 +Found 1 tuple: +[360, 'tuple 360'] +select * from t0 where k0 = 361 +Found 1 tuple: +[361, 'tuple 361'] +select * from t0 where k0 = 362 +Found 1 tuple: +[362, 'tuple 362'] +select * from t0 where k0 = 363 +Found 1 tuple: +[363, 'tuple 363'] +select * from t0 where k0 = 364 +Found 1 tuple: +[364, 'tuple 364'] +insert into t0 values (365, 'tuple 365') +Insert OK, 1 row affected +insert into t0 values (366, 'tuple 366') +Insert OK, 1 row affected +insert into t0 values (367, 'tuple 367') +Insert OK, 1 row affected +insert into t0 values (368, 'tuple 368') +Insert OK, 1 row affected +insert into t0 values (369, 'tuple 369') +Insert OK, 1 row affected +select * from t0 where k0 = 365 +Found 1 tuple: +[365, 'tuple 365'] +select * from t0 where k0 = 366 +Found 1 tuple: +[366, 'tuple 366'] +select * from t0 where k0 = 367 +Found 1 tuple: +[367, 'tuple 367'] +select * from t0 where k0 = 368 +Found 1 tuple: +[368, 'tuple 368'] +select * from t0 where k0 = 369 +Found 1 tuple: +[369, 'tuple 369'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (370, 'tuple 370') +Insert OK, 1 row affected +insert into t0 values (371, 'tuple 371') +Insert OK, 1 row affected +insert into t0 values (372, 'tuple 372') +Insert OK, 1 row affected +insert into t0 values (373, 'tuple 373') +Insert OK, 1 row affected +insert into t0 values (374, 'tuple 374') +Insert OK, 1 row affected +select * from t0 where k0 = 370 +Found 1 tuple: +[370, 'tuple 370'] +select * from t0 where k0 = 371 +Found 1 tuple: +[371, 'tuple 371'] +select * from t0 where k0 = 372 +Found 1 tuple: +[372, 'tuple 372'] +select * from t0 where k0 = 373 +Found 1 tuple: +[373, 'tuple 373'] +select * from t0 where k0 = 374 +Found 1 tuple: +[374, 'tuple 374'] +insert into t0 values (375, 'tuple 375') +Insert OK, 1 row affected +insert into t0 values (376, 'tuple 376') +Insert OK, 1 row affected +insert into t0 values (377, 'tuple 377') +Insert OK, 1 row affected +insert into t0 values (378, 'tuple 378') +Insert OK, 1 row affected +insert into t0 values (379, 'tuple 379') +Insert OK, 1 row affected +select * from t0 where k0 = 375 +Found 1 tuple: +[375, 'tuple 375'] +select * from t0 where k0 = 376 +Found 1 tuple: +[376, 'tuple 376'] +select * from t0 where k0 = 377 +Found 1 tuple: +[377, 'tuple 377'] +select * from t0 where k0 = 378 +Found 1 tuple: +[378, 'tuple 378'] +select * from t0 where k0 = 379 +Found 1 tuple: +[379, 'tuple 379'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... +test 19 iteration +insert into t0 values (380, 'tuple 380') +Insert OK, 1 row affected +insert into t0 values (381, 'tuple 381') +Insert OK, 1 row affected +insert into t0 values (382, 'tuple 382') +Insert OK, 1 row affected +insert into t0 values (383, 'tuple 383') +Insert OK, 1 row affected +insert into t0 values (384, 'tuple 384') +Insert OK, 1 row affected +select * from t0 where k0 = 380 +Found 1 tuple: +[380, 'tuple 380'] +select * from t0 where k0 = 381 +Found 1 tuple: +[381, 'tuple 381'] +select * from t0 where k0 = 382 +Found 1 tuple: +[382, 'tuple 382'] +select * from t0 where k0 = 383 +Found 1 tuple: +[383, 'tuple 383'] +select * from t0 where k0 = 384 +Found 1 tuple: +[384, 'tuple 384'] +insert into t0 values (385, 'tuple 385') +Insert OK, 1 row affected +insert into t0 values (386, 'tuple 386') +Insert OK, 1 row affected +insert into t0 values (387, 'tuple 387') +Insert OK, 1 row affected +insert into t0 values (388, 'tuple 388') +Insert OK, 1 row affected +insert into t0 values (389, 'tuple 389') +Insert OK, 1 row affected +select * from t0 where k0 = 385 +Found 1 tuple: +[385, 'tuple 385'] +select * from t0 where k0 = 386 +Found 1 tuple: +[386, 'tuple 386'] +select * from t0 where k0 = 387 +Found 1 tuple: +[387, 'tuple 387'] +select * from t0 where k0 = 388 +Found 1 tuple: +[388, 'tuple 388'] +select * from t0 where k0 = 389 +Found 1 tuple: +[389, 'tuple 389'] +swap servers +reload configuration +--- +ok +... +reload configuration +--- +ok +... +insert into t0 values (390, 'tuple 390') +Insert OK, 1 row affected +insert into t0 values (391, 'tuple 391') +Insert OK, 1 row affected +insert into t0 values (392, 'tuple 392') +Insert OK, 1 row affected +insert into t0 values (393, 'tuple 393') +Insert OK, 1 row affected +insert into t0 values (394, 'tuple 394') +Insert OK, 1 row affected +select * from t0 where k0 = 390 +Found 1 tuple: +[390, 'tuple 390'] +select * from t0 where k0 = 391 +Found 1 tuple: +[391, 'tuple 391'] +select * from t0 where k0 = 392 +Found 1 tuple: +[392, 'tuple 392'] +select * from t0 where k0 = 393 +Found 1 tuple: +[393, 'tuple 393'] +select * from t0 where k0 = 394 +Found 1 tuple: +[394, 'tuple 394'] +insert into t0 values (395, 'tuple 395') +Insert OK, 1 row affected +insert into t0 values (396, 'tuple 396') +Insert OK, 1 row affected +insert into t0 values (397, 'tuple 397') +Insert OK, 1 row affected +insert into t0 values (398, 'tuple 398') +Insert OK, 1 row affected +insert into t0 values (399, 'tuple 399') +Insert OK, 1 row affected +select * from t0 where k0 = 395 +Found 1 tuple: +[395, 'tuple 395'] +select * from t0 where k0 = 396 +Found 1 tuple: +[396, 'tuple 396'] +select * from t0 where k0 = 397 +Found 1 tuple: +[397, 'tuple 397'] +select * from t0 where k0 = 398 +Found 1 tuple: +[398, 'tuple 398'] +select * from t0 where k0 = 399 +Found 1 tuple: +[399, 'tuple 399'] +rollback servers configuration +reload configuration +--- +ok +... +reload configuration +--- +ok +... diff --git a/test/box_replication/swap.test b/test/box_replication/swap.test new file mode 100644 index 0000000000000000000000000000000000000000..54a4187942c4169fa9a780224fbbf6bbb4429f0f --- /dev/null +++ b/test/box_replication/swap.test @@ -0,0 +1,76 @@ +# encoding: tarantool +import os +import time +from lib.tarantool_box_server import TarantoolBoxServer + +REPEAT = 20 +ID_BEGIN = 0 +ID_STEP = 5 + +def insert_tuples(server, begin, end, msg = "tuple"): + for i in range(begin, end): + server.sql.execute("insert into t0 values (%d, '%s %d')" % (i, msg, i), silent=False) + +def select_tuples(server, begin, end): + # the last lsn is end id + 1 + server.wait_lsn(end + 1) + for i in range(begin, end): + server.sql.execute("select * from t0 where k0 = %d" % i, silent=False) + +# master server +master = server + +# replica server +replica = TarantoolBoxServer() +replica.deploy("box_replication/cfg/replica.cfg", + replica.find_exe(self.args.builddir), + os.path.join(self.args.vardir, "replica")) + +id = ID_BEGIN +for i in range(REPEAT): + print "test %d iteration" % i + + # insert to master + insert_tuples(master, id, id + ID_STEP) + # select from replica + select_tuples(replica, id, id + ID_STEP) + id += ID_STEP + + # insert to master + insert_tuples(master, id, id + ID_STEP) + # select from replica + select_tuples(replica, id, id + ID_STEP) + id += ID_STEP + + print "swap servers" + # reconfigure replica to master + replica.reconfigure("box_replication/cfg/replica_to_master.cfg", silent = False) + # reconfigure master to replica + master.reconfigure("box_replication/cfg/master_to_replica.cfg", silent = False) + + # insert to replica + insert_tuples(replica, id, id + ID_STEP) + # select from master + select_tuples(master, id, id + ID_STEP) + id += ID_STEP + + # insert to replica + insert_tuples(replica, id, id + ID_STEP) + # select from master + select_tuples(master, id, id + ID_STEP) + id += ID_STEP + + print "rollback servers configuration" + # reconfigure replica to master + master.reconfigure("box_replication/cfg/master.cfg", silent = False) + # reconfigure master to replica + replica.reconfigure("box_replication/cfg/replica.cfg", silent = False) + + +# Cleanup. +replica.stop() +replica.cleanup(True) +server.stop() +server.deploy(self.suite_ini["config"]) + +# vim: syntax=python diff --git a/test/box_replication/tarantool_beholder.cfg b/test/box_replication/tarantool_beholder.cfg deleted file mode 100644 index 6e74dbd891b52c979fc2ca76e87062f21cc9ab24..0000000000000000000000000000000000000000 --- a/test/box_replication/tarantool_beholder.cfg +++ /dev/null @@ -1,13 +0,0 @@ -slab_alloc_arena=0.05 -pid_file = "tarantool.pid" - -primary_port = 33013 -secondary_port = 33024 -admin_port = 33025 - -logger="tee -a tarantool.log" -namespace[0].enabled = 1 -namespace[0].index[0].type = "HASH" -namespace[0].index[0].unique = 1 -namespace[0].index[0].key_field[0].fieldno = 0 -namespace[0].index[0].key_field[0].type = "NUM" diff --git a/test/box_replication/tarantool_slave_secondary_feeder_replication.cfg b/test/box_replication/tarantool_slave_secondary_feeder_replication.cfg deleted file mode 100644 index cd918ba1226da0b3e0b4114e91f2bc10ebf035dd..0000000000000000000000000000000000000000 --- a/test/box_replication/tarantool_slave_secondary_feeder_replication.cfg +++ /dev/null @@ -1,17 +0,0 @@ -slab_alloc_arena=0.05 -pid_file = "tarantool.pid" - -primary_port = 33113 -secondary_port = 33114 -admin_port = 33115 - -logger="tee -a tarantool.log" -namespace[0].enabled = 1 -namespace[0].index[0].type = "HASH" -namespace[0].index[0].unique = 1 -namespace[0].index[0].key_field[0].fieldno = 0 -namespace[0].index[0].key_field[0].type = "NUM" - -remote_hot_standby = 1 -wal_feeder_ipaddr = "127.0.0.1" -wal_feeder_port = 33026 diff --git a/test/lib/server.py b/test/lib/server.py index 2c8d47d733e0421a7b2168256f133a57fa7425d5..ab3ff8f7a7b661b066e5fae29fb02e141c573490 100644 --- a/test/lib/server.py +++ b/test/lib/server.py @@ -229,7 +229,7 @@ class Server(object): self.pid = None def deploy(self, config=None, binary=None, vardir=None, - mem=None, start_and_exit=None, gdb=None, valgrind=None, silent=True): + mem=None, start_and_exit=None, gdb=None, valgrind=None, silent=True, need_init=True): if config != None: self.config = config if binary != None: self.binary = binary if vardir != None: self.vardir = vardir @@ -240,7 +240,8 @@ class Server(object): self.configure(self.config) self.install(self.binary, self.vardir, self.mem, silent) - self.init() + if need_init: + self.init() self.start(self.start_and_exit, self.gdb, self.valgrind, silent) def restart(self): diff --git a/test/lib/tarantool_box_server.py b/test/lib/tarantool_box_server.py index c170d1f18f4252c01ab8ddcfaae01bd66769802c..849b235dc1d39053ae6605f6d5232180d556fb12 100644 --- a/test/lib/tarantool_box_server.py +++ b/test/lib/tarantool_box_server.py @@ -1,19 +1,14 @@ +import time import shutil import subprocess import yaml import ConfigParser from tarantool_server import TarantoolServer, TarantoolConfigFile -from admin_connection import AdminConnection +from admin_connection import AdminConnection from box_connection import BoxConnection from memcached_connection import MemcachedConnection import time -#try: -# import memcache -# has_memcached = True -#except ImportError: -# has_memcached = False - class TarantoolBoxServer(TarantoolServer): def __new__(cls, core="tarantool", module="box"): return TarantoolServer.__new__(cls) @@ -53,10 +48,15 @@ class TarantoolBoxServer(TarantoolServer): stdout = subprocess.PIPE, stderr = subprocess.PIPE) + def get_param(self, param): + data = self.admin.execute("show info\n", silent = True) + info = yaml.load(data)["info"] + return info[param] + def wait_lsn(self, lsn): while True: - data = self.admin.execute("show info\n", silent=True) - info = yaml.load(data)["info"] - if (int(info["lsn"]) >= lsn): + curr_lsn = int(self.get_param("lsn")) + if (curr_lsn >= lsn): break time.sleep(0.01) + diff --git a/test/lib/tarantool_feeder_server.py b/test/lib/tarantool_feeder_server.py deleted file mode 100644 index 2a4b7979c568b650ac54c36c4698c61bb0bdf791..0000000000000000000000000000000000000000 --- a/test/lib/tarantool_feeder_server.py +++ /dev/null @@ -1,18 +0,0 @@ -import ConfigParser -from tarantool_server import TarantoolServer, TarantoolConfigFile - -class TarantoolFeederServer(TarantoolServer): - def __new__(cls, core="tarantool", module="feeder"): - return TarantoolServer.__new__(cls) - - def __init__(self, core="tarantool", module="feeder"): - TarantoolServer.__init__(self, core, module) - - def configure(self, config): - TarantoolServer.configure(self, config) - with open(self.config) as fp: - dummy_section_name = "tarantool" - config = ConfigParser.ConfigParser() - config.readfp(TarantoolConfigFile(fp, dummy_section_name)) - self.port = int(config.get(dummy_section_name, "wal_feeder_bind_port")) -