diff --git a/CMakeLists.txt b/CMakeLists.txt index e9651a6ced501442a5b97ba94c9af7f7b1f7f1ea..cb3341db9d6bbfdcfed92fc03c08f7ecdd12942d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,6 @@ include(CheckCCompilerFlag) include(CheckSymbolExists) include(CheckCXXSourceRuns) include(TestBigEndian) -include(CheckFunctionExists) find_program(ECHO echo) find_program(XSLTPROC xsltproc) @@ -60,10 +59,6 @@ endif() check_symbol_exists(MAP_ANON sys/mman.h HAVE_MAP_ANON) check_symbol_exists(MAP_ANONYMOUS sys/mman.h HAVE_MAP_ANONYMOUS) -check_include_file(sys/time.h HAVE_SYS_TIME_H) - -check_symbol_exists(O_DSYNC fcntl.h HAVE_O_DSYNC) -check_function_exists(fdatasync HAVE_FDATASYNC) test_big_endian(HAVE_BYTE_ORDER_BIG_ENDIAN) diff --git a/cfg/core_cfg.cfg_tmpl b/cfg/core_cfg.cfg_tmpl index 3a019a52e21fedaaae2dbe24338916d2bf7f279c..bb3580aa5ce2ee5dadcf0ecb0ba4aaf49ed52b0c 100644 --- a/cfg/core_cfg.cfg_tmpl +++ b/cfg/core_cfg.cfg_tmpl @@ -1,12 +1,6 @@ # username to switch to username=NULL, ro -# 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=false, ro - # tarantool bind ip address, applies to master # and replication ports. INADDR_ANY is the default value. bind_ipaddr="INADDR_ANY", ro @@ -35,12 +29,6 @@ slab_alloc_factor=2.0, ro # working directory (daemon will chdir(2) to it) work_dir=NULL, ro -# Snapshot directory (where snapshots get saved/read) -snap_dir=".", ro - -# WAL directory (where WALs get saved/read) -wal_dir=".", ro - # name of pid file pid_file="tarantool.pid", ro @@ -61,36 +49,3 @@ backlog=1024, ro # network io readahead readahead=16320 - -# Do not write into snapshot faster than snap_io_rate_limit MB/sec -snap_io_rate_limit=0.0, ro - -# Write no more rows in WAL -rows_per_wal=500000, ro - -# Size of the WAL writer request queue: how many outstanding -# requests for write to disk it can have. -# Rule of thumb is to set this to the average connection count. -wal_writer_inbox_size=16384, ro - -# Defines fiber/data synchronization fsync(2) policy: -# "write": fibers wait for their data to be written to the log. -# "fsync": fibers wait for their data, fsync(2) follows each write(2) -# "fsync_delay": fibers wait for their data, fsync every N=wal_fsync_delay seconds, -# N=0.0 means no fsync (equivalent to wal_mode = "write"); -wal_mode="fsync_delay" - -# Fsync WAL delay, only issue fsync if last fsync was wal_fsync_delay -# seconds ago. -# WARNING: actually, several last requests may stall fsync for much longer -wal_fsync_delay=0.0 - -# Delay, in seconds, between successive re-readings of wal_dir. -# The re-scan is necessary to discover new WAL files or snapshots. -wal_dir_rescan_delay=0.1, ro - -# Panic if there is an error reading a snapshot or WAL. -# By default, panic on any snapshot reading error and ignore errors -# when reading WALs. -panic_on_snap_error=true, ro -panic_on_wal_error=false, ro diff --git a/cfg/prscfg.c b/cfg/prscfg.c index c4f11a2bbcc6379eee047cb3a002589dafc67f1c..6f930b537c5f8981d0e3cf9913e0c664a239a608 100644 --- a/cfg/prscfg.c +++ b/cfg/prscfg.c @@ -189,7 +189,7 @@ typedef union YYSTYPE #include <limits.h> #include <sys/types.h> -static int prscfg_yyerror(prscfg_yyscan_t yyscanner, const char *msg); +static int prscfg_yyerror(prscfg_yyscan_t yyscanner, char *msg); extern int prscfg_yylex (YYSTYPE * yylval_param, prscfg_yyscan_t yyscanner); static NameAtom* prependName(NameAtom *prep, NameAtom *name); static void freeName(NameAtom *atom); @@ -2018,7 +2018,7 @@ YYSTYPE yylval; static int -prscfg_yyerror(prscfg_yyscan_t yyscanner, const char *msg) { +prscfg_yyerror(prscfg_yyscan_t yyscanner, char *msg) { out_warning(CNF_SYNTAXERROR, "gram_yyerror: %s at line %d", msg, prscfgGetLineNo(yyscanner)); return 0; } diff --git a/cfg/tarantool_box_cfg.c b/cfg/tarantool_box_cfg.c index 713077d10a4b1b18e594069f591a6fe23c400753..1044259140a484db15945e8ef11e2f69a0297700 100644 --- a/cfg/tarantool_box_cfg.c +++ b/cfg/tarantool_box_cfg.c @@ -29,7 +29,6 @@ init_tarantool_cfg(tarantool_cfg *c) { c->__confetti_flags = 0; c->username = NULL; - c->local_hot_standby = false; c->bind_ipaddr = NULL; c->coredump = false; c->admin_port = 0; @@ -39,22 +38,14 @@ init_tarantool_cfg(tarantool_cfg *c) { c->slab_alloc_minimal = 0; c->slab_alloc_factor = 0; c->work_dir = NULL; - c->snap_dir = NULL; - c->wal_dir = NULL; c->pid_file = NULL; c->logger = NULL; c->logger_nonblock = false; c->io_collect_interval = 0; c->backlog = 0; c->readahead = 0; - c->snap_io_rate_limit = 0; - c->rows_per_wal = 0; - c->wal_writer_inbox_size = 0; - c->wal_mode = NULL; - c->wal_fsync_delay = 0; - c->wal_dir_rescan_delay = 0; - c->panic_on_snap_error = false; - c->panic_on_wal_error = false; + c->snap_dir = NULL; + c->wal_dir = NULL; c->primary_port = 0; c->secondary_port = 0; c->too_long_threshold = 0; @@ -64,6 +55,14 @@ init_tarantool_cfg(tarantool_cfg *c) { c->memcached_expire = false; c->memcached_expire_per_loop = 0; c->memcached_expire_full_sweep = 0; + c->snap_io_rate_limit = 0; + c->rows_per_wal = 0; + c->wal_fsync_delay = 0; + c->wal_writer_inbox_size = 0; + c->local_hot_standby = false; + c->wal_dir_rescan_delay = 0; + c->panic_on_snap_error = false; + c->panic_on_wal_error = false; c->replication_source = NULL; c->space = NULL; } @@ -73,7 +72,6 @@ fill_default_tarantool_cfg(tarantool_cfg *c) { c->__confetti_flags = 0; c->username = NULL; - c->local_hot_standby = false; c->bind_ipaddr = strdup("INADDR_ANY"); if (c->bind_ipaddr == NULL) return CNF_NOMEMORY; c->coredump = false; @@ -84,10 +82,6 @@ fill_default_tarantool_cfg(tarantool_cfg *c) { c->slab_alloc_minimal = 64; c->slab_alloc_factor = 2; c->work_dir = NULL; - c->snap_dir = strdup("."); - if (c->snap_dir == NULL) return CNF_NOMEMORY; - c->wal_dir = strdup("."); - if (c->wal_dir == NULL) return CNF_NOMEMORY; c->pid_file = strdup("tarantool.pid"); if (c->pid_file == NULL) return CNF_NOMEMORY; c->logger = NULL; @@ -95,15 +89,10 @@ fill_default_tarantool_cfg(tarantool_cfg *c) { c->io_collect_interval = 0; c->backlog = 1024; c->readahead = 16320; - c->snap_io_rate_limit = 0; - c->rows_per_wal = 500000; - c->wal_writer_inbox_size = 16384; - c->wal_mode = strdup("fsync_delay"); - if (c->wal_mode == NULL) return CNF_NOMEMORY; - c->wal_fsync_delay = 0; - c->wal_dir_rescan_delay = 0.1; - c->panic_on_snap_error = true; - c->panic_on_wal_error = false; + c->snap_dir = strdup("."); + if (c->snap_dir == NULL) return CNF_NOMEMORY; + c->wal_dir = strdup("."); + if (c->wal_dir == NULL) return CNF_NOMEMORY; c->primary_port = 0; c->secondary_port = 0; c->too_long_threshold = 0.5; @@ -113,6 +102,14 @@ fill_default_tarantool_cfg(tarantool_cfg *c) { c->memcached_expire = false; c->memcached_expire_per_loop = 1024; c->memcached_expire_full_sweep = 3600; + c->snap_io_rate_limit = 0; + c->rows_per_wal = 500000; + c->wal_fsync_delay = 0; + c->wal_writer_inbox_size = 128; + c->local_hot_standby = false; + c->wal_dir_rescan_delay = 0.1; + c->panic_on_snap_error = true; + c->panic_on_wal_error = false; c->replication_source = NULL; c->space = NULL; return 0; @@ -154,9 +151,6 @@ acceptDefault_name__space__index__key_field(tarantool_cfg_space_index_key_field static NameAtom _name__username[] = { { "username", -1, NULL } }; -static NameAtom _name__local_hot_standby[] = { - { "local_hot_standby", -1, NULL } -}; static NameAtom _name__bind_ipaddr[] = { { "bind_ipaddr", -1, NULL } }; @@ -184,12 +178,6 @@ static NameAtom _name__slab_alloc_factor[] = { static NameAtom _name__work_dir[] = { { "work_dir", -1, NULL } }; -static NameAtom _name__snap_dir[] = { - { "snap_dir", -1, NULL } -}; -static NameAtom _name__wal_dir[] = { - { "wal_dir", -1, NULL } -}; static NameAtom _name__pid_file[] = { { "pid_file", -1, NULL } }; @@ -208,29 +196,11 @@ static NameAtom _name__backlog[] = { static NameAtom _name__readahead[] = { { "readahead", -1, NULL } }; -static NameAtom _name__snap_io_rate_limit[] = { - { "snap_io_rate_limit", -1, NULL } -}; -static NameAtom _name__rows_per_wal[] = { - { "rows_per_wal", -1, NULL } -}; -static NameAtom _name__wal_writer_inbox_size[] = { - { "wal_writer_inbox_size", -1, NULL } -}; -static NameAtom _name__wal_mode[] = { - { "wal_mode", -1, NULL } -}; -static NameAtom _name__wal_fsync_delay[] = { - { "wal_fsync_delay", -1, NULL } -}; -static NameAtom _name__wal_dir_rescan_delay[] = { - { "wal_dir_rescan_delay", -1, NULL } -}; -static NameAtom _name__panic_on_snap_error[] = { - { "panic_on_snap_error", -1, NULL } +static NameAtom _name__snap_dir[] = { + { "snap_dir", -1, NULL } }; -static NameAtom _name__panic_on_wal_error[] = { - { "panic_on_wal_error", -1, NULL } +static NameAtom _name__wal_dir[] = { + { "wal_dir", -1, NULL } }; static NameAtom _name__primary_port[] = { { "primary_port", -1, NULL } @@ -259,6 +229,30 @@ static NameAtom _name__memcached_expire_per_loop[] = { static NameAtom _name__memcached_expire_full_sweep[] = { { "memcached_expire_full_sweep", -1, NULL } }; +static NameAtom _name__snap_io_rate_limit[] = { + { "snap_io_rate_limit", -1, NULL } +}; +static NameAtom _name__rows_per_wal[] = { + { "rows_per_wal", -1, NULL } +}; +static NameAtom _name__wal_fsync_delay[] = { + { "wal_fsync_delay", -1, NULL } +}; +static NameAtom _name__wal_writer_inbox_size[] = { + { "wal_writer_inbox_size", -1, NULL } +}; +static NameAtom _name__local_hot_standby[] = { + { "local_hot_standby", -1, NULL } +}; +static NameAtom _name__wal_dir_rescan_delay[] = { + { "wal_dir_rescan_delay", -1, NULL } +}; +static NameAtom _name__panic_on_snap_error[] = { + { "panic_on_snap_error", -1, NULL } +}; +static NameAtom _name__panic_on_wal_error[] = { + { "panic_on_wal_error", -1, NULL } +}; static NameAtom _name__replication_source[] = { { "replication_source", -1, NULL } }; @@ -352,37 +346,6 @@ 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__local_hot_standby) ) { - if (opt->paramType != stringType && opt->paramType != numberType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - bool bln; - - if (opt->paramType == numberType) { - if (strcmp(opt->paramValue.numberval, "0") == 0 || strcmp(opt->paramValue.numberval, "1") == 0) - bln = opt->paramValue.numberval[0] - '0'; - else - return CNF_WRONGRANGE; - } - else if (strcasecmp(opt->paramValue.stringval, "true") == 0 || - strcasecmp(opt->paramValue.stringval, "yes") == 0 || - strcasecmp(opt->paramValue.stringval, "enable") == 0 || - strcasecmp(opt->paramValue.stringval, "on") == 0 || - strcasecmp(opt->paramValue.stringval, "1") == 0 ) - bln = true; - else if (strcasecmp(opt->paramValue.stringval, "false") == 0 || - strcasecmp(opt->paramValue.stringval, "no") == 0 || - strcasecmp(opt->paramValue.stringval, "disable") == 0 || - strcasecmp(opt->paramValue.stringval, "off") == 0 || - strcasecmp(opt->paramValue.stringval, "0") == 0 ) - bln = false; - else - return CNF_WRONGRANGE; - if (check_rdonly && c->local_hot_standby != bln) - return CNF_RDONLY; - c->local_hot_standby = bln; - } else if ( cmpNameAtoms( opt->name, _name__bind_ipaddr) ) { if (opt->paramType != stringType ) return CNF_WRONGTYPE; @@ -516,30 +479,6 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { if (opt->paramValue.stringval && c->work_dir == NULL) return CNF_NOMEMORY; } - else if ( cmpNameAtoms( opt->name, _name__snap_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->snap_dir == NULL) || strcmp(opt->paramValue.stringval, c->snap_dir) != 0)) - return CNF_RDONLY; - if (c->snap_dir) free(c->snap_dir); - c->snap_dir = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; - if (opt->paramValue.stringval && c->snap_dir == NULL) - return CNF_NOMEMORY; - } - else if ( cmpNameAtoms( opt->name, _name__wal_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_dir == NULL) || strcmp(opt->paramValue.stringval, c->wal_dir) != 0)) - return CNF_RDONLY; - if (c->wal_dir) free(c->wal_dir); - c->wal_dir = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; - if (opt->paramValue.stringval && c->wal_dir == NULL) - return CNF_NOMEMORY; - } else if ( cmpNameAtoms( opt->name, _name__pid_file) ) { if (opt->paramType != stringType ) return CNF_WRONGTYPE; @@ -633,19 +572,31 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { return CNF_WRONGRANGE; c->readahead = i32; } - else if ( cmpNameAtoms( opt->name, _name__snap_io_rate_limit) ) { - if (opt->paramType != numberType ) + else if ( cmpNameAtoms( opt->name, _name__snap_dir) ) { + if (opt->paramType != stringType ) 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->snap_io_rate_limit != dbl) + if (check_rdonly && ( (opt->paramValue.stringval == NULL && c->snap_dir == NULL) || strcmp(opt->paramValue.stringval, c->snap_dir) != 0)) return CNF_RDONLY; - c->snap_io_rate_limit = dbl; + if (c->snap_dir) free(c->snap_dir); + c->snap_dir = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; + if (opt->paramValue.stringval && c->snap_dir == NULL) + return CNF_NOMEMORY; } - else if ( cmpNameAtoms( opt->name, _name__rows_per_wal) ) { + else if ( cmpNameAtoms( opt->name, _name__wal_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_dir == NULL) || strcmp(opt->paramValue.stringval, c->wal_dir) != 0)) + return CNF_RDONLY; + if (c->wal_dir) free(c->wal_dir); + c->wal_dir = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; + if (opt->paramValue.stringval && c->wal_dir == NULL) + return CNF_NOMEMORY; + } + else if ( cmpNameAtoms( opt->name, _name__primary_port) ) { if (opt->paramType != numberType ) return CNF_WRONGTYPE; c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; @@ -655,11 +606,11 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { return CNF_WRONGINT; if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) return CNF_WRONGRANGE; - if (check_rdonly && c->rows_per_wal != i32) + if (check_rdonly && c->primary_port != i32) return CNF_RDONLY; - c->rows_per_wal = i32; + c->primary_port = i32; } - else if ( cmpNameAtoms( opt->name, _name__wal_writer_inbox_size) ) { + else if ( cmpNameAtoms( opt->name, _name__secondary_port) ) { if (opt->paramType != numberType ) return CNF_WRONGTYPE; c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; @@ -669,21 +620,11 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { return CNF_WRONGINT; if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) return CNF_WRONGRANGE; - if (check_rdonly && c->wal_writer_inbox_size != i32) + if (check_rdonly && c->secondary_port != i32) return CNF_RDONLY; - c->wal_writer_inbox_size = i32; - } - else if ( cmpNameAtoms( opt->name, _name__wal_mode) ) { - if (opt->paramType != stringType ) - return CNF_WRONGTYPE; - c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; - errno = 0; - if (c->wal_mode) free(c->wal_mode); - c->wal_mode = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; - if (opt->paramValue.stringval && c->wal_mode == NULL) - return CNF_NOMEMORY; + c->secondary_port = i32; } - else if ( cmpNameAtoms( opt->name, _name__wal_fsync_delay) ) { + else if ( cmpNameAtoms( opt->name, _name__too_long_threshold) ) { if (opt->paramType != numberType ) return CNF_WRONGTYPE; c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; @@ -691,52 +632,49 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { double dbl = strtod(opt->paramValue.numberval, NULL); if ( (dbl == 0 || dbl == -HUGE_VAL || dbl == HUGE_VAL) && errno == ERANGE) return CNF_WRONGRANGE; - c->wal_fsync_delay = dbl; + c->too_long_threshold = dbl; } - else if ( cmpNameAtoms( opt->name, _name__wal_dir_rescan_delay) ) { + 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; + if (c->custom_proc_title) free(c->custom_proc_title); + 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 if ( cmpNameAtoms( opt->name, _name__memcached_port) ) { 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) + 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_dir_rescan_delay != dbl) + if (check_rdonly && c->memcached_port != i32) return CNF_RDONLY; - c->wal_dir_rescan_delay = dbl; + c->memcached_port = i32; } - else if ( cmpNameAtoms( opt->name, _name__panic_on_snap_error) ) { - if (opt->paramType != stringType && opt->paramType != numberType ) + else if ( cmpNameAtoms( opt->name, _name__memcached_space) ) { + if (opt->paramType != numberType ) return CNF_WRONGTYPE; c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; errno = 0; - bool bln; - - if (opt->paramType == numberType) { - if (strcmp(opt->paramValue.numberval, "0") == 0 || strcmp(opt->paramValue.numberval, "1") == 0) - bln = opt->paramValue.numberval[0] - '0'; - else - return CNF_WRONGRANGE; - } - else if (strcasecmp(opt->paramValue.stringval, "true") == 0 || - strcasecmp(opt->paramValue.stringval, "yes") == 0 || - strcasecmp(opt->paramValue.stringval, "enable") == 0 || - strcasecmp(opt->paramValue.stringval, "on") == 0 || - strcasecmp(opt->paramValue.stringval, "1") == 0 ) - bln = true; - else if (strcasecmp(opt->paramValue.stringval, "false") == 0 || - strcasecmp(opt->paramValue.stringval, "no") == 0 || - strcasecmp(opt->paramValue.stringval, "disable") == 0 || - strcasecmp(opt->paramValue.stringval, "off") == 0 || - strcasecmp(opt->paramValue.stringval, "0") == 0 ) - bln = false; - else + 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->panic_on_snap_error != bln) + if (check_rdonly && c->memcached_space != i32) return CNF_RDONLY; - c->panic_on_snap_error = bln; + c->memcached_space = i32; } - else if ( cmpNameAtoms( opt->name, _name__panic_on_wal_error) ) { + else if ( cmpNameAtoms( opt->name, _name__memcached_expire) ) { if (opt->paramType != stringType && opt->paramType != numberType ) return CNF_WRONGTYPE; c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; @@ -763,11 +701,11 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { bln = false; else return CNF_WRONGRANGE; - if (check_rdonly && c->panic_on_wal_error != bln) + if (check_rdonly && c->memcached_expire != bln) return CNF_RDONLY; - c->panic_on_wal_error = bln; + c->memcached_expire = bln; } - else if ( cmpNameAtoms( opt->name, _name__primary_port) ) { + else if ( cmpNameAtoms( opt->name, _name__memcached_expire_per_loop) ) { if (opt->paramType != numberType ) return CNF_WRONGTYPE; c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; @@ -777,25 +715,19 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { return CNF_WRONGINT; if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) return CNF_WRONGRANGE; - if (check_rdonly && c->primary_port != i32) - return CNF_RDONLY; - c->primary_port = i32; + c->memcached_expire_per_loop = i32; } - else if ( cmpNameAtoms( opt->name, _name__secondary_port) ) { + else if ( cmpNameAtoms( opt->name, _name__memcached_expire_full_sweep) ) { 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) + 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->secondary_port != i32) - return CNF_RDONLY; - c->secondary_port = i32; + c->memcached_expire_full_sweep = dbl; } - else if ( cmpNameAtoms( opt->name, _name__too_long_threshold) ) { + else if ( cmpNameAtoms( opt->name, _name__snap_io_rate_limit) ) { if (opt->paramType != numberType ) return CNF_WRONGTYPE; c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; @@ -803,21 +735,11 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { double dbl = strtod(opt->paramValue.numberval, NULL); if ( (dbl == 0 || dbl == -HUGE_VAL || dbl == HUGE_VAL) && errno == ERANGE) return CNF_WRONGRANGE; - c->too_long_threshold = dbl; - } - 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)) + if (check_rdonly && c->snap_io_rate_limit != dbl) return CNF_RDONLY; - if (c->custom_proc_title) free(c->custom_proc_title); - c->custom_proc_title = (opt->paramValue.stringval) ? strdup(opt->paramValue.stringval) : NULL; - if (opt->paramValue.stringval && c->custom_proc_title == NULL) - return CNF_NOMEMORY; + c->snap_io_rate_limit = dbl; } - else if ( cmpNameAtoms( opt->name, _name__memcached_port) ) { + else if ( cmpNameAtoms( opt->name, _name__rows_per_wal) ) { if (opt->paramType != numberType ) return CNF_WRONGTYPE; c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; @@ -827,11 +749,23 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { return CNF_WRONGINT; if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) return CNF_WRONGRANGE; - if (check_rdonly && c->memcached_port != i32) + if (check_rdonly && c->rows_per_wal != i32) return CNF_RDONLY; - c->memcached_port = i32; + c->rows_per_wal = i32; } - else if ( cmpNameAtoms( opt->name, _name__memcached_space) ) { + else if ( cmpNameAtoms( opt->name, _name__wal_fsync_delay) ) { + 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->wal_fsync_delay != dbl) + return CNF_RDONLY; + c->wal_fsync_delay = dbl; + } + else if ( cmpNameAtoms( opt->name, _name__wal_writer_inbox_size) ) { if (opt->paramType != numberType ) return CNF_WRONGTYPE; c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; @@ -841,11 +775,11 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { return CNF_WRONGINT; if ( (i32 == LONG_MIN || i32 == LONG_MAX) && errno == ERANGE) return CNF_WRONGRANGE; - if (check_rdonly && c->memcached_space != i32) + if (check_rdonly && c->wal_writer_inbox_size != i32) return CNF_RDONLY; - c->memcached_space = i32; + c->wal_writer_inbox_size = i32; } - else if ( cmpNameAtoms( opt->name, _name__memcached_expire) ) { + else if ( cmpNameAtoms( opt->name, _name__local_hot_standby) ) { if (opt->paramType != stringType && opt->paramType != numberType ) return CNF_WRONGTYPE; c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; @@ -872,31 +806,83 @@ acceptValue(tarantool_cfg* c, OptDef* opt, int check_rdonly) { bln = false; else return CNF_WRONGRANGE; - if (check_rdonly && c->memcached_expire != bln) + if (check_rdonly && c->local_hot_standby != bln) return CNF_RDONLY; - c->memcached_expire = bln; + c->local_hot_standby = bln; } - else if ( cmpNameAtoms( opt->name, _name__memcached_expire_per_loop) ) { + else if ( cmpNameAtoms( opt->name, _name__wal_dir_rescan_delay) ) { 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) + double dbl = strtod(opt->paramValue.numberval, NULL); + if ( (dbl == 0 || dbl == -HUGE_VAL || dbl == HUGE_VAL) && errno == ERANGE) return CNF_WRONGRANGE; - c->memcached_expire_per_loop = i32; + if (check_rdonly && c->wal_dir_rescan_delay != dbl) + return CNF_RDONLY; + c->wal_dir_rescan_delay = dbl; } - else if ( cmpNameAtoms( opt->name, _name__memcached_expire_full_sweep) ) { - if (opt->paramType != numberType ) + else if ( cmpNameAtoms( opt->name, _name__panic_on_snap_error) ) { + if (opt->paramType != stringType && 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) + bool bln; + + if (opt->paramType == numberType) { + if (strcmp(opt->paramValue.numberval, "0") == 0 || strcmp(opt->paramValue.numberval, "1") == 0) + bln = opt->paramValue.numberval[0] - '0'; + else + return CNF_WRONGRANGE; + } + else if (strcasecmp(opt->paramValue.stringval, "true") == 0 || + strcasecmp(opt->paramValue.stringval, "yes") == 0 || + strcasecmp(opt->paramValue.stringval, "enable") == 0 || + strcasecmp(opt->paramValue.stringval, "on") == 0 || + strcasecmp(opt->paramValue.stringval, "1") == 0 ) + bln = true; + else if (strcasecmp(opt->paramValue.stringval, "false") == 0 || + strcasecmp(opt->paramValue.stringval, "no") == 0 || + strcasecmp(opt->paramValue.stringval, "disable") == 0 || + strcasecmp(opt->paramValue.stringval, "off") == 0 || + strcasecmp(opt->paramValue.stringval, "0") == 0 ) + bln = false; + else return CNF_WRONGRANGE; - c->memcached_expire_full_sweep = dbl; + if (check_rdonly && c->panic_on_snap_error != bln) + return CNF_RDONLY; + c->panic_on_snap_error = bln; + } + else if ( cmpNameAtoms( opt->name, _name__panic_on_wal_error) ) { + if (opt->paramType != stringType && opt->paramType != numberType ) + return CNF_WRONGTYPE; + c->__confetti_flags &= ~CNF_FLAG_STRUCT_NOTSET; + errno = 0; + bool bln; + + if (opt->paramType == numberType) { + if (strcmp(opt->paramValue.numberval, "0") == 0 || strcmp(opt->paramValue.numberval, "1") == 0) + bln = opt->paramValue.numberval[0] - '0'; + else + return CNF_WRONGRANGE; + } + else if (strcasecmp(opt->paramValue.stringval, "true") == 0 || + strcasecmp(opt->paramValue.stringval, "yes") == 0 || + strcasecmp(opt->paramValue.stringval, "enable") == 0 || + strcasecmp(opt->paramValue.stringval, "on") == 0 || + strcasecmp(opt->paramValue.stringval, "1") == 0 ) + bln = true; + else if (strcasecmp(opt->paramValue.stringval, "false") == 0 || + strcasecmp(opt->paramValue.stringval, "no") == 0 || + strcasecmp(opt->paramValue.stringval, "disable") == 0 || + strcasecmp(opt->paramValue.stringval, "off") == 0 || + strcasecmp(opt->paramValue.stringval, "0") == 0 ) + bln = false; + else + return CNF_WRONGRANGE; + if (check_rdonly && c->panic_on_wal_error != bln) + return CNF_RDONLY; + c->panic_on_wal_error = bln; } else if ( cmpNameAtoms( opt->name, _name__replication_source) ) { if (opt->paramType != stringType ) @@ -1221,7 +1207,6 @@ parse_cfg_buffer_tarantool_cfg(tarantool_cfg *c, char *buffer, int check_rdonly, typedef enum IteratorState { _S_Initial = 0, S_name__username, - S_name__local_hot_standby, S_name__bind_ipaddr, S_name__coredump, S_name__admin_port, @@ -1231,22 +1216,14 @@ typedef enum IteratorState { S_name__slab_alloc_minimal, S_name__slab_alloc_factor, S_name__work_dir, - S_name__snap_dir, - S_name__wal_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__snap_io_rate_limit, - S_name__rows_per_wal, - S_name__wal_writer_inbox_size, - S_name__wal_mode, - S_name__wal_fsync_delay, - S_name__wal_dir_rescan_delay, - S_name__panic_on_snap_error, - S_name__panic_on_wal_error, + S_name__snap_dir, + S_name__wal_dir, S_name__primary_port, S_name__secondary_port, S_name__too_long_threshold, @@ -1256,6 +1233,14 @@ typedef enum IteratorState { S_name__memcached_expire, S_name__memcached_expire_per_loop, S_name__memcached_expire_full_sweep, + S_name__snap_io_rate_limit, + S_name__rows_per_wal, + S_name__wal_fsync_delay, + S_name__wal_writer_inbox_size, + S_name__local_hot_standby, + S_name__wal_dir_rescan_delay, + S_name__panic_on_snap_error, + S_name__panic_on_wal_error, S_name__replication_source, S_name__space, S_name__space__enabled, @@ -1302,17 +1287,6 @@ tarantool_cfg_iterator_next(tarantool_cfg_iterator_t* i, tarantool_cfg *c, char return NULL; } snprintf(buf, PRINTBUFLEN-1, "username"); - i->state = S_name__local_hot_standby; - return buf; - case S_name__local_hot_standby: - *v = malloc(8); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%s", c->local_hot_standby ? "true" : "false"); - snprintf(buf, PRINTBUFLEN-1, "local_hot_standby"); i->state = S_name__bind_ipaddr; return buf; case S_name__bind_ipaddr: @@ -1410,26 +1384,6 @@ tarantool_cfg_iterator_next(tarantool_cfg_iterator_t* i, tarantool_cfg *c, char return NULL; } snprintf(buf, PRINTBUFLEN-1, "work_dir"); - i->state = S_name__snap_dir; - return buf; - case S_name__snap_dir: - *v = (c->snap_dir) ? strdup(c->snap_dir) : NULL; - if (*v == NULL && c->snap_dir) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - snprintf(buf, PRINTBUFLEN-1, "snap_dir"); - i->state = S_name__wal_dir; - return buf; - case S_name__wal_dir: - *v = (c->wal_dir) ? strdup(c->wal_dir) : NULL; - if (*v == NULL && c->wal_dir) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - snprintf(buf, PRINTBUFLEN-1, "wal_dir"); i->state = S_name__pid_file; return buf; case S_name__pid_file: @@ -1470,117 +1424,50 @@ tarantool_cfg_iterator_next(tarantool_cfg_iterator_t* i, tarantool_cfg *c, char 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__snap_io_rate_limit; - return buf; - case S_name__snap_io_rate_limit: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%g", c->snap_io_rate_limit); - snprintf(buf, PRINTBUFLEN-1, "snap_io_rate_limit"); - i->state = S_name__rows_per_wal; - return buf; - case S_name__rows_per_wal: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%"PRId32, c->rows_per_wal); - snprintf(buf, PRINTBUFLEN-1, "rows_per_wal"); - i->state = S_name__wal_writer_inbox_size; - return buf; - case S_name__wal_writer_inbox_size: - *v = malloc(32); - if (*v == NULL) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - sprintf(*v, "%"PRId32, c->wal_writer_inbox_size); - snprintf(buf, PRINTBUFLEN-1, "wal_writer_inbox_size"); - i->state = S_name__wal_mode; - return buf; - case S_name__wal_mode: - *v = (c->wal_mode) ? strdup(c->wal_mode) : NULL; - if (*v == NULL && c->wal_mode) { - free(i); - out_warning(CNF_NOMEMORY, "No memory to output value"); - return NULL; - } - snprintf(buf, PRINTBUFLEN-1, "wal_mode"); - i->state = S_name__wal_fsync_delay; + sprintf(*v, "%g", c->io_collect_interval); + snprintf(buf, PRINTBUFLEN-1, "io_collect_interval"); + i->state = S_name__backlog; return buf; - case S_name__wal_fsync_delay: + 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, "%g", c->wal_fsync_delay); - snprintf(buf, PRINTBUFLEN-1, "wal_fsync_delay"); - i->state = S_name__wal_dir_rescan_delay; + sprintf(*v, "%"PRId32, c->backlog); + snprintf(buf, PRINTBUFLEN-1, "backlog"); + i->state = S_name__readahead; return buf; - case S_name__wal_dir_rescan_delay: + 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, "%g", c->wal_dir_rescan_delay); - snprintf(buf, PRINTBUFLEN-1, "wal_dir_rescan_delay"); - i->state = S_name__panic_on_snap_error; + sprintf(*v, "%"PRId32, c->readahead); + snprintf(buf, PRINTBUFLEN-1, "readahead"); + i->state = S_name__snap_dir; return buf; - case S_name__panic_on_snap_error: - *v = malloc(8); - if (*v == NULL) { + case S_name__snap_dir: + *v = (c->snap_dir) ? strdup(c->snap_dir) : NULL; + if (*v == NULL && c->snap_dir) { free(i); out_warning(CNF_NOMEMORY, "No memory to output value"); return NULL; } - sprintf(*v, "%s", c->panic_on_snap_error ? "true" : "false"); - snprintf(buf, PRINTBUFLEN-1, "panic_on_snap_error"); - i->state = S_name__panic_on_wal_error; + snprintf(buf, PRINTBUFLEN-1, "snap_dir"); + i->state = S_name__wal_dir; return buf; - case S_name__panic_on_wal_error: - *v = malloc(8); - if (*v == NULL) { + case S_name__wal_dir: + *v = (c->wal_dir) ? strdup(c->wal_dir) : NULL; + if (*v == NULL && c->wal_dir) { free(i); out_warning(CNF_NOMEMORY, "No memory to output value"); return NULL; } - sprintf(*v, "%s", c->panic_on_wal_error ? "true" : "false"); - snprintf(buf, PRINTBUFLEN-1, "panic_on_wal_error"); + snprintf(buf, PRINTBUFLEN-1, "wal_dir"); i->state = S_name__primary_port; return buf; case S_name__primary_port: @@ -1679,6 +1566,94 @@ tarantool_cfg_iterator_next(tarantool_cfg_iterator_t* i, tarantool_cfg *c, char } sprintf(*v, "%g", c->memcached_expire_full_sweep); snprintf(buf, PRINTBUFLEN-1, "memcached_expire_full_sweep"); + i->state = S_name__snap_io_rate_limit; + return buf; + case S_name__snap_io_rate_limit: + *v = malloc(32); + if (*v == NULL) { + free(i); + out_warning(CNF_NOMEMORY, "No memory to output value"); + return NULL; + } + sprintf(*v, "%g", c->snap_io_rate_limit); + snprintf(buf, PRINTBUFLEN-1, "snap_io_rate_limit"); + i->state = S_name__rows_per_wal; + return buf; + case S_name__rows_per_wal: + *v = malloc(32); + if (*v == NULL) { + free(i); + out_warning(CNF_NOMEMORY, "No memory to output value"); + return NULL; + } + sprintf(*v, "%"PRId32, c->rows_per_wal); + snprintf(buf, PRINTBUFLEN-1, "rows_per_wal"); + i->state = S_name__wal_fsync_delay; + return buf; + case S_name__wal_fsync_delay: + *v = malloc(32); + if (*v == NULL) { + free(i); + out_warning(CNF_NOMEMORY, "No memory to output value"); + return NULL; + } + sprintf(*v, "%g", c->wal_fsync_delay); + snprintf(buf, PRINTBUFLEN-1, "wal_fsync_delay"); + i->state = S_name__wal_writer_inbox_size; + return buf; + case S_name__wal_writer_inbox_size: + *v = malloc(32); + if (*v == NULL) { + free(i); + out_warning(CNF_NOMEMORY, "No memory to output value"); + return NULL; + } + sprintf(*v, "%"PRId32, c->wal_writer_inbox_size); + snprintf(buf, PRINTBUFLEN-1, "wal_writer_inbox_size"); + i->state = S_name__local_hot_standby; + return buf; + case S_name__local_hot_standby: + *v = malloc(8); + if (*v == NULL) { + free(i); + out_warning(CNF_NOMEMORY, "No memory to output value"); + return NULL; + } + sprintf(*v, "%s", c->local_hot_standby ? "true" : "false"); + snprintf(buf, PRINTBUFLEN-1, "local_hot_standby"); + i->state = S_name__wal_dir_rescan_delay; + return buf; + case S_name__wal_dir_rescan_delay: + *v = malloc(32); + if (*v == NULL) { + free(i); + out_warning(CNF_NOMEMORY, "No memory to output value"); + return NULL; + } + sprintf(*v, "%g", c->wal_dir_rescan_delay); + snprintf(buf, PRINTBUFLEN-1, "wal_dir_rescan_delay"); + i->state = S_name__panic_on_snap_error; + return buf; + case S_name__panic_on_snap_error: + *v = malloc(8); + if (*v == NULL) { + free(i); + out_warning(CNF_NOMEMORY, "No memory to output value"); + return NULL; + } + sprintf(*v, "%s", c->panic_on_snap_error ? "true" : "false"); + snprintf(buf, PRINTBUFLEN-1, "panic_on_snap_error"); + i->state = S_name__panic_on_wal_error; + return buf; + case S_name__panic_on_wal_error: + *v = malloc(8); + if (*v == NULL) { + free(i); + out_warning(CNF_NOMEMORY, "No memory to output value"); + return NULL; + } + sprintf(*v, "%s", c->panic_on_wal_error ? "true" : "false"); + snprintf(buf, PRINTBUFLEN-1, "panic_on_wal_error"); i->state = S_name__replication_source; return buf; case S_name__replication_source: @@ -1970,7 +1945,6 @@ dup_tarantool_cfg(tarantool_cfg* dst, tarantool_cfg* src) { if (dst->username) free(dst->username);dst->username = src->username == NULL ? NULL : strdup(src->username); if (src->username != NULL && dst->username == NULL) return CNF_NOMEMORY; - dst->local_hot_standby = src->local_hot_standby; if (dst->bind_ipaddr) free(dst->bind_ipaddr);dst->bind_ipaddr = src->bind_ipaddr == NULL ? NULL : strdup(src->bind_ipaddr); if (src->bind_ipaddr != NULL && dst->bind_ipaddr == NULL) return CNF_NOMEMORY; @@ -1984,12 +1958,6 @@ dup_tarantool_cfg(tarantool_cfg* dst, tarantool_cfg* src) { if (dst->work_dir) free(dst->work_dir);dst->work_dir = src->work_dir == NULL ? NULL : strdup(src->work_dir); if (src->work_dir != NULL && dst->work_dir == NULL) return CNF_NOMEMORY; - if (dst->snap_dir) free(dst->snap_dir);dst->snap_dir = src->snap_dir == NULL ? NULL : strdup(src->snap_dir); - if (src->snap_dir != NULL && dst->snap_dir == NULL) - return CNF_NOMEMORY; - if (dst->wal_dir) free(dst->wal_dir);dst->wal_dir = src->wal_dir == NULL ? NULL : strdup(src->wal_dir); - if (src->wal_dir != NULL && dst->wal_dir == NULL) - return CNF_NOMEMORY; if (dst->pid_file) free(dst->pid_file);dst->pid_file = src->pid_file == NULL ? NULL : strdup(src->pid_file); if (src->pid_file != NULL && dst->pid_file == NULL) return CNF_NOMEMORY; @@ -2000,16 +1968,12 @@ dup_tarantool_cfg(tarantool_cfg* dst, tarantool_cfg* src) { dst->io_collect_interval = src->io_collect_interval; dst->backlog = src->backlog; dst->readahead = src->readahead; - dst->snap_io_rate_limit = src->snap_io_rate_limit; - dst->rows_per_wal = src->rows_per_wal; - dst->wal_writer_inbox_size = src->wal_writer_inbox_size; - if (dst->wal_mode) free(dst->wal_mode);dst->wal_mode = src->wal_mode == NULL ? NULL : strdup(src->wal_mode); - if (src->wal_mode != NULL && dst->wal_mode == NULL) + if (dst->snap_dir) free(dst->snap_dir);dst->snap_dir = src->snap_dir == NULL ? NULL : strdup(src->snap_dir); + if (src->snap_dir != NULL && dst->snap_dir == NULL) + return CNF_NOMEMORY; + if (dst->wal_dir) free(dst->wal_dir);dst->wal_dir = src->wal_dir == NULL ? NULL : strdup(src->wal_dir); + if (src->wal_dir != NULL && dst->wal_dir == NULL) return CNF_NOMEMORY; - dst->wal_fsync_delay = src->wal_fsync_delay; - 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->primary_port = src->primary_port; dst->secondary_port = src->secondary_port; dst->too_long_threshold = src->too_long_threshold; @@ -2021,6 +1985,14 @@ dup_tarantool_cfg(tarantool_cfg* dst, tarantool_cfg* src) { dst->memcached_expire = src->memcached_expire; dst->memcached_expire_per_loop = src->memcached_expire_per_loop; dst->memcached_expire_full_sweep = src->memcached_expire_full_sweep; + dst->snap_io_rate_limit = src->snap_io_rate_limit; + dst->rows_per_wal = src->rows_per_wal; + dst->wal_fsync_delay = src->wal_fsync_delay; + dst->wal_writer_inbox_size = src->wal_writer_inbox_size; + dst->local_hot_standby = src->local_hot_standby; + 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; if (dst->replication_source) free(dst->replication_source);dst->replication_source = src->replication_source == NULL ? NULL : strdup(src->replication_source); if (src->replication_source != NULL && dst->replication_source == NULL) return CNF_NOMEMORY; @@ -2093,16 +2065,14 @@ destroy_tarantool_cfg(tarantool_cfg* c) { free(c->bind_ipaddr); if (c->work_dir != NULL) free(c->work_dir); - if (c->snap_dir != NULL) - free(c->snap_dir); - if (c->wal_dir != NULL) - free(c->wal_dir); if (c->pid_file != NULL) free(c->pid_file); if (c->logger != NULL) free(c->logger); - if (c->wal_mode != NULL) - free(c->wal_mode); + if (c->snap_dir != NULL) + free(c->snap_dir); + if (c->wal_dir != NULL) + free(c->wal_dir); if (c->custom_proc_title != NULL) free(c->custom_proc_title); if (c->replication_source != NULL) @@ -2173,11 +2143,6 @@ cmp_tarantool_cfg(tarantool_cfg* c1, tarantool_cfg* c2, int only_check_rdonly) { return diff; } - if (c1->local_hot_standby != c2->local_hot_standby) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->local_hot_standby"); - - return diff; - } if (confetti_strcmp(c1->bind_ipaddr, c2->bind_ipaddr) != 0) { snprintf(diff, PRINTBUFLEN - 1, "%s", "c->bind_ipaddr"); @@ -2225,16 +2190,6 @@ cmp_tarantool_cfg(tarantool_cfg* c1, tarantool_cfg* c2, int only_check_rdonly) { return diff; } - if (confetti_strcmp(c1->snap_dir, c2->snap_dir) != 0) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->snap_dir"); - - return diff; -} - if (confetti_strcmp(c1->wal_dir, c2->wal_dir) != 0) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_dir"); - - return diff; -} if (confetti_strcmp(c1->pid_file, c2->pid_file) != 0) { snprintf(diff, PRINTBUFLEN - 1, "%s", "c->pid_file"); @@ -2267,50 +2222,16 @@ cmp_tarantool_cfg(tarantool_cfg* c1, tarantool_cfg* c2, int only_check_rdonly) { return diff; } } - if (c1->snap_io_rate_limit != c2->snap_io_rate_limit) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->snap_io_rate_limit"); - - return diff; - } - if (c1->rows_per_wal != c2->rows_per_wal) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->rows_per_wal"); - - return diff; - } - if (c1->wal_writer_inbox_size != c2->wal_writer_inbox_size) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_writer_inbox_size"); + if (confetti_strcmp(c1->snap_dir, c2->snap_dir) != 0) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->snap_dir"); return diff; - } - if (!only_check_rdonly) { - if (confetti_strcmp(c1->wal_mode, c2->wal_mode) != 0) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_mode"); - - return diff; } - } - if (!only_check_rdonly) { - if (c1->wal_fsync_delay != c2->wal_fsync_delay) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_fsync_delay"); - - return diff; - } - } - if (c1->wal_dir_rescan_delay != c2->wal_dir_rescan_delay) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_dir_rescan_delay"); - - return diff; - } - if (c1->panic_on_snap_error != c2->panic_on_snap_error) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->panic_on_snap_error"); - - return diff; - } - if (c1->panic_on_wal_error != c2->panic_on_wal_error) { - snprintf(diff, PRINTBUFLEN - 1, "%s", "c->panic_on_wal_error"); + if (confetti_strcmp(c1->wal_dir, c2->wal_dir) != 0) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_dir"); return diff; - } +} if (c1->primary_port != c2->primary_port) { snprintf(diff, PRINTBUFLEN - 1, "%s", "c->primary_port"); @@ -2362,6 +2283,46 @@ cmp_tarantool_cfg(tarantool_cfg* c1, tarantool_cfg* c2, int only_check_rdonly) { return diff; } } + if (c1->snap_io_rate_limit != c2->snap_io_rate_limit) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->snap_io_rate_limit"); + + return diff; + } + if (c1->rows_per_wal != c2->rows_per_wal) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->rows_per_wal"); + + return diff; + } + if (c1->wal_fsync_delay != c2->wal_fsync_delay) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_fsync_delay"); + + return diff; + } + if (c1->wal_writer_inbox_size != c2->wal_writer_inbox_size) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_writer_inbox_size"); + + return diff; + } + if (c1->local_hot_standby != c2->local_hot_standby) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->local_hot_standby"); + + return diff; + } + if (c1->wal_dir_rescan_delay != c2->wal_dir_rescan_delay) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->wal_dir_rescan_delay"); + + return diff; + } + if (c1->panic_on_snap_error != c2->panic_on_snap_error) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->panic_on_snap_error"); + + return diff; + } + if (c1->panic_on_wal_error != c2->panic_on_wal_error) { + snprintf(diff, PRINTBUFLEN - 1, "%s", "c->panic_on_wal_error"); + + return diff; + } if (!only_check_rdonly) { if (confetti_strcmp(c1->replication_source, c2->replication_source) != 0) { snprintf(diff, PRINTBUFLEN - 1, "%s", "c->replication_source"); diff --git a/cfg/tarantool_box_cfg.h b/cfg/tarantool_box_cfg.h index 617d989e05bda834f081dd8b7b3514f84e518fe7..5e9451bb9899c2502b8e28591d27dbf22bde0061 100644 --- a/cfg/tarantool_box_cfg.h +++ b/cfg/tarantool_box_cfg.h @@ -44,14 +44,6 @@ typedef struct tarantool_cfg { /* username to switch to */ char* username; - /* - * 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. - */ - confetti_bool_t local_hot_standby; - /* * tarantool bind ip address, applies to master * and replication ports. INADDR_ANY is the default value. @@ -88,12 +80,6 @@ typedef struct tarantool_cfg { /* working directory (daemon will chdir(2) to it) */ char* work_dir; - /* Snapshot directory (where snapshots get saved/read) */ - char* snap_dir; - - /* WAL directory (where WALs get saved/read) */ - char* wal_dir; - /* name of pid file */ char* pid_file; @@ -117,53 +103,16 @@ typedef struct tarantool_cfg { /* network io readahead */ int32_t readahead; - /* Do not write into snapshot faster than snap_io_rate_limit MB/sec */ - double snap_io_rate_limit; - - /* Write no more rows in WAL */ - int32_t rows_per_wal; - /* - * Size of the WAL writer request queue: how many outstanding - * requests for write to disk it can have. - * Rule of thumb is to set this to the average connection count. - */ - int32_t wal_writer_inbox_size; - - /* - * Defines fiber/data synchronization fsync(2) policy: - * "write": fibers wait for their data to be written to the log. - * "fsync": fibers wait for their data, fsync(2) follows each write(2) - * "fsync_delay": fibers wait for their data, fsync every N=wal_fsync_delay seconds, - * N=0.0 means no fsync (equivalent to wal_mode = "write"); - */ - char* wal_mode; - - /* - * Fsync WAL delay, only issue fsync if last fsync was wal_fsync_delay - * seconds ago. - * WARNING: actually, several last requests may stall fsync for much longer - */ - double wal_fsync_delay; - - /* - * Delay, in seconds, between successive re-readings of wal_dir. - * The re-scan is necessary to discover new WAL files or snapshots. + * # BOX + * Snapshot directory (where snapshots get saved/read) */ - double wal_dir_rescan_delay; + char* snap_dir; - /* - * Panic if there is an error reading a snapshot or WAL. - * By default, panic on any snapshot reading error and ignore errors - * when reading WALs. - */ - confetti_bool_t panic_on_snap_error; - confetti_bool_t panic_on_wal_error; + /* WAL directory (where WALs get saved/read) */ + char* wal_dir; - /* - * # BOX - * Primary port (where updates are accepted) - */ + /* Primary port (where updates are accepted) */ int32_t primary_port; /* Secondary port (where only selects are accepted) */ @@ -193,6 +142,44 @@ typedef struct tarantool_cfg { /* tarantool will try to iterate over all rows within this time */ double memcached_expire_full_sweep; + /* Do not write into snapshot faster than snap_io_rate_limit MB/sec */ + double snap_io_rate_limit; + + /* Write no more rows in WAL */ + int32_t rows_per_wal; + + /* + * fsync WAL delay, only issue fsync if last fsync was wal_fsync_delay + * seconds ago. + * WARNING: actually, several last requests may stall fsync for much longer + */ + double wal_fsync_delay; + + /* size of WAL writer request buffer */ + int32_t wal_writer_inbox_size; + + /* + * 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. + */ + confetti_bool_t local_hot_standby; + + /* + * Delay, in seconds, between successive re-readings of wal_dir. + * The re-scan is necessary to discover new WAL files or snapshots. + */ + double wal_dir_rescan_delay; + + /* + * Panic if there is an error reading a snapshot or WAL. + * By default, panic on any snapshot reading error and ignore errors + * when reading WALs. + */ + confetti_bool_t panic_on_snap_error; + confetti_bool_t panic_on_wal_error; + /* * Replication mode (if enabled, the server, once * bound to the primary port, will connect to diff --git a/cmake/luajit.cmake b/cmake/luajit.cmake index a7dc5fd5159435d41c9774e259c7f3ae4a5beadf..9f8ed4244f569c16f4f824d11f35ac61f84cdb4c 100644 --- a/cmake/luajit.cmake +++ b/cmake/luajit.cmake @@ -119,7 +119,7 @@ elseif (NOT ENABLE_BUNDLED_LUAJIT) # building of LuaJIT bundled with the server source. luajit_try_system() else() - luajit_use_bundled() + luajit_set_default() endif() unset (LUAJIT_RUNS) diff --git a/connector/c/include/libtnt/tnt_update.h b/connector/c/include/libtnt/tnt_update.h index 5b6a36ecf9da3c81107b0e36bcbb5471fa6217e7..8aea2bab305ce44279d35c183cfd5e9a8909c18d 100644 --- a/connector/c/include/libtnt/tnt_update.h +++ b/connector/c/include/libtnt/tnt_update.h @@ -26,16 +26,13 @@ * SUCH DAMAGE. */ -enum { - TNT_UPDATE_ASSIGN = 0, - TNT_UPDATE_ADD, - TNT_UPDATE_AND, - TNT_UPDATE_XOR, - TNT_UPDATE_OR, - TNT_UPDATE_SPLICE, - TNT_UPDATE_DELETE, - TNT_UPDATE_INSERT, -}; +#define TNT_UPDATE_ASSIGN 0 +#define TNT_UPDATE_ADD 1 +#define TNT_UPDATE_AND 2 +#define TNT_UPDATE_XOR 3 +#define TNT_UPDATE_OR 4 +#define TNT_UPDATE_SPLICE 5 +#define TNT_UPDATE_DELETE 6 ssize_t tnt_update_arith(struct tnt_stream *s, uint32_t field, @@ -61,10 +58,6 @@ tnt_update_splice(struct tnt_stream *s, uint32_t field, ssize_t tnt_update_delete(struct tnt_stream *s, uint32_t field); -ssize_t -tnt_update_insert(struct tnt_stream *s, uint32_t field, - char *data, uint32_t size); - ssize_t tnt_update(struct tnt_stream *s, uint32_t ns, uint32_t flags, struct tnt_tuple *k, diff --git a/connector/c/tnt/tnt_update.c b/connector/c/tnt/tnt_update.c index e7de0f26cc6c66391475bae0f3233576588a6cd4..4c106165698a71ca03a199969d99151f64612d87 100644 --- a/connector/c/tnt/tnt_update.c +++ b/connector/c/tnt/tnt_update.c @@ -206,14 +206,6 @@ tnt_update_delete(struct tnt_stream *s, uint32_t field) return tnt_update_op(s, field, TNT_UPDATE_DELETE, NULL, 0); } -ssize_t -tnt_update_insert(struct tnt_stream *s, uint32_t field, - char *data, uint32_t size) -{ - return tnt_update_op(s, field, TNT_UPDATE_INSERT, data, size); -} - - struct tnt_header_update { uint32_t ns; uint32_t flags; diff --git a/connector/perl/lib/MR/IProto.pm b/connector/perl/lib/MR/IProto.pm index 058e9be7f5f728070b5cf637a5cfa375dd0995f3..152b226620637bd80f53aadeb40cb7fd311f84e0 100644 --- a/connector/perl/lib/MR/IProto.pm +++ b/connector/perl/lib/MR/IProto.pm @@ -67,14 +67,6 @@ Or asynchronously: $client->send($request, $callback); # callback is called when reply is received or error is occured -It is recommended to disconnect all connections in child after fork() to -prevent possible conflicts: - - my $pid = fork(); - if ($pid == 0) { - MR::IProto->disconnect_all(); - } - =head1 DESCRIPTION This client is used to communicate with cluster of balanced servers using @@ -234,35 +226,22 @@ sub send { die "Method must be called in void context if you want to use async" if defined wantarray; $self->_send($message, $callback); return; - } else { + } + else { die "Method must be called in scalar context if you want to use sync" unless defined wantarray; my $olddie = ref $SIG{__DIE__} eq 'CODE' ? $SIG{__DIE__} : ref $SIG{__DIE__} eq 'GLOB' ? *{$SIG{__DIE__}}{CODE} : undef; local $SIG{__DIE__} = sub { local $! = 0; $olddie->(@_); } if $olddie; my %servers; my ($data, $error, $errno); - my $conn = $self->_send_now($message, sub { + $self->_send_now($message, sub { ($data, $error) = @_; $errno = $!; return; }, \%servers); - - return if $message->{continue} && !$conn; - - my $cont = sub { - $self->_recv_now(\%servers, max => $message->{continue}?1:0); - $! = $errno; - return $message->{continue}->($data, $error, $errno) if ref $message->{continue} eq 'CODE'; - die $error if $error; - return $data; - }; - - return { - fh => $conn->fh, - connection => $conn, - continue => $cont, - } if $message->{continue}; - - return &$cont(); + $self->_recv_now(\%servers); + $! = $errno; + die $error if $error; + return $data; } } @@ -342,18 +321,6 @@ sub SetTimeout { return; } -=item disconnect_all - -Class method used to disconnect all iproto-connections. Very useful in case of fork(). - -=cut - -sub disconnect_all { - my ($class) = @_; - MR::IProto::Cluster::Server->disconnect_all(); - return; -} - =back =head1 PROTECTED METHODS @@ -401,7 +368,6 @@ around BUILDARGS => sub { $srvargs{tcp_nodelay} = delete $args{tcp_nodelay} if exists $args{tcp_nodelay}; $srvargs{tcp_keepalive} = delete $args{tcp_keepalive} if exists $args{tcp_keepalive}; $srvargs{dump_no_ints} = delete $args{dump_no_ints} if exists $args{dump_no_ints}; - $srvargs{prefix} = $args{name} if exists $args{name} and defined $args{name}; my %clusterargs; $clusterargs{balance} = delete $args{balance} if exists $args{balance}; $clusterargs{servers} = [ @@ -562,19 +528,19 @@ sub _send_now { ); return; }; - return $self->_send_try($sync, $args, $handler, $try); + $self->_send_try($sync, $args, $handler, $try); + return; } sub _send_try { my ($self, $sync, $args, $handler, $try) = @_; my $xsync = $sync ? 'sync' : 'async'; - $args->{max_request_retries} ||= $self->max_request_retries; - $self->_debug(sprintf "send msg=%d try %d of %d total", $args->{msg}, $try, $args->{max_request_retries} ) if $self->debug >= 2; + $self->_debug(sprintf "send msg=%d try %d of %d total", $args->{msg}, $try, $self->max_request_retries ) if $self->debug >= 2; my $server = $self->cluster->server( $args->{key} ); my $connection = $server->$xsync(); - return unless $connection->send($args->{msg}, $args->{body}, $handler, $args->{no_reply}, $args->{sync}); + $connection->send($args->{msg}, $args->{body}, $handler, $args->{no_reply}, $args->{sync}); $sync->{$connection} ||= $connection if $sync; - return $connection; + return; } sub _send_retry { @@ -609,8 +575,8 @@ sub _server_callback { my $retry = defined $args->{request} ? $args->{request}->retry() : ref $args->{retry} eq 'CODE' ? $args->{retry}->() : $args->{retry}; - $self->_debug("send: failed[@{[$retry, $$try+1, $args->{max_request_retries}]}]") if $self->debug >= 2; - if( $retry && $$try++ < $args->{max_request_retries} ) { + $self->_debug("send: failed[@{[$retry, $$try+1, $self->max_request_retries]}]") if $self->debug >= 2; + if( $retry && $$try++ < $self->max_request_retries ) { $self->_send_retry($sync, $args, $$handler, $$try); } else { @@ -631,10 +597,10 @@ sub _server_callback { 1; }; if($ok) { - if( defined $args->{request} && $data->retry && $$try++ < $args->{max_request_retries} ) { + if( defined $args->{request} && $data->retry && $$try++ < $self->max_request_retries ) { $self->_send_retry($sync, $args, $$handler, $$try); } - elsif( defined $args->{is_retry} && $args->{is_retry}->($data) && $$try++ < $args->{max_request_retries} ) { + elsif( defined $args->{is_retry} && $args->{is_retry}->($data) && $$try++ < $self->max_request_retries ) { $self->_send_retry($sync, $args, $$handler, $$try); } else { @@ -657,10 +623,10 @@ sub _server_callback { } sub _recv_now { - my ($self, $servers, %opts) = @_; + my ($self, $servers) = @_; while(my @servers = values %$servers) { %$servers = (); - $_->recv_all(%opts) foreach @servers; + $_->recv_all() foreach @servers; } return; } diff --git a/connector/perl/lib/MR/IProto/Cluster/Server.pm b/connector/perl/lib/MR/IProto/Cluster/Server.pm index e5b75164ee63797452049ac781f70fcf340bd2b5..e22de5e00ef054e60043bb36881fe2f33573b582 100644 --- a/connector/perl/lib/MR/IProto/Cluster/Server.pm +++ b/connector/perl/lib/MR/IProto/Cluster/Server.pm @@ -12,7 +12,6 @@ This class is used to implement all communication with one server. use Mouse; use Mouse::Util::TypeConstraints; -use Scalar::Util; use MR::IProto::Connection::Async; use MR::IProto::Connection::Sync; use MR::IProto::Message; @@ -30,12 +29,6 @@ coerce 'MR::IProto::Cluster::Server' ); }; -has prefix => ( - is => 'ro', - isa => 'Str', - default => 'MR::IProto', -); - =head1 ATTRIBUTES =over @@ -171,48 +164,14 @@ has sync => ( lazy_build => 1, ); -my %servers; - =back -=head1 PUBLIC METHODS - -=over - -=item disconnect_all - -Class method used to disconnect all iproto-connections. Very useful in case of fork(). - -=cut - -sub disconnect_all { - my ($class) = @_; - foreach my $server (values %servers) { - $server->clear_async(); - $server->clear_sync(); - } - return; -} - =head1 PROTECTED METHODS =over =cut -sub BUILD { - my ($self) = @_; - $servers{Scalar::Util::refaddr($self)} = $self; - Scalar::Util::weaken($servers{Scalar::Util::refaddr($self)}); - return; -} - -sub DEMOLISH { - my ($self) = @_; - delete $servers{Scalar::Util::refaddr($self)}; - return; -} - sub _build_async { my ($self) = @_; return MR::IProto::Connection::Async->new( server => $self ); @@ -225,11 +184,10 @@ sub _build_sync { sub _build_debug_cb { my ($self) = @_; - my $prefix = $self->prefix; return sub { my ($msg) = @_; chomp $msg; - warn "$prefix: $msg\n"; + warn "MR::IProto: $msg\n"; return; }; } diff --git a/connector/perl/lib/MR/IProto/Connection.pm b/connector/perl/lib/MR/IProto/Connection.pm index fd634caaba3b5b333af555a3e37344278091aece..4cc0d66a2c2d8c89ee69075d083627ebd71a6191 100644 --- a/connector/perl/lib/MR/IProto/Connection.pm +++ b/connector/perl/lib/MR/IProto/Connection.pm @@ -58,7 +58,7 @@ sub _unpack_header { sub _choose_sync { my ($self) = @_; - return 1 + int rand 0xfffffffe; + return int(rand 0xffffffff); } no Mouse; diff --git a/connector/perl/lib/MR/IProto/Connection/Async.pm b/connector/perl/lib/MR/IProto/Connection/Async.pm index 2fbdb77c0c7c867dfb4350f3dad77d85bcfbf139..d78b9180ff7eafcf10b7fac169b513c90bef57d4 100644 --- a/connector/perl/lib/MR/IProto/Connection/Async.pm +++ b/connector/perl/lib/MR/IProto/Connection/Async.pm @@ -19,7 +19,6 @@ use Scalar::Util qw(weaken); has _handle => ( is => 'ro', isa => 'AnyEvent::Handle', - predicate => '_has_handle', lazy_build => 1, ); @@ -70,8 +69,6 @@ For list of arguments see L</_send>. =cut -sub fh { return $_[0]->_has_handle && $_[0]->_handle } - sub send { my $self = shift; if( $self->_in_progress < $self->max_parallel ) { @@ -269,8 +266,6 @@ around _choose_sync => sub { die "Can't choose sync value after 50 iterations"; }; -sub Close { die "This is not what should be done" } - =back =head1 SEE ALSO diff --git a/connector/perl/lib/MR/IProto/Connection/Sync.pm b/connector/perl/lib/MR/IProto/Connection/Sync.pm index 33ad7b5c42fddedf155b31967618ee58843f0c26..7c3da90c46e690d3eaca9e31e2dc6d6b2e1b3d89 100644 --- a/connector/perl/lib/MR/IProto/Connection/Sync.pm +++ b/connector/perl/lib/MR/IProto/Connection/Sync.pm @@ -20,62 +20,34 @@ use Socket qw( TCP_NODELAY SO_KEEPALIVE SO_SNDTIMEO SO_RCVTIMEO ); has _socket => ( is => 'ro', isa => 'IO::Socket::INET', - predicate => '_has_socket', - clearer => '_clear_socket', lazy_build => 1, ); has _sent => ( is => 'ro', - default => sub { {} }, -); - -has last_sync => ( - is => 'rw', - isa => 'Int', -); - -has last_error => ( - is => 'rw', - isa => 'Str', - default => '', + default => sub { [] }, ); =head1 PUBLIC METHODS =over -=item fh - -Returns socket. - =item send See L<MR::IProto::Connection/send> for more information. =cut -sub fh { return $_[0]->_has_socket && $_[0]->_socket } - -sub Close { - my ($self, $reason) = @_; - $self->_handle_error(undef, undef, $reason); -} - sub send { my ($self, $msg, $payload, $callback, $no_reply, $sync) = @_; my $server = $self->server; my $sent = $self->_sent; my $ok = eval { - if(defined $sync) { - die "Sync $sync already sent" if exists $sent->{$sync}; - } else { - 1 while exists $sent->{$sync = $self->_choose_sync()}; - } + $sync = $self->_choose_sync() unless defined $sync; $server->_send_started($sync, $msg, $payload); my $socket = $self->_socket; - unless (%$sent) { + unless (@$sent) { vec((my $rin = ''), fileno($socket), 1) = 1; if (select((my $rout = $rin), undef, undef, 0) > 0) { if (sysread($socket, my $buf, 1)) { @@ -108,32 +80,28 @@ sub send { } 1; }; - my $err = $@; - $self->last_sync($sync); if($ok) { if ($no_reply) { $callback->(undef, undef); $server->_recv_finished($sync, undef, undef); } else { - $sent->{$sync} = $callback; + push @$sent, [$sync, $callback]; } } else { - $self->_handle_error($sync, $callback, $err); + $self->_handle_error($sync, $callback, $@); } - return $ok; + return; } sub recv_all { - my ($self, %opts) = @_; + my ($self) = @_; my $server = $self->server; my $sent = $self->_sent; my $dump_resp = $server->debug >= 6; - my @sync = keys %$sent; - my $n = $opts{max} || @sync; - while ($n-- and %$sent) { + while (my $args = shift @$sent) { + my ($sync, $callback) = @$args; my ($resp_msg, $resp_payload); - my ($sync,$callback); my $ok = eval { my $socket = $self->_socket; my $resp_header; @@ -153,9 +121,8 @@ sub recv_all { } } $server->_debug_dump('recv header: ', $resp_header) if $dump_resp; - ($resp_msg, my $resp_length, $sync) = $self->_unpack_header($resp_header); - $callback = delete $sent->{$sync} or die "Reply sync $sync not found"; - #die "Request and reply sync is different: $resp_sync != $sync" unless $resp_sync == $sync; + ($resp_msg, my $resp_length, my $resp_sync) = $self->_unpack_header($resp_header); + die "Request and reply sync is different: $resp_sync != $sync" unless $resp_sync == $sync; $to_read = $resp_length; while( $to_read ) { @@ -177,11 +144,10 @@ sub recv_all { }; if($ok) { $server->_recv_finished($sync, $resp_msg, $resp_payload); - die "No Callback" unless $callback; $callback->($resp_msg, $resp_payload); } else { - $self->_handle_error(undef, undef, $@); + $self->_handle_error($sync, $callback, $@); } } return; @@ -246,7 +212,6 @@ sub _handle_error { } elsif ($error =~ /^(.+?) at \S+ line \d+/s) { $error = $1; } - $self->last_error($error); my $server = $self->server; $server->_debug("error: $error"); if($self->_has_socket()) { @@ -255,17 +220,15 @@ sub _handle_error { } $server->active(0); my $sent = $self->_sent; - if($sync && $callback) { + my @sent = splice @$sent, 0, scalar @$sent; + $server->_recv_finished($sync, undef, undef, $error, $errno); + $callback->(undef, undef, $error, $errno); + foreach my $args (@sent) { + my ($sync, $callback) = @$args; $server->_recv_finished($sync, undef, undef, $error, $errno); $callback->(undef, undef, $error, $errno); - delete $sent->{$sync}; - } - foreach my $sync (keys %$sent) { - $server->_recv_finished($sync, undef, undef, $error, $errno); - $sent->{$sync}->(undef, undef, $error, $errno); } - undef %$sent; - return; + return } =head1 SEE ALSO diff --git a/connector/perl/lib/MR/Pending.pm b/connector/perl/lib/MR/Pending.pm deleted file mode 100644 index 177f78d12d4046e4172ba0d96a6f74cfb305dab1..0000000000000000000000000000000000000000 --- a/connector/perl/lib/MR/Pending.pm +++ /dev/null @@ -1,372 +0,0 @@ -package MR::Pending; -use Mouse; -use Time::HiRes qw/time/; - -has maxtime => ( - is => 'rw', - isa => 'Num', - predicate => "_has_maxtime", - default => 6.0, -); - -has itertime => ( - is => 'rw', - isa => 'Num', - predicate => "_has_itertime", - default => 0.1, -); - -has name => ( - is => 'rw', - isa => 'Str', - required => 1, -); - -has onidle => ( - is => 'rw', - isa => 'CodeRef', - predicate => "_has_onidle", -); - -has _pending => ( - is => 'ro', - isa => 'HashRef[MR::Pending::Item]', - default => sub { {} }, -); - -has exceptions => ( - is => 'rw', - isa => 'Int', - default => 0, -); - -has _exceptions => ( - is => 'ro', - isa => 'ArrayRef', - default => sub { [] }, -); - -has _waitresult => ( - is => 'rw', - isa => 'ArrayRef', -); - -around BUILDARGS => sub { - my $orig = shift; - my $class = shift; - my %args = @_; - if(my $p = delete $args{pending}) { - $args{_pending} = { map { $_->id => $_ } @$p }; - } - $class->$orig(%args); -}; - -sub runcatch { - my ($self, $code, @param) = @_; - my $ret; - unless(eval { $ret = &$code(@param); 1 }) { - push @{$self->_exceptions}, $@; - $self->exceptions($self->exceptions + 1); - } - return $ret; -} - -sub add { - my ($self, @p) = @_; - my $p = $self->_pending; - for my $add (@p) { - die if exists $p->{$add->id}; - $p->{$add->id} = $add; - } - return $self; -} - -sub remove { - my ($self, @p) = @_; - my $p = $self->_pending; - for my $del (@p) { - die unless exists $p->{$del->id}; - delete $p->{$del->id}; - } - return $self; -} - -sub send { - my ($self) = @_; - my $pending = $self->_pending; - foreach my $shard ( grep { $pending->{$_}->is_sleeping } keys %$pending ) { - my $pend = $pending->{$shard}; - if ($pend->try < $pend->retry) { - next unless $pend->is_timeout; - $pend->set_pending_mode(scalar $self->runcatch($pend->onretry, ($pend->id, $pend, $self))); - } else { - delete $pending->{$shard}; - $self->runcatch($pend->onerror, ($pend->id, "no success after @{[$pend->try]} retries", $pend, $self)); - } - } - return $self; -} - -sub wait { - my ($self) = @_; - my $pending = $self->_pending; - - my $in = ''; - vec($in, $_->fileno, 1) = 1 for grep { $_->is_pending } values %$pending; - - my $n; - while(1) { - my $ein = my $rin = $in; - $n = CORE::select($rin, undef, $ein, $self->itertime); - $self->_waitresult([$rin,$ein]); - if ($n < 0) { - next if $!{EINTR}; - warn $self->name.": select() failed: $!"; - return undef; - } - } - - if ($n == 0) { - $self->runcatch($self->onidle, ($self)) if $self->_has_onidle; - return 0; - } - - return $n; -} - -sub recv { - my ($self) = @_; - my $pending = $self->_pending; - my ($rin, $ein) = @{$self->_waitresult}; - - for my $shard (grep { $pending->{$_}->is_pending } keys %$pending) { - my $pend = $pending->{$shard}; - my $fileno = $pend->fileno; - if (vec($rin, $fileno, 1)) { - if (my $list = $pend->continue) { - if (ref $list) { - delete $pending->{$shard}; - $self->runcatch($pend->onok, ($pend->id, $list, $pend, $self)); - } - } else { - $pend->close("error while receiving (".$pend->last_error.")"); - } - } elsif (vec($ein, $fileno, 1)) { - $pend->close("connection reset (".$pend->last_error.")"); - } elsif ($pend->is_timeout) { - $pend->close("timeout (".$pend->last_error.")"); - } - } - - return $self; -} - -sub finish { - my ($self) = @_; - my $timeout = !$self->exceptions; - my $pending = $self->_pending; - for my $shard (grep { !$pending->{$_}->is_done } keys %$pending) { - my $pend = delete $pending->{$shard}; - $pend->close($timeout ? "timeout" : "aborted due to external exception"); - $self->runcatch($pend->onerror, ($pend->id, "timeout", $pend, $self)) if $timeout; - } - return $self; -} - -sub iter { - my ($self) = @_; - - $self->send or return; - return if $self->exceptions; - - my $res = $self->wait; - return if $self->exceptions; - return unless defined $res; - return 1 unless $res; - - $self->recv or return; - return if $self->exceptions; - - return 1; -} - -sub work { - my ($self) = @_; - - my $pending = $self->_pending; - my $time0 = time; - - while(%$pending and time() - $time0 <= $self->maxtime) { - last unless $self->iter; - } - $self->finish; - $self->check_exceptions('raise'); -} - -sub check_exceptions { - my ($self, $raise) = @_; - my $e = $self->_exceptions; - return unless $e && @$e; - my $str = "$$: PENDING EXCEPTIONS BEGIN\n".join("\n$$:###################\n", @$e)."$$: PENDING EXCEPTIONS END"; - die $str if $raise; - warn $str if defined $raise; - return $str; -} - -no Mouse; -__PACKAGE__->meta->make_immutable(); - - - - -package MR::Pending::Item; -use Mouse; -use Time::HiRes qw/time/; -use Carp; - -has id => ( - is => 'ro', - isa => 'Str', - required => 1, -); - -has $_ => ( - is => 'ro', - isa => 'CodeRef', - predicate => "_has_$_", - required => 1, -) for qw/onok onerror onretry/; - -has $_ => ( - is => 'rw', - isa => 'Num', - predicate => "_has_$_", -) for qw/timeout retry_delay/; - -has retry => ( - is => 'rw', - isa => 'Int', - predicate => "_has_retry", -); - -has _done => ( - is => 'rw', - isa => 'Bool', - default => 0, -); - -has _time => ( - is => 'rw', - isa => 'Num', - default => 0, -); - -has _connection => ( - is => 'rw', - isa => 'Maybe[MR::IProto::Connection::Sync]', - clearer => '_clear__connection', - predicate=> '_has__connection', - handles => [qw/last_error/], -); - -has fileno => ( - is => 'ro', - isa => 'Int', - lazy => 1, - default => sub { Carp::confess "not connected!" unless $_[0]->_connection; $_[0]->_connection->fh->fileno }, - clearer => '_clear_fileno', -); - -has _continue => ( - is => 'rw', - isa => 'Maybe[CodeRef]', - clearer => '_clear__continue', -); - -has _postprocess => ( - is => 'rw', - isa => 'Maybe[CodeRef]', - clearer => '_clear__postprocess', -); - -has try => ( - is => 'ro', - isa => 'Int', - default => 0, - writer => '_set_try', -); - -# has bornat => ( -# is => 'ro', -# isa => 'Str', -# default => sub { "[".join("-", $_[0], $$, time(), Carp::longmess())."]"; }, -# ); - -sub is_done { return $_[0]->_done } -sub is_pending { return !$_[0]->_done && $_[0]->_has__connection } -sub is_sleeping { return !$_[0]->_done && !$_[0]->_has__connection } - -sub set_pending_mode { - my ($self, $cont) = @_; - $self->_clear__connection; - $self->_clear__continue; - $self->_clear__postprocess; - $self->_clear_fileno; - if($cont) { - $self->_connection($cont->{connection}); - $self->_continue($cont->{continue}); - $self->_postprocess($cont->{postprocess}); - } - $self->_set_try($self->try + 1) if @_ > 1; - $self->_time(time); - return $self; -} - -sub set_sleeping_mode { - $_[0]->set_pending_mode; -} - -sub is_timeout { - my ($self, $timeout) = @_; - $timeout ||= $self->is_pending ? $self->timeout : $self->retry_delay; - return time() - $self->_time > $timeout; -} - -sub continue { - my ($self) = @_; - my $is_cont = 0; - my @list; - if (eval{@list = $self->_continue->($is_cont); 1}) { - if ($is_cont) { - $self->_clear_fileno; - $self->_connection($list[0]->{connection}); - $self->_continue($list[0]->{continue}); - $self->_time(time); - return 1; - } else { - $self->_done(1); - if (my $pp = $self->_postprocess) { - &$pp(\@list); - } - return \@list; - } - } - return 0; -} - -sub close { - my ($self, $reason) = @_; - $self->_connection->Close($reason) if $self->is_pending; - $self->set_sleeping_mode; -} - -sub DEMOLISH { - my ($self) = @_; - warn "$$ FORGOTTEN $self" if $self->is_pending; - #Carp::cluck "$$ FORGOTTEN $self" if $self->is_pending; -} - -no Mouse; -__PACKAGE__->meta->make_immutable(); - -1; diff --git a/connector/perl/lib/MR/Tarantool/Box.pm b/connector/perl/lib/MR/Tarantool/Box.pm index c0701dcfff6b02a8fe01f2bb073733cd0111f4be..0e8279f4f1c7f40512ffc001b75553017e8a8a67 100644 --- a/connector/perl/lib/MR/Tarantool/Box.pm +++ b/connector/perl/lib/MR/Tarantool/Box.pm @@ -79,7 +79,7 @@ use constant { sub IPROTOCLASS () { 'MR::IProto' } use vars qw/$VERSION %ERRORS/; -$VERSION = 0.0.21; +$VERSION = 0.0.11; BEGIN { *confess = \&MR::IProto::confess } @@ -194,14 +194,9 @@ Properly ordered arrayref of fields' numbers which are indexed. =item B<default_index> => $default_index_name_string_or_id_uint32 -Index C<id> or C<name> to be used by default for the current C<space> in B<select> operations. +Index C<id> or C<name> to be used by default for the current C<space>. Must be set if there are more than one C<\%index>es. -=item B<primary_key_index> => $primary_key_name_string_or_id_uint32 - -Index C<id> or C<name> to be used by default for the current C<space> in B<update> operations. -It is set to C<default_index> by default. - =back =item B<default_space> => $default_space_name_string_or_id_uint32 @@ -282,11 +277,9 @@ sub new { $self->{select_timeout} = $arg->{select_timeout} || $self->{timeout}; $self->{iprotoclass} = $arg->{iprotoclass} || $class->IPROTOCLASS; $self->{_last_error} = 0; - $self->{_last_error_msg} = ''; $self->{hashify} = $arg->{'hashify'} if exists $arg->{'hashify'}; $self->{default_raw} = $arg->{default_raw}; - $self->{default_raw} = 1 if !defined$self->{default_raw} and defined $self->{hashify} and !$self->{hashify}; $arg->{spaces} = $arg->{namespaces} = [@{ $arg->{spaces} ||= $arg->{namespaces} || confess "no spaces given" }]; confess "no spaces given" unless @{$arg->{spaces}}; @@ -326,20 +319,15 @@ sub new { if( @{$ns->{indexes}} > 1 ) { confess "space[$namespace] default_index not given" unless defined $ns->{default_index}; confess "space[$namespace] default_index $ns->{default_index} does not exist" unless $inames->{$ns->{default_index}}; - $ns->{primary_key_index} = $ns->{default_index} unless defined $ns->{primary_key_index}; - confess "space[$namespace] primary_key_index $ns->{primary_key_index} does not exist" unless $inames->{$ns->{primary_key_index}}; } else { $ns->{default_index} ||= 0; - $ns->{primary_key_index} ||= 0; } - $ns->{fields} ||= $arg->{default_fields}; if($ns->{fields}) { confess "space[$namespace] fields must be ARRAYREF" unless ref $ns->{fields} eq 'ARRAY'; confess "space[$namespace] fields number must match format" if @{$ns->{fields}} != @f; m/^[A-Za-z]/ or confess "space[$namespace] fields names must begin with [A-Za-z]: bad name $_" for @{$ns->{fields}}; $ns->{fields_hash} = { map { $ns->{fields}->[$_] => $_ } 0..$#{$ns->{fields}} }; } - $ns->{default_raw} = 1 if !defined$ns->{default_raw} and defined $ns->{hashify} and !$ns->{hashify}; } $self->{namespaces} = \%namespaces; if (@{$arg->{spaces}} > 1) { @@ -371,8 +359,6 @@ sub _connect { name => $self->{name}, debug => $self->{'ipdebug'}, dump_no_ints => 1, - max_request_retries => 1, - retry_delay => $self->{retry_delay}, }); } @@ -419,83 +405,48 @@ sub _chat { my $soft_retry = $self->{softretry}; my $retry_count = 0; - my $callback = delete $param{callback}; - my $return_fh = delete $param{return_fh}; - my $_cb = $callback || $return_fh; - - die "Can't use raise and callback together" if $callback && $self->{raise}; - - my $is_retry = sub { - my ($data) = @_; + while ($retry > 0) { $retry_count++; - if($data) { - my ($ret_code, $data, $full_code) = @$data; - return 0 if $ret_code->[0] == 0; - # retry if error is soft even in case of update e.g. ROW_LOCK - if ($ret_code->[0] == 1 and --$soft_retry > 0) { - --$retry if $retry > 1; - return 1; - } - } - return 1 if --$retry; - return 0; - }; - my $message; - my $process = sub { - my ($data, $error) = @_; - my $errno = $!; - if (!$error && $data) { - my ($ret_code, $data, $full_code) = @$data; + $self->{_last_error} = 0x77777777; + $self->{server}->SetTimeout($timeout); + my $ret = $self->{server}->Chat1(%param); + my $message; + if (exists $ret->{ok}) { + my ($ret_code, $data, $full_code) = @{$ret->{ok}}; $self->{_last_error} = $full_code; - $self->{_last_error_msg} = $message = $ret_code->[0] == 0 ? "" : sprintf "Error %08X: %s", $full_code, $$data || $ERRORS{$full_code & 0xFFFFFF00} || 'Unknown error'; - $self->_debug("$self->{name}: $message") if $ret_code->[0] != 0 && $self->{debug} >= 1; - if ($ret_code->[0] == 0) { my $ret = $orig_unpack->($$data,$ret_code->[2]); confess __LINE__."$self->{name}: [common]: Bad response (more data left)" if length $$data > 0; - return $ret unless $_cb; - return &$_cb($ret); + return $ret; } + $self->{_last_error_msg} = $message = $ret_code->[0] == 0 ? "ok" : sprintf "Error %08X: %s", $full_code, $$data || $ERRORS{$full_code & 0xFFFFFF00} || 'Unknown error'; + $self->_debug("$self->{name}: $message") if $self->{debug} >= 1; if ($ret_code->[0] == 2) { #fatal error $self->_raise($message) if $self->{raise}; - return 0 unless $_cb; - return &$_cb(0, $error); + return 0; + } + + # retry if error is soft even in case of update e.g. ROW_LOCK + if ($ret_code->[0] == 1 and --$soft_retry > 0) { + --$retry if $retry > 1; + sleep $self->{retry_delay}; + next; } } else { # timeout has caused the failure if $ret->{timeout} $self->{_last_error} = 'fail'; - $message ||= $self->{_last_error_msg} = $error; + $message ||= $self->{_last_error_msg} = $ret->{fail}; $self->_debug("$self->{name}: $message") if $self->{debug} >= 1; - $self->_raise("$self->{name}: no success after $retry_count tries: $message\n") if $self->{raise}; - return 0 unless $_cb; - return &$_cb(0, $error); } - }; - if ($callback) { - $self->{_last_error} = 0x77777777; - $self->{server}->SetTimeout($timeout); - return 1 if eval { $self->{server}->send({%param, is_retry => $is_retry, max_request_retries => $retry}, $process); 1 }; - return 0; - } - - $param{continue} = $process if $return_fh; - - my $ret; - while ($retry > 0) { - $self->{_last_error} = 0x77777777; - $self->{server}->SetTimeout($timeout); + last unless --$retry; - $ret = $self->{server}->Chat1(%param); - return $ret->{ok} if $param{continue} && $ret->{ok}; - last unless &$is_retry($ret->{ok}); sleep $self->{retry_delay}; }; - $self->_raise("no success after $retry_count tries\n") if $self->{raise} && !$ret->{ok}; - return &$process($ret->{ok}, $ret->{fail}); + $self->_raise("no success after $retry_count tries\n") if $self->{raise}; } sub _raise { @@ -510,7 +461,6 @@ sub _validate_param { my %pnames = map { $_ => 1 } @pnames; $pnames{space} = 1; $pnames{namespace} = 1; - $pnames{callback} = 1; foreach my $pname (keys %$param) { confess "$self->{name}: unknown param $pname\n" unless exists $pnames{$pname}; } @@ -520,7 +470,7 @@ sub _validate_param { confess "$self->{name}: bad space `$param->{namespace}'" unless exists $self->{namespaces}->{$param->{namespace}}; my $ns = $self->{namespaces}->{$param->{namespace}}; - $param->{use_index} = $pnames{use_index} ? $ns->{default_index} : $ns->{primary_key_index} unless defined $param->{use_index}; + $param->{use_index} = $ns->{default_index} unless defined $param->{use_index}; confess "$self->{name}: bad index `$param->{use_index}'" unless exists $ns->{index_names}->{$param->{use_index}}; $param->{index} = $ns->{index_names}->{$param->{use_index}}; @@ -622,11 +572,11 @@ The difference between them is the behaviour concerning tuple with the same prim =item * -B<Add> will succeed if and only if duplicate-key tuple B<does not exist> +B<Add> will succeed if and only if duplicate-key tuple B<does not exist> =item * -B<Replace> will succeed if and only if a duplicate-key tuple B<exists> +B<Replace> will succeed if and only if a duplicate-key tuple B<exists> =item * @@ -692,27 +642,17 @@ sub Insert { $self->_debug("$self->{name}: INSERT[${\join ' ', map {join' ',unpack'(H2)*',$_} @tuple}]") if $self->{debug} >= 4; - my $cb = sub { - my ($r) = @_; - - if($param->{want_result}) { - $self->_PostSelect($r, $param, $namespace); - $r = $r && $r->[0]; - } - - return $param->{callback}->($r) if $param->{callback}; - return $r; - }; - my $r = $self->_chat ( msg => 13, payload => pack("LLL (w/a*)*", $namespace->{namespace}, $flags, scalar(@tuple), @tuple), unpack => sub { $self->_unpack_affected($flags, $namespace, @_) }, - callback => $param->{callback} && $cb, + callback => $param->{callback}, ) or return; - return 1 if $param->{callback}; - return $cb->($r); + return $r unless $param->{want_result}; + + $self->_PostSelect($r, $param, $namespace); + return $r->[0]; } sub _unpack_select { @@ -809,7 +749,7 @@ sub _PackSelect { @$_{qw/field offset length/} } @{$param->{format}}; } - return pack("LLLL a* La*", $namespace->{namespace}, $param->{index}->{id}, $param->{offset} || 0, $param->{limit} || ($param->{default_limit_by_keys} ? scalar(@keys) : 0x7FFFFFFF), $format, scalar(@keys), join('',@keys)); + return pack("LLLL a* La*", $namespace->{namespace}, $param->{index}->{id}, $param->{offset} || 0, $param->{limit} || scalar(@keys), $format, scalar(@keys), join('',@keys)); } sub _PostSelect { @@ -833,13 +773,13 @@ Select tuple(s) from storage my $key = $id; my $key = [ $firstname, $lastname ]; my @keys = ($key, ...); - + my $tuple = $box->Select($key) or $box->Error && die $box->ErrorStr; my $tuple = $box->Select($key, \%options) or $box->Error && die $box->ErrorStr; - + my @tuples = $box->Select(@keys) or $box->Error && die $box->ErrorStr; my @tuples = $box->Select(@keys, \%options) or $box->Error && die $box->ErrorStr; - + my $tuples = $box->Select(\@keys) or die $box->ErrorStr; my $tuples = $box->Select(\@keys, \%options) or die $box->ErrorStr; @@ -894,10 +834,6 @@ Specify storage (by id or name) space to select from. Specify index (by id or name) to use. -=item B<limit> => $limit_uint32 - -Max tuples to select. It is set to C<< MAX_INT32 >> by default. - =item B<raw> => $bool Don't C<hashify> (see L</new>). @@ -915,7 +851,7 @@ C<False> will be returned in case of error. =cut -my @select_param_ok = qw/use_index raw want next_rows limit offset raise hashify timeout format hash_by callback return_fh default_limit_by_keys/; +my @select_param_ok = qw/use_index raw want next_rows limit offset raise hashify timeout format hash_by/; sub Select { confess q/Select isnt callable in void context/ unless defined wantarray; my ($param, $namespace) = $_[0]->_validate_param(\@_, @select_param_ok); @@ -939,70 +875,45 @@ sub Select { local $namespace->{unpack_format} = $param->{unpack_format} if $param->{unpack_format}; my $r = []; - - $param->{want} ||= !1; - my $wantarray = wantarray; - - my $cb = sub { - my ($r) = (@_); - - $self->_PostSelect($r, $param, $namespace) if $r; - - if ($r && defined(my $p = $param->{hash_by})) { - my %h; - if (@$r) { - if (ref $r->[0] eq 'HASH') { - confess "Bad hash_by `$p' for HASH" unless exists $r->[0]->{$p}; - $h{$_->{$p}} = $_ for @$r; - } elsif (ref $r->[0] eq 'ARRAY') { - confess "Bad hash_by `$p' for ARRAY" unless $p =~ m/^\d+$/ && $p >= 0 && $p < @{$r->[0]}; - $h{$_->[$p]} = $_ for @$r; - } else { - confess "i dont know how to hash_by ".ref($r->[0]); - } - } - $r = \%h; - } - - if ($param->{callback}) { - return $param->{callback}->($r); - } - - if ($param->{return_fh} && ref $param->{return_fh} eq 'CODE') { - return $param->{return_fh}->($r); - } - - return unless $r; - - return $r if defined $param->{hash_by}; - return $r if $param->{want} eq 'arrayref'; - $wantarray = wantarray if $param->{return_fh}; - - if ($wantarray) { - return @{$r}; - } else { - confess "$self->{name}: too many keys in scalar context" if @keys > 1; - return $r->[0]; - } - }; - if (@keys && $payload) { $r = $self->_chat( msg => $msg, payload => $payload, unpack => sub { $self->_unpack_select($namespace, "SELECT", @_) }, - retry => $param->{return_fh} ? 1 : $self->{select_retry}, + retry => $self->{select_retry}, timeout => $param->{timeout} || $self->{select_timeout}, - callback => $param->{callback} ? $cb : 0, - return_fh=> $param->{return_fh} ? $cb : 0, + callback => $param->{callback}, ) or return; - return $r if $param->{return_fh}; - return 1 if $param->{callback}; - } else { - $r = []; } - return $cb->($r); + $param->{want} ||= !1; + + $self->_PostSelect($r, $param, $namespace); + + if(defined(my $p = $param->{hash_by})) { + my %h; + if(@$r) { + if (ref $r->[0] eq 'HASH') { + confess "Bad hash_by `$p' for HASH" unless exists $r->[0]->{$p}; + $h{$_->{$p}} = $_ for @$r; + } elsif(ref $r->[0] eq 'ARRAY') { + confess "Bad hash_by `$p' for ARRAY" unless $p =~ m/^\d+$/ && $p >= 0 && $p < @{$r->[0]}; + $h{$_->[$p]} = $_ for @$r; + } else { + confess "i dont know how to hash_by ".ref($r->[0]); + } + } + return \%h; + } + + return $r if $param->{want} eq 'arrayref'; + + if (wantarray) { + return @{$r}; + } else { + confess "$self->{name}: too many keys in scalar context" if @keys > 1; + return $r->[0]; + } } sub SelectUnion { @@ -1046,7 +957,7 @@ Delete tuple from storage. Return false upon error. my $n_deleted = $box->Delete($key) or die $box->ErrorStr; my $n_deleted = $box->Delete($key, \%options) or die $box->ErrorStr; warn "Nothing was deleted" unless int $n_deleted; - + my $deleted_tuple_set = $box->Delete($key, { want_deleted_tuples => 1 }) or die $box->ErrorStr; warn "Nothing was deleted" unless @$deleted_tuple_set; @@ -1084,27 +995,17 @@ sub Delete { confess "$self->{name}\->Delete: for now key cardinality of 1 is only allowed" unless 1 == @{$param->{index}->{keys}}; $self->_pack_keys($namespace, $param->{index}, $key); - my $cb = sub { - my ($r) = @_; - - if($param->{want_result}) { - $self->_PostSelect($r, $param, $namespace); - $r = $r && $r->[0]; - } - - return $param->{callback}->($r) if $param->{callback}; - return $r; - }; - my $r = $self->_chat( msg => $flags ? 21 : 20, payload => $flags ? pack("L L a*", $namespace->{namespace}, $flags, $key) : pack("L a*", $namespace->{namespace}, $key), unpack => sub { $self->_unpack_affected($flags, $namespace, @_) }, - callback => $param->{callback} && $cb, + callback => $param->{callback}, ) or return; - return 1 if $param->{callback}; - return $cb->($r); + return $r unless $param->{want_result}; + + $self->_PostSelect($r, $param, $namespace); + return $r->[0]; } sub OP_SET () { 0 } @@ -1168,11 +1069,11 @@ BEGIN { Apply several update operations to a tuple. my @op = ([ f1 => add => 10 ], [ f1 => and => 0xFF], [ f2 => set => time() ], [ misc_string => cutend => 3 ]); - + my $n_updated = $box->UpdateMulti($key, @op) or die $box->ErrorStr; my $n_updated = $box->UpdateMulti($key, @op, \%options) or die $box->ErrorStr; warn "Nothing was updated" unless int $n_updated; - + my $updated_tuple_set = $box->UpdateMulti($key, @op, { want_result => 1 }) or die $box->ErrorStr; warn "Nothing was updated" unless @$updated_tuple_set; @@ -1217,7 +1118,7 @@ Append or prepend C<< $field >> with C<$value> string. Cut C<< $value >> bytes from beginning or end of C<< $field >>. -=back +=back =back @@ -1241,7 +1142,7 @@ sub UpdateMulti { my ($param, $namespace) = $_[0]->_validate_param(\@_, qw/want_updated_tuple want_result _flags raw/); my ($self, $key, @op) = @_; - $self->_debug("$self->{name}: UPDATEMULTI(NS:$namespace->{namespace},KEY:$key)[@{[map{$_?qq{[@$_]}:q{-}}@op]}]") if $self->{debug} >= 3; + $self->_debug("$self->{name}: UPDATEMULTI(NS:$namespace->{namespace},KEY:$key)[@{[map{qq{[@$_]}}@op]}]") if $self->{debug} >= 3; confess "$self->{name}\->UpdateMulti: for now key cardinality of 1 is only allowed" unless 1 == @{$param->{index}->{keys}}; confess "$self->{name}: too many op" if scalar @op > 128; @@ -1296,27 +1197,17 @@ sub UpdateMulti { $self->_pack_keys($namespace, $param->{index}, $key); - my $cb = sub { - my ($r) = @_; - - if($param->{want_result}) { - $self->_PostSelect($r, $param, $namespace); - $r = $r && $r->[0]; - } - - return $param->{callback}->($r) if $param->{callback}; - return $r; - }; - my $r = $self->_chat( msg => 19, payload => pack("LL a* L (a*)*" , $namespace->{namespace}, $flags, $key, scalar(@op), @op), unpack => sub { $self->_unpack_affected($flags, $namespace, @_) }, - callback => $param->{callback} && $cb, + callback => $param->{callback}, ) or return; - return 1 if $param->{callback}; - return $cb->($r); + return $r unless $param->{want_result}; + + $self->_PostSelect($r, $param, $namespace); + return $r->[0]; } sub Update { @@ -1365,52 +1256,6 @@ sub Num { $self->UpdateMulti($key, @op, $param); } -=head2 AnyEvent - -C<< Insert, UpdateMulti, Select, Delete, Call >> methods can be given the following options: - -=over - -=item B<callback> => sub { my ($data, $error) = @_; } - -Do an async request using AnyEvent. -C<< $data >> contains unpacked and processed according to request options data. -C<< $error >> contains a message string in case of error. -Set up C<< raise => 0 >> to use this option. - -=back - -=head2 "Continuations" - -C<< Select >> methods can be given the following options: - -=over - -=item B<return_fh> => 1 - -The request does only send operation on network, and returns -C<< { fh => $IO_Handle, continue => $code } >> or false if send operation failed. -C<< $code >> reads data from network, unpacks, processes according to options and returns it. - -You should handle timeouts and retries manually (using select() call for example). -Usage example: - - my $continuation = $box->Select(13,{ return_fh => 1 }); - ok $continuation, "select/continuation"; - - my $rin = ''; - vec($rin,$continuation->{fh}->fileno,1) = 1; - my $ein = $rin; - ok 0 <= select($rin,undef,$ein,2), "select/continuation/select"; - - my $res = $continuation->{continue}->(); - use Data::Dumper; - is_deeply $res, [13, 'some_email@test.mail.ru', 1, 2, 3, 4, '123456789'], "select/continuation/result"; - -=back - - - =head1 LICENCE AND COPYRIGHT This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. diff --git a/connector/perl/lib/MR/Tarantool/Box/Singleton.pm b/connector/perl/lib/MR/Tarantool/Box/Singleton.pm index 9d4f72d42962b963cb0961deae135c1e7d4d45ba..3d106a1f800efd2c6ea7a805c9b071638d32ad72 100644 --- a/connector/perl/lib/MR/Tarantool/Box/Singleton.pm +++ b/connector/perl/lib/MR/Tarantool/Box/Singleton.pm @@ -322,12 +322,17 @@ sub _new_instance { $config->{servers} ||= $class->SERVER; $config->{param}->{name} ||= $class; - $config->{param}->{spaces} ||= $class->SPACES; - $config->{param}->{default_fields} ||= [ $class->FIELDS ] if $class->can('FIELDS'); + + $config->{param}->{spaces} ||= my $sp = $class->SPACES; + $config->{param}->{default_space} ||= my $defsp = @$sp == 1 ? 0 : $class->DEFAULT_SPACE; + + $sp->[$defsp]->{fields} ||= [ $class->FIELDS ] if $class->can('FIELDS'); $config->{param}->{raise} = $class->RAISE unless defined $config->{param}->{raise}; + $config->{param}->{timeout} ||= $class->TIMEOUT; $config->{param}->{select_timeout} ||= $class->SELECT_TIMEOUT; + $config->{param}->{debug} ||= $class->DEBUG; $config->{param}->{ipdebug} ||= $class->IPDEBUG; @@ -336,19 +341,17 @@ sub _new_instance { $config->{param}->{softretry} ||= $class->SOFT_RETRY; $config->{param}->{retry_delay} ||= $class->RETRY_DELAY; + $config->{param}->{fields} ||= [ $class->FIELDS ]; + my $replicas = delete $config->{replicas} || $class->REPLICAS || []; $replicas = [ split /,/, $replicas ] unless ref $replicas eq 'ARRAY'; - $class->CheckConfig($config); - return bless { box => $class->MR_TARANTOOL_BOX_CLASS->new({ servers => $config->{servers}, %{$config->{param}} }), replicas => [ map { $class->MR_TARANTOOL_BOX_CLASS->new({ servers => $_, %{$config->{param}} }) } shuffle @$replicas ], }, $class; } -sub CheckConfig {} - =pod =head3 Add, Insert, Replace, UpdateMulti, Delete diff --git a/connector/perl/t/box.pl b/connector/perl/t/box.pl index bb6941ffc675b5de9758638f0202c1f81654e410..b9e4f854def6c1200f94e21f27cd2b734d874193 100644 --- a/connector/perl/t/box.pl +++ b/connector/perl/t/box.pl @@ -13,7 +13,7 @@ use FindBin qw($Bin); use lib "$Bin"; use Carp qw/confess/; -use Test::More tests => 339; +use Test::More tests => 233; use Test::Exception; use List::MoreUtils qw/zip/; @@ -28,17 +28,10 @@ use constant TUPLE_NOT_EXISTS => qr/Error 00003102/; use constant TUPLE_EXISTS => qr/Error 00003702/; use constant INDEX_VIOLATION => qr/Error 00003802/; -use constant NO_SUCCESS => qr/no success after/; - use constant TOO_BIG_FIELD => qr/too big field/; -our $box; -our $server = (shift || $ENV{BOX}) or die; -our %opts = ( - debug => $ENV{DEBUG}||0, - ipdebug => $ENV{IPDEBUG}||0, - raise => 1, -); +my $box; +my $server = (shift || $ENV{BOX}) or die; sub cleanup ($) { my ($id) = @_; @@ -65,7 +58,6 @@ sub def_param { name => 'main', } ], default_space => "main", - %opts, } } @@ -163,367 +155,6 @@ ok $box->Replace(13, q/some_email@test.mail.ru/, 1, 2, 3, 4, '123456789'), 'repl is_deeply scalar $box->Select(13), [13, 'some_email@test.mail.ru', 1, 2, 3, 4, '123456789'], 'select/replace'; -is_deeply [$box->Select([13], {raise => 0, hash_by => 0, raw => 1})], [{13 => [13, 'some_email@test.mail.ru', 1, 2, 3, 4, '123456789']}], 'select/rawhash1'; -is_deeply [$box->Select([13,14], {raise => 0, hash_by => 0, raw => 1})], [{13 => [13, 'some_email@test.mail.ru', 1, 2, 3, 4, '123456789'], 14 => [14, 'some1email@test.mail.ru', 1, 2, 3, 4, '123456789']}], 'select/rawhash2'; - - -do { - my $continuation = $box->Select(13,{ return_fh => 1 }); - ok $continuation, "select/continuation"; - - my $rin = ''; - vec($rin,$continuation->{fh}->fileno,1) = 1; - my $ein = $rin; - ok 0 <= select($rin,undef,$ein,2), "select/continuation/select"; - - my $res = $continuation->{continue}->(); - use Data::Dumper; - is_deeply $res, [13, 'some_email@test.mail.ru', 1, 2, 3, 4, '123456789'], "select/continuation/result"; -}; - -our $ANYEVENT = 1 && eval { require AnyEvent; 1 }; -SKIP:{ - skip "AnyEvent not found", 60 unless $ANYEVENT; - - local $opts{raise} = 0; - $box = $CLASS->new(def_param('l&SSLL&')); - - my $tt = [ [1, 'rtokarev@corp.mail.ru', 11, 111, 1111, 11111, "1111111111111"], - [2, 'vostrikov@corp.mail.ru', 22, 222, 2222, 22222, "2222222222222"], - [3, 'aleinikov@corp.mail.ru', 33, 333, 3333, 33333, "3333333333333"], - [4, 'roman.s.tokarev@gmail.com', 44, 444, 4444, 44444, "4444444444444"], - [5, 'vostrIIIkov@corp.mail.ru', 55, 555, 5555, 55555, "5555555555555"] ]; - - foreach my $tuple (@$tt) { - cleanup $tuple->[0]; - } - - AnyEvent->now_update; - my $cv = AnyEvent->condvar; - foreach my $tuple (@$tt) { - $cv->begin; - ok $box->Insert(@$tuple, {callback => sub { ok $_[0], "async/insert$tuple->[0]/result"; $cv->end; }}), "async/insert$tuple->[0]"; - } - $cv->recv; - - - AnyEvent->now_update; - $cv = AnyEvent->condvar; - $cv->begin; - ok $box->Select(1,2,3,{callback => sub { - my ($res) = @_; - $cv->end; - is_deeply $res, [@$tt[0,1,2]], "async/select1/result"; - }}), "async/select1"; - - $cv->begin; - ok $box->Select(4,5,{ callback => sub { - my ($res) = @_; - $cv->end; - is_deeply $res, [@$tt[3,4]], "async/select2/result"; - }}), "async/select2"; - - $cv->recv; - - - AnyEvent->now_update; - $cv = AnyEvent->condvar; - foreach my $tuple (@$tt) { - $tuple->[4] += 10000; - $cv->begin; - ok $box->UpdateMulti($tuple->[0], [ 4 => add => 10000 ], {callback => sub { ok $_[0], "async/update1-$tuple->[0]/result"; $cv->end; }}), "async/update1-$tuple->[0]"; - } - $cv->begin; - ok $box->Select((map{$_->[0]}@$tt),{ callback => sub { - my ($res) = @_; - $cv->end; - is_deeply $res, $tt, "async/update1-select/result"; - }}), "async/update1-select"; - $cv->recv; - - AnyEvent->now_update; - $cv = AnyEvent->condvar; - foreach my $tuple (@$tt) { - $tuple->[4] += 10000; - $cv->begin; - ok $box->UpdateMulti($tuple->[0], [ 4 => add => 10000 ], {want_result => 1, callback => sub { is_deeply $_[0], $tuple, "async/update2-$tuple->[0]/result"; $cv->end; }}), "async/update2-$tuple->[0]"; - } - $cv->begin; - ok $box->Select((map{$_->[0]}@$tt),{ callback => sub { - my ($res) = @_; - $cv->end; - is_deeply $res, $tt, "async/update2-select/result"; - }}), "async/update2-select"; - $cv->recv; - - AnyEvent->now_update; - $cv = AnyEvent->condvar; - foreach my $tuple (@$tt) { - $cv->begin; - ok $box->Delete($tuple->[0], {want_result => 1, callback => sub { is_deeply $_[0], $tuple, "async/delete-$tuple->[0]/result"; $cv->end; }}), "async/delete-$tuple->[0]"; - } - $cv->begin; - ok $box->Select((map{$_->[0]}@$tt),{ callback => sub { - my ($res) = @_; - $cv->end; - is_deeply $res, [], "async/delete-select/result"; - }}), "async/delete-select"; - $cv->recv; -} - -sub countwarn { - my ($qr, $counter) = @_; - return sub { - ++$$counter if $_[0] =~ $qr; - warn @_; - }; -}; - -do { - local $server = "127.0.0.1:1111"; - local $opts{raise} = 0; - my $try = 3; - - my $counter = 0; - local $SIG{__WARN__} = countwarn(qr/refused/i, \$counter); - - my $box = $CLASS->new(def_param('l&SSLL&')); - - throws_ok sub{my$x=$box->Select(13,{ want => "arrayref", raise => 1 })}, NO_SUCCESS, "reject/select/raise/sync"; - ok $counter == $try, "reject/select/raise/sync/counter"; - $counter = 0; - - ok !$box->Select(13,{ want => "arrayref", raise => 0 }), "reject/select/noraise/sync"; - ok $counter == $try, "reject/select/noraise/sync/counter"; - $counter = 0; - - my $continuation = $box->Select(13,{ return_fh => 1, raise => 0 }); - ok !$continuation, "reject/select/continuation"; - ok $counter == 1, "reject/select/continuation/counter"; - $counter = 0; - - - SKIP:{ - skip "AnyEvent not found", 5 unless $ANYEVENT; - - AnyEvent->now_update; - my $cv = AnyEvent->condvar; - $cv->begin; - ok $box->Select(4,5,{ callback => sub { - my ($res) = @_; - $cv->end; - ok !$res, "reject/select/async/noraise/cb"; - ok $box->Error, "reject/select/async/noraise/cb/error"; - ok $box->ErrorStr, "reject/select/async/noraise/cb/errorstr"; - }}), "reject/select/async/noraise"; - - $cv->recv; - ok $counter == $try, "reject/select/async/noraise/counter"; - $counter = 0; - } -}; - -do { - my $pid; - local $SIG{INT} = $SIG{TERM} = sub { kill 'TERM', $pid }; - - $pid = fork(); - die unless defined $pid; - unless($pid) { - $0 = "$0 <SERVER>"; - my $stop = 0; - my $h; - my $l = IO::Socket::INET->new( - LocalAddr => '127.0.0.1', - LocalPort => 1111, - Proto => 'tcp', - Listen => 10, - Blocking => 1, - ReuseAddr => 1, - ) or die $!; - $SIG{INT} = $SIG{TERM} = sub { ++$stop; close $l; close $h; exit; }; - while(!$stop) { - $h = $l->accept; - my $data; - while($h->read($data,1024) > 0) { 0; } - close $h; - } - exit; - } - - - local $server = "127.0.0.1:1111"; - local $opts{raise} = 0; - local $opts{timeout} = 0.1; - local $opts{select_timeout} = 0.1; - - my $try = 3; - - my $counter = 0; - local $SIG{__WARN__} = countwarn(qr/timed? ?out/i, \$counter); - - my $box = $CLASS->new(def_param('l&SSLL&')); - - sleep 1; - - throws_ok sub{my$x=$box->Select(13,{ want => "arrayref", raise => 1 })}, NO_SUCCESS, "timeout1/select/raise/sync"; - ok $counter == $try, "timeout1/select/raise/sync/counter"; - $counter = 0; - - ok !$box->Select(13,{ want => "arrayref", raise => 0 }), "timeout1/select/noraise/sync"; - ok $counter == $try, "/counter"; - $counter = 0; - - my $continuation = $box->Select(13,{ return_fh => 1, raise => 0 }); - ok $continuation, "timeout1/select/continuation"; - ok !$continuation->{continue}->(), "timeout1/select/continuation/result"; - ok $counter == 1, "timeout1/select/continuation/counter"; - $counter = 0; - - - SKIP:{ - skip "AnyEvent not found", 5 unless $ANYEVENT; - - AnyEvent->now_update; - my $cv = AnyEvent->condvar; - $cv->begin; - ok $box->Select(4,5,{ callback => sub { - my ($res) = @_; - $cv->end; - ok !$res, "timeout1/select/async/noraise/cb"; - ok $box->Error, "timeout1/select/async/noraise/cb/error"; - ok $box->ErrorStr, "timeout1/select/async/noraise/cb/errorstr"; - }}), "timeout1/select/async/noraise"; - - $cv->recv; - ok $counter == $try, "timeout1/select/async/noraise/counter"; - $counter = 0; - } - - kill 'TERM', $pid; -}; - -do { - my $pid; - local $SIG{INT} = $SIG{TERM} = sub { kill 'TERM', $pid }; - - $pid = fork(); - die unless defined $pid; - unless($pid) { - $0 = "$0 <SERVER>"; - my $stop = 0; - my $h; - my @ok = (0,0,1,0,0,1,1,0,0,1); - my $l = IO::Socket::INET->new( - LocalAddr => '127.0.0.1', - LocalPort => 1111, - Proto => 'tcp', - Listen => 10, - Blocking => 1, - ReuseAddr => 1, - ) or die $!; - my ($host, $port) = split /:/, $server; - my $box = IO::Socket::INET->new( - PeerAddr => $host, - PeerPort => $port, - Proto => 'tcp', - Blocking => 1, - ) or die; - $SIG{INT} = $SIG{TERM} = sub { ++$stop; close $l; close $h; close $box; exit; }; - - while(!$stop) { - $h = $l->accept; - $h->blocking(1); - my $data = ''; - if (shift @ok) { - while(!$stop) { - $h->blocking(0); - $h->read($data,1024,length$data); - if(length$data) { - $h->blocking(1); - $h->read($data,12-length$data,length$data) while length $data < 12; - my ($len) = unpack 'x4L', $data; - $h->read($data,12+$len-length$data,length$data) while length $data < 12+$len; - $box->write($data); - - $data = ''; - $box->read($data,12-length$data, length$data) while length $data < 12; - ($len) = unpack 'x4L', $data; - $box->read($data,12+$len-length$data,length$data) while length $data < 12+$len; - $h->write($data); - close $h; - last; - } - sleep 0.1; - } - } else { - while($h->read($data,1024) > 0) { 0; } - } - close $h; - } - close $l; - close $box; - exit; - } - - - local $server = "127.0.0.1:1111"; - local $opts{raise} = 0; - local $opts{timeout} = 0.1; - local $opts{select_timeout} = 0.1; - - my $try = 2; - - my $counter = 0; - local $SIG{__WARN__} = countwarn(qr/timed? ?out/i, \$counter); - - my $box = $CLASS->new(def_param('l&SSLL&')); - - sleep 1; - - is_deeply $box->Select(13,{ want => "arrayref", raise => 1 }), [[13, 'some_email@test.mail.ru', 1, 2, 3, 4, '123456789']], "timeout2/select/raise/sync"; - ok !$box->Error, "timeout2/select/raise/sync/error"; - ok !$box->ErrorStr, "timeout2/select/raise/sync/errorstr"; - ok $counter == $try, "timeout2/select/raise/sync/counter"; - $counter = 0; - - is_deeply $box->Select(13,{ want => "arrayref", raise => 0 }), [[13, 'some_email@test.mail.ru', 1, 2, 3, 4, '123456789']], "timeout2/select/noraise/sync"; - ok !$box->Error, "timeout2/select/noraise/sync/error"; - ok !$box->ErrorStr, "timeout2/select/noraise/sync/errorstr"; - ok $counter == $try, "timeout2/select/noraise/sync/counter"; - $counter = 0; - - my $continuation = $box->Select(13,{ return_fh => 1, raise => 0, want => 'arrayref' }); - ok $continuation, "timeout2/select/continuation"; - is_deeply $continuation->{continue}->(), [[13, 'some_email@test.mail.ru', 1, 2, 3, 4, '123456789']], "timeout2/select/continuation/result"; - ok !$box->Error, "timeout2/select/continuation/error"; - ok !$box->ErrorStr, "timeout2/select/continuation/errorstr"; - ok $counter == 0, "timeout2/select/continuation/counter"; - $counter = 0; - - - SKIP:{ - skip "AnyEvent not found", 5 unless $ANYEVENT; - - AnyEvent->now_update; - my $cv = AnyEvent->condvar; - $cv->begin; - ok $box->Select(13,{ callback => sub { - my ($res) = @_; - $cv->end; - is_deeply $res, [[13, 'some_email@test.mail.ru', 1, 2, 3, 4, '123456789']], "timeout2/select/async/noraise/cb"; - ok !$box->Error, "timeout2/select/async/noraise/cb/error"; - ok !$box->ErrorStr, "timeout2/select/async/noraise/cb/errorstr"; - }}), "timeout2/select/async/noraise"; - - $cv->recv; - ok $counter == $try, "timeout2/select/async/noraise/counter"; - $counter = 0; - } - - kill 'TERM', $pid; -}; - $box = $CLASS->new(def_param); ok $box->isa($CLASS), 'connect'; @@ -784,9 +415,7 @@ sub def_param1 { namespace => 26, format => $format, default_index => 'primary_num1', - } ], - %opts, - } + } ]} } $box = $CLASS->new(def_param1); @@ -829,9 +458,7 @@ sub def_param_bad { namespace => 26, format => $format, default_index => 'primary_num1', - } ], - %opts, - } + } ]} } $box = $CLASS->new(def_param_bad); @@ -866,9 +493,7 @@ sub def_param_unique { space => 27, format => $format, default_index => 'id', - } ], - %opts, - } + } ]} } $box = $CLASS->new(def_param_unique); @@ -962,7 +587,7 @@ sub def_param_u64 { format => $format, default_index => 'id', } ], - %opts, + debug => 0, } } diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index fb753cf491c9721c6897d53fab979f44b89a9c05..331d9e9f600f32b41cfecf0a4c5fb348236f356b 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -48,9 +48,6 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E touch_nocreate # set_property(DIRECTORY PROPERTY CLEAN_NO_CUSTOM 1) -set_source_files_properties(cpu_feature.m - PROPERTIES COMPILE_FLAGS "-msse3 -msse4") - # # Used by modules. # @@ -64,7 +61,7 @@ set (recompiled_core_sources ${CMAKE_SOURCE_DIR}/core/fiber.m PARENT_SCOPE) set (common_sources tbuf.m palloc.m util.m - salloc.m pickle.m coro.m stat.m log_io.m cpu_feature.m crc32.c + salloc.m pickle.m coro.m stat.m log_io.m cpu_feature.m log_io_remote.m iproto.m exception.m errcode.c errinj.m latch.m) if (ENABLE_TRACE) @@ -75,7 +72,7 @@ add_library(core STATIC ${common_sources}) add_dependencies(core generate_headers luajit) set_target_properties(core PROPERTIES COMPILE_FLAGS "${core_cflags}") -set (common_libraries cfg core ev coro gopt misc objc pthread rt) +set (common_libraries cfg core ev coro gopt misc objc) set (common_libraries ${common_libraries} ${LUAJIT_LIB}) if (TARGET_OS_LINUX) diff --git a/core/cpu_feature.m b/core/cpu_feature.m index e9d2f22f4713c5e79b0c2c58aeeae5f98ffb91da..b50db25dedc74c71dd1cbee2e5352b3f19e0b3e5 100644 --- a/core/cpu_feature.m +++ b/core/cpu_feature.m @@ -25,55 +25,210 @@ #include <sys/types.h> #include <errno.h> -#include <stdlib.h> -#if !defined (__x86_64__) && !defined (__i386__) - #error "Only x86 and x86_64 architectures supported" -#endif +#include "cpu_feature.h" -#ifndef __GNUC__ - #error This module uses GCC intrinsic header(s) and should be compiled using gcc. -#endif +#if defined (__i386__) || defined (__x86_64__) -/* GCC intrinsic headers */ -#include <cpuid.h> -#include <smmintrin.h> +enum { eAX=0, eBX, eCX, eDX }; -#include "cpu_feature.h" +static const struct cpuid_feature { + unsigned int ri; + u_int32_t bitmask; +} cpu_mask[] = { + {eDX, (1 << 28)}, /* HT */ + {eCX, (1 << 19)}, /* SSE 4.1 */ + {eCX, (1 << 20)}, /* SSE 4.2 */ + {eCX, (1 << 31)} /* HYPERV */ +}; +static const size_t LEN_cpu_mask = sizeof(cpu_mask) / sizeof (cpu_mask[0]); +#define SCALE_F sizeof(unsigned long) -u_int32_t -crc32c_hw(u_int32_t crc, const unsigned char *buf, unsigned int len) -{ -#define SCALE_F sizeof(unsigned long) - size_t nwords = len / SCALE_F, nbytes = len % SCALE_F; - unsigned long *pword; - unsigned char *pbyte; - - for (pword = (unsigned long *)buf; nwords--; ++pword) #if defined (__x86_64__) - crc = (u_int32_t)_mm_crc32_u64((u_int64_t)crc, *pword); + #define REX_PRE "0x48, " #elif defined (__i386__) - crc = _mm_crc32_u32(crc, *pword); + #define REX_PRE #endif - if (nbytes) - for (pbyte = (unsigned char*)pword; nbytes--; ++pbyte) - crc = _mm_crc32_u8(crc, *pbyte); + +/* Hw-calculate CRC32 per byte (for the unaligned portion of data buffer). */ +/* NOTE: the function below was adopted from Linux 2.6 kernel source tree, + licensed under GPL. */ +static u_int32_t +crc32c_hw_byte(u_int32_t crc, unsigned char const *data, size_t length) +{ + while (length--) { + __asm__ __volatile__( + ".byte 0xf2, 0xf, 0x38, 0xf0, 0xf1" + :"=S"(crc) + :"0"(crc), "c"(*data) + ); + data++; + } + + return crc; +} + + +/* Hw-calculate CRC32 for the given data buffer. */ +/* NOTE: the function below was adopted from Linux 2.6 kernel source tree, + licensed under GPL. */ +static u_int32_t +crc32c_hw_intel(u_int32_t crc, unsigned char const *buf, size_t len) +{ + unsigned int iquotient = len / SCALE_F; + unsigned int iremainder = len % SCALE_F; + unsigned long *ptmp = (unsigned long *)buf; + + while (iquotient--) { + __asm__ __volatile__( + ".byte 0xf2, " REX_PRE "0xf, 0x38, 0xf1, 0xf1;" + :"=S"(crc) + :"0"(crc), "c"(*ptmp) + ); + ptmp++; + } + + if (iremainder) { + crc = crc32c_hw_byte(crc, (unsigned char *)ptmp, + iremainder); + } return crc; } -bool -sse42_enabled_cpu() +/* Toggle x86 flag-register bits, as per mask. */ +static void +toggle_x86_flags(long mask, long* orig, long* toggled) { - unsigned int ax, bx, cx, dx; + long forig = 0, fres = 0; + +#if defined (__i386__) + asm ( + "pushfl; popl %%eax; movl %%eax, %0; xorl %2, %%eax; " + "pushl %%eax; popfl; pushfl; popl %%eax; pushl %0; popfl " + : "=r" (forig), "=a" (fres) + : "m" (mask) + ); +#elif __x86_64__ + asm ( + "pushfq; popq %%rax; movq %%rax, %0; xorq %2, %%rax; " + "pushq %%rax; popfq; pushfq; popq %%rax; pushq %0; popfq " + : "=r" (forig), "=a" (fres) + : "m" (mask) + ); +#endif + + if (orig) + *orig = forig; + if (toggled) + *toggled = fres; + return; +} - if (__get_cpuid(1 /* level */, &ax, &bx, &cx, &dx) == 0) - return 0; /* not supported */ - return (cx & (1 << 20)) != 0; +/* Is CPUID instruction available ? */ +static int +can_cpuid() +{ + long of = -1, tf = -1; + + /* x86 flag register masks */ + enum { + cpuf_AC = (1 << 18), /* bit 18 */ + cpuf_ID = (1 << 21) /* bit 21 */ + }; + + + /* Check if AC (alignment) flag could be toggled: + if not - it's i386, thus no CPUID. + */ + toggle_x86_flags(cpuf_AC, &of, &tf); + if ((of & cpuf_AC) == (tf & cpuf_AC)) { + return 0; + } + + /* Next try toggling CPUID (ID) flag. */ + toggle_x86_flags(cpuf_ID, &of, &tf); + if ((of & cpuf_ID) == (tf & cpuf_ID)) { + return 0; + } + + return 1; } +/* Retrieve CPUID data using info as the EAX key. */ +static void +get_cpuid(long info, long* eax, long* ebx, long* ecx, long *edx) +{ + *eax = info; + +#if defined (__i386__) + asm __volatile__ ( + "movl %%ebx, %%edi; " /* must save ebx for 32-bit PIC code */ + "cpuid; " + "movl %%ebx, %%esi; " + "movl %%edi, %%ebx; " + : "+a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx) + : + : "%edi" + ); +#elif defined (__x86_64__) + asm __volatile__ ( + "cpuid; " + : "+a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) + ); +#endif +} + + +/* Check whether CPU has a certain feature. */ +int +cpu_has(unsigned int feature) +{ + long info = 1, reg[4] = {0,0,0,0}; + + if (!can_cpuid()) + return -EINVAL; + + if (feature > LEN_cpu_mask) + return -ERANGE; + + get_cpuid(info, ®[eAX], ®[eBX], ®[eCX], ®[eDX]); + + return (reg[cpu_mask[feature].ri] & cpu_mask[feature].bitmask) ? 1 : 0; +} + + +u_int32_t +crc32c_hw(u_int32_t crc, const unsigned char *buf, unsigned int len) +{ + return crc32c_hw_intel (crc, (unsigned char const*)buf, len); +} + +#else /* other (yet unsupported architectures) */ + +int +cpu_has(unsigned int feature) +{ + (void)feature; + return EINVAL; +} + +u_int32_t +crc32c_hw(u_int32_t crc, const unsigned char *buf, unsigned int len) +{ + (void)crc; (void)buf, (void)len; + assert(false); + return 0; +} + + +#endif /* defined (__i386__) || defined (__x86_64__) */ + + +/* __EOF__ */ + diff --git a/core/crc32.c b/core/crc32.c deleted file mode 100644 index 1d77af49362ff98459aef4a50352a006e5ab298f..0000000000000000000000000000000000000000 --- a/core/crc32.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 <COPYRIGHT HOLDER> ``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 - * <COPYRIGHT HOLDER> 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 "crc32.h" -#include <third_party/crc32.h> -#include <cpu_feature.h> -/* - * Pointer to an architecture-specific implementation of - * CRC32 calculation method. - */ -crc32_func crc32_calc = NULL; - -void -crc32_init() -{ - crc32_calc = sse42_enabled_cpu() ? &crc32c_hw : &crc32c; -} - diff --git a/core/fiber.m b/core/fiber.m index 1abbb7063b655f6011d6e952aaf233ce516f3543..89258fa0a2aa0e4bd2557f05aa6fbbb0915596af 100644 --- a/core/fiber.m +++ b/core/fiber.m @@ -135,6 +135,7 @@ fiber_call(struct fiber *callee) void fiber_wakeup(struct fiber *f) { + ev_async_start(&f->async); ev_async_send(&f->async); } @@ -530,7 +531,6 @@ fiber_create(const char *name, int fd, int inbox_size, void (*f) (void *), void fiber_alloc(fiber); ev_init(&fiber->io, (void *)ev_schedule); ev_async_init(&fiber->async, (void *)ev_schedule); - ev_async_start(&fiber->async); ev_init(&fiber->timer, (void *)ev_schedule); ev_init(&fiber->cw, (void *)ev_schedule); fiber->io.data = fiber->async.data = fiber->timer.data = fiber->cw.data = fiber; @@ -565,7 +565,6 @@ fiber_destroy(struct fiber *f) if (strcmp(f->name, "sched") == 0) return; - ev_async_stop(&f->async); palloc_destroy_pool(f->gc_pool); tarantool_coro_destroy(&f->coro); } diff --git a/core/iproto.m b/core/iproto.m index f297c54501d18feda107bd362c212248f3ba39a5..21f71272e5999991ee1e6937dd5bf902e4e8f78d 100644 --- a/core/iproto.m +++ b/core/iproto.m @@ -39,25 +39,6 @@ const uint32_t msg_ping = 0xff00; static void iproto_reply(iproto_callback callback, struct tbuf *request); -inline static int -iproto_flush(struct tbuf **in, ssize_t to_read) -{ - /* - * Flush output and garbage collect before reading - * next header. - */ - if (to_read > 0) { - if (iov_flush() < 0) { - say_warn("io_error: %s", strerror(errno)); - return -1; - } - fiber_gc(); - /* Must be reset after fiber_gc() */ - *in = fiber->rbuf; - } - return 0; -} - void iproto_interact(iproto_callback *callback) { @@ -71,8 +52,6 @@ iproto_interact(iproto_callback *callback) ssize_t request_len = sizeof(struct iproto_header) + iproto(in)->len; to_read = request_len - in->size; - if (iproto_flush(&in, to_read) == -1) - break; if (to_read > 0 && fiber_bread(in, to_read) <= 0) break; @@ -80,8 +59,20 @@ iproto_interact(iproto_callback *callback) iproto_reply(*callback, request); to_read = sizeof(struct iproto_header) - in->size; - if (iproto_flush(&in, to_read) == -1) - break; + + /* + * Flush output and garbage collect before reading + * next header. + */ + if (to_read > 0) { + if (iov_flush() < 0) { + say_warn("io_error: %s", strerror(errno)); + break; + } + fiber_gc(); + /* Must be reset after fiber_gc() */ + in = fiber->rbuf; + } } } diff --git a/core/log_io.m b/core/log_io.m index 345901a9cbafa84da31f2b1825a93b393f8533d9..6d35768687c90c2a19b5b2fb19a58e20eb347e94 100644 --- a/core/log_io.m +++ b/core/log_io.m @@ -41,9 +41,9 @@ #include <fiber.h> #include <say.h> +#include <third_party/crc32.h> #include <pickle.h> -#include <crc32.h> -#include <tarantool_pthread.h> +#include <cpu_feature.h> const u16 snap_tag = -1; const u16 wal_tag = -2; @@ -51,33 +51,15 @@ const u64 default_cookie = 0; const u32 default_version = 11; const u32 marker_v11 = 0xba0babed; const u32 eof_marker_v11 = 0x10adab1e; -const char snap_suffix[] = ".snap"; -const char xlog_suffix[] = ".xlog"; -const char inprogress_suffix[] = ".inprogress"; -const char v11[] = "0.11\n"; -const char snap_mark[] = "SNAP\n"; -const char xlog_mark[] = "XLOG\n"; -static const int HEADER_SIZE_MAX = sizeof(v11) + sizeof(snap_mark) + 2; - -struct recovery_state *recovery_state; +const char *snap_suffix = ".snap"; +const char *xlog_suffix = ".xlog"; +const char *inprogress_suffix = ".inprogress"; +const char *v11 = "0.11\n"; +const char *snap_mark = "SNAP\n"; +const char *xlog_mark = "XLOG\n"; #define ROW_EOF (void *)1 -/* Context of the WAL writer thread. */ - -struct wal_writer -{ - STAILQ_HEAD(wal_fifo, wal_write_request) input; - pthread_t thread; - pthread_mutex_t mutex; - pthread_cond_t cond; - bool is_shutdown; -}; - -static pthread_once_t wal_writer_once = PTHREAD_ONCE_INIT; - -static struct wal_writer wal_writer; - static struct tbuf *row_reader_v11(FILE *f, struct palloc_pool *pool); struct log_io_iter { @@ -90,6 +72,19 @@ struct log_io_iter { int io_rate_limit; }; +static u_int32_t (*calc_crc32c)(u_int32_t crc, const unsigned char *buf, + unsigned int len) = NULL; + +void +mach_setup_crc32() +{ +#if defined (__i386__) || defined (__x86_64__) + calc_crc32c = cpu_has(cpuf_sse4_2) ? &crc32c_hw : &crc32c; +#else + calc_crc32c = &crc32c; +#endif +} + void wait_lsn_set(struct wait_lsn *wait_lsn, i64 lsn) @@ -229,13 +224,6 @@ close_iter(struct log_io_iter *i) tarantool_coro_destroy(&i->coro); } -/** - * Read logfile contents using designated format, panic if - * the log is corrupted/unreadable. - * - * @param i iterator object, encapsulating log specifics. - * - */ static void read_rows(struct log_io_iter *i) { @@ -298,8 +286,8 @@ read_rows(struct log_io_iter *i) if (++row_count % 100000 == 0) say_info("%.1fM rows processed", row_count / 1000000.); - } /* for loop */ -eof: + } + eof: /* * then only two cases of fully read file: * 1. eof_marker_size > 0 and it is the last record in file @@ -320,7 +308,7 @@ eof: goto out; } -out: + out: l->rows += row_count; fseeko(l->f, good_offset, SEEK_SET); /* seek back to last known good offset */ @@ -484,8 +472,8 @@ row_reader_v11(FILE *f, struct palloc_pool *pool) m->size = offsetof(struct row_v11, data); /* header crc32c calculated on <lsn, tm, len, data_crc32c> */ - header_crc = crc32_calc(0, m->data + offsetof(struct row_v11, lsn), - sizeof(struct row_v11) - offsetof(struct row_v11, lsn)); + header_crc = calc_crc32c(0, m->data + offsetof(struct row_v11, lsn), + sizeof(struct row_v11) - offsetof(struct row_v11, lsn)); if (row_v11(m)->header_crc32c != header_crc) { say_error("header crc32c mismatch"); @@ -498,7 +486,7 @@ row_reader_v11(FILE *f, struct palloc_pool *pool) m->size += row_v11(m)->len; - data_crc = crc32_calc(0, row_v11(m)->data, row_v11(m)->len); + data_crc = calc_crc32c(0, row_v11(m)->data, row_v11(m)->len); if (row_v11(m)->data_crc32c != data_crc) { say_error("data crc32c mismatch"); return NULL; @@ -509,7 +497,7 @@ row_reader_v11(FILE *f, struct palloc_pool *pool) } static int -log_io_inprogress_rename(char *filename) +inprogress_log_rename(char *filename) { char *new_filename; char *suffix = strrchr(filename, '.'); @@ -553,14 +541,14 @@ inprogress_log_unlink(char *filename) } int -log_io_close(struct log_io **lptr) +close_log(struct log_io **lptr) { struct log_io *l = *lptr; int r; if (l->rows == 1 && l->mode == LOG_WRITE) { /* Rename WAL before finalize. */ - if (log_io_inprogress_rename(l->filename) != 0) + if (inprogress_log_rename(l->filename) != 0) panic("can't rename 'inprogress' WAL"); } @@ -580,29 +568,38 @@ log_io_close(struct log_io **lptr) } static int -log_io_flush(struct log_io *l) +flush_log(struct log_io *l) { if (fflush(l->f) < 0) return -1; +#ifdef TARGET_OS_LINUX + if (fdatasync(fileno(l->f)) < 0) { + say_syserror("fdatasync"); + return -1; + } +#else if (fsync(fileno(l->f)) < 0) { say_syserror("fsync"); return -1; } +#endif return 0; } static int write_header(struct log_io *l) { - char header[HEADER_SIZE_MAX]; + if (fwrite(l->class->filetype, strlen(l->class->filetype), 1, l->f) != 1) + return -1; - int n = snprintf(header, HEADER_SIZE_MAX, "%s%s\n", - l->class->filetype, l->class->version); + if (fwrite(l->class->version, strlen(l->class->version), 1, l->f) != 1) + return -1; - assert(n < HEADER_SIZE_MAX); + if (fwrite("\n", 1, 1, l->f) != 1) + return -1; - return fwrite(header, n, 1, l->f); + return 0; } static char * @@ -629,61 +626,19 @@ format_filename(char *filename, struct log_io_class *class, i64 lsn, int suffix) return filename; } -/** - * Verify that file is of the given class (format). - * - * @param l log_io object, denoting the file to check. - * @param class class to check against. - * @param[out] errmsg set if error - * - * @return 0 if success, -1 on error. - */ -static int -log_io_verify_meta(struct log_io *l, struct log_io_class *class, - const char **errmsg) -{ - char filetype[32], version[32], buf[256]; - - FILE *stream = l->f; - - if (fgets(filetype, sizeof(filetype), stream) == NULL || - fgets(version, sizeof(version), stream) == NULL) { - *errmsg = "failed to read log file header"; - goto error; - } - if (strcmp(class->filetype, filetype) != 0) { - *errmsg = "unknown filetype"; - goto error; - } - - if (strcmp(class->version, version) != 0) { - *errmsg = "unknown version"; - goto error; - } - for (;;) { - if (fgets(buf, sizeof(buf), stream) == NULL) { - *errmsg = "failed to read log file header"; - goto error; - } - if (strcmp(buf, "\n") == 0 || strcmp(buf, "\r\n") == 0) - break; - } - return 0; -error: - return -1; -} - - static struct log_io * -log_io_open_for_read(struct recovery_state *recover, struct log_io_class *class, i64 lsn, int suffix, - const char *filename) +open_for_read(struct recovery_state *recover, struct log_io_class *class, i64 lsn, int suffix, + const char *filename) { + char filetype[32], version[32], buf[256]; + struct log_io *l = NULL; + char *r; const char *errmsg; - struct log_io *l = calloc(1, sizeof(*l)); + l = calloc(1, sizeof(*l)); if (l == NULL) { - say_syserror("calloc"); - return NULL; + errmsg = strerror(errno); + goto error; } l->mode = LOG_READ; l->stat.data = recover; @@ -698,7 +653,7 @@ log_io_open_for_read(struct recovery_state *recover, struct log_io_class *class, strncpy(l->filename, filename, PATH_MAX); } - say_debug("%s: opening %s'", __func__, l->filename); + say_debug("find_log for reading `%s'", l->filename); l->f = fopen(l->filename, "r"); if (l->f == NULL) { @@ -706,23 +661,54 @@ log_io_open_for_read(struct recovery_state *recover, struct log_io_class *class, goto error; } - if (log_io_verify_meta(l, class, &errmsg) != 0) + r = fgets(filetype, sizeof(filetype), l->f); + if (r == NULL) { + errmsg = "header reading failed"; + goto error; + } + + r = fgets(version, sizeof(version), l->f); + if (r == NULL) { + errmsg = "header reading failed"; + goto error; + } + + if (strcmp(class->filetype, filetype) != 0) { + errmsg = "unknown filetype"; + goto error; + } + + if (strcmp(class->version, version) != 0) { + errmsg = "unknown version"; goto error; + } l->class = class; + for (;;) { + r = fgets(buf, sizeof(buf), l->f); + if (r == NULL) { + errmsg = "header reading failed"; + goto error; + } + if (strcmp(r, "\n") == 0 || strcmp(r, "\r\n") == 0) + break; + } + return l; -error: - say_error("%s: failed to open %s: %s", __func__, - l->filename, errmsg); - if (l->f != NULL) - fclose(l->f); - free(l); + error: + say_error("open_for_read: failed to open `%s': %s", l->filename, + errmsg); + if (l != NULL) { + if (l->f != NULL) + fclose(l->f); + free(l); + } return NULL; } struct log_io * -log_io_open_for_write(struct recovery_state *recover, struct log_io_class *class, i64 lsn, - int suffix, int *save_errno) +open_for_write(struct recovery_state *recover, struct log_io_class *class, i64 lsn, + int suffix, int *save_errno) { struct log_io *l = NULL; int fd; @@ -733,8 +719,8 @@ log_io_open_for_write(struct recovery_state *recover, struct log_io_class *class l = calloc(1, sizeof(*l)); if (l == NULL) { *save_errno = errno; - say_syserror("calloc"); - return NULL; + errmsg = strerror(errno); + goto error; } l->mode = LOG_WRITE; l->class = class; @@ -743,7 +729,7 @@ log_io_open_for_write(struct recovery_state *recover, struct log_io_class *class assert(lsn > 0); format_filename(l->filename, class, lsn, suffix); - say_debug("%s: opening %s'", __func__, l->filename); + say_debug("find_log for writing `%s'", l->filename); if (suffix == -1) { /* @@ -765,15 +751,14 @@ log_io_open_for_write(struct recovery_state *recover, struct log_io_class *class * Open the <lsn>.<suffix>.inprogress file. If it * exists, open will fail. */ - fd = open(l->filename, - O_WRONLY | O_CREAT | O_EXCL | l->class->open_wflags, 0664); + fd = open(l->filename, O_WRONLY | O_CREAT | O_EXCL | O_APPEND, 0664); if (fd < 0) { *save_errno = errno; errmsg = strerror(errno); goto error; } - l->f = fdopen(fd, "w"); + l->f = fdopen(fd, "a"); if (l->f == NULL) { *save_errno = errno; errmsg = strerror(errno); @@ -783,13 +768,14 @@ log_io_open_for_write(struct recovery_state *recover, struct log_io_class *class say_info("creating `%s'", l->filename); write_header(l); return l; - -error: - say_error("%s: failed to open `%s': %s", __func__, l->filename, + error: + say_error("find_log: failed to open `%s': %s", l->filename, errmsg); - if (l->f != NULL) - fclose(l->f); - free(l); + if (l != NULL) { + if (l->f != NULL) + fclose(l->f); + free(l); + } return NULL; } @@ -815,7 +801,7 @@ read_log(const char *filename, return -1; } - l = log_io_open_for_read(NULL, c, 0, 0, filename); + l = open_for_read(NULL, c, 0, 0, filename); iter_open(l, &i, read_rows); while ((row = iter_inner(&i, (void *)1))) h(state, row); @@ -825,7 +811,7 @@ read_log(const char *filename, close_iter(&i); v11_class_free(c); - log_io_close(&l); + close_log(&l); return i.error; } @@ -846,7 +832,7 @@ recover_snap(struct recovery_state *r) return -1; } - snap = log_io_open_for_read(r, r->snap_class, lsn, 0, NULL); + snap = open_for_read(r, r->snap_class, lsn, 0, NULL); if (snap == NULL) { say_error("can't find/open snapshot"); return -1; @@ -880,7 +866,7 @@ recover_snap(struct recovery_state *r) close_iter(&i); if (snap != NULL) - log_io_close(&snap); + close_log(&snap); prelease(fiber->gc_pool); } @@ -981,19 +967,19 @@ recover_remaining_wals(struct recovery_state *r) } else { say_warn("wal `%s' wasn't correctly closed", r->current_wal->filename); - log_io_close(&r->current_wal); + close_log(&r->current_wal); } } current_lsn = r->confirmed_lsn + 1; /* TODO: find better way looking for next xlog */ - next_wal = log_io_open_for_read(r, r->wal_class, current_lsn, 0, NULL); + next_wal = open_for_read(r, r->wal_class, current_lsn, 0, NULL); /* * When doing final recovery, and dealing with the * last file, try opening .<suffix>.inprogress. */ if (next_wal == NULL && r->finalize && current_lsn == wal_greatest_lsn) { - next_wal = log_io_open_for_read(r, r->wal_class, current_lsn, -1, NULL); + next_wal = open_for_read(r, r->wal_class, current_lsn, -1, NULL); if (next_wal == NULL) { char *filename = format_filename(NULL, r->wal_class, current_lsn, -1); @@ -1034,7 +1020,7 @@ recover_remaining_wals(struct recovery_state *r) if (result == LOG_EOF) { say_info("done `%s' confirmed_lsn:%" PRIi64, r->current_wal->filename, r->confirmed_lsn); - log_io_close(&r->current_wal); + close_log(&r->current_wal); } } @@ -1091,7 +1077,7 @@ recover(struct recovery_state *r, i64 lsn) result = -1; goto out; } - r->current_wal = log_io_open_for_read(r, r->wal_class, lsn, 0, NULL); + r->current_wal = open_for_read(r, r->wal_class, lsn, 0, NULL); if (r->current_wal == NULL) { result = -1; goto out; @@ -1137,7 +1123,7 @@ recover_follow_file(ev_stat *w, int revents __attribute__((unused))) if (result == LOG_EOF) { say_info("done `%s' confirmed_lsn:%" PRIi64, r->current_wal->filename, r->confirmed_lsn); - log_io_close(&r->current_wal); + close_log(&r->current_wal); recover_follow_dir((ev_timer *)w, 0); } } @@ -1190,203 +1176,102 @@ recover_finalize(struct recovery_state *r) } else if (r->current_wal->rows == 1) { /* Rename inprogress wal with one row */ say_warn("rename unfinished %s wal", r->current_wal->filename); - if (log_io_inprogress_rename(r->current_wal->filename) != 0) + if (inprogress_log_rename(r->current_wal->filename) != 0) panic("can't rename 'inprogress' wal"); } else panic("too many rows in inprogress WAL `%s'", r->current_wal->filename); - log_io_close(&r->current_wal); + close_log(&r->current_wal); } } -static void -wal_writer_child() +static struct wal_write_request * +wal_write_request(const struct tbuf *t) { - recovery_state->writer = NULL; + return t->data; } -static void -wal_writer_init_once() -{ - pthread_atfork(NULL, NULL, wal_writer_child); -} - -static void -wal_writer_init(struct wal_writer *writer) -{ - /* I. Initialize the state. */ - pthread_mutexattr_t errorcheck; - - tt_pthread_mutexattr_init(&errorcheck); - -#ifndef NDEBUG - tt_pthread_mutexattr_settype(&errorcheck, PTHREAD_MUTEX_ERRORCHECK); -#endif - /* Initialize queue lock mutex. */ - tt_pthread_mutex_init(&writer->mutex, &errorcheck); - tt_pthread_mutexattr_destroy(&errorcheck); - - pthread_condattr_t clock_monotonic; - tt_pthread_condattr_init(&clock_monotonic); - - /* CLOCK_REALTIME is default for pthread timeouts, yet - * we'd want to use a faster CLOCK_MONOTONIC. - */ - tt_pthread_condattr_setclock(&clock_monotonic, CLOCK_MONOTONIC); - - tt_pthread_cond_init(&writer->cond, &clock_monotonic); - tt_pthread_condattr_destroy(&clock_monotonic); - - STAILQ_INIT(&writer->input); - - tt_pthread_once(&wal_writer_once, wal_writer_init_once); -} - -static void -wal_writer_destroy(struct wal_writer *writer) -{ - tt_pthread_mutex_destroy(&writer->mutex); - tt_pthread_cond_destroy(&writer->cond); -} - -/** WAL writer thread routine. */ -static void *wal_writer_thread(void *worker_args); - -/** - * Initialize WAL writer, start the thread. - * - * @param state WAL writer meta-data. - * - * @return 0 success, -1 on error. On success, recovery->writer - * points to a newly created WAL writer. - */ -static int -wal_writer_start(struct recovery_state *state) -{ - assert(state->writer == NULL); - assert(wal_writer.is_shutdown == false); - - /* I. Initialize the state. */ - wal_writer_init(&wal_writer); - state->writer = &wal_writer; - - /* II. Start the thread. */ - - if (pthread_create(&wal_writer.thread, NULL, wal_writer_thread, - state)) { - wal_writer_destroy(&wal_writer); - state->writer = NULL; - return -1; - } - return 0; -} - -static int -wal_writer_stop(struct recovery_state *state) -{ - struct wal_writer *writer = state->writer; - - state->writer = NULL; - - /* Stop the worker thread. */ - - tt_pthread_mutex_lock(&writer->mutex); - writer->is_shutdown= true; - tt_pthread_cond_signal(&writer->cond); - tt_pthread_mutex_unlock(&writer->mutex); - - if (pthread_join(writer->thread, NULL) == 0) { - wal_writer_destroy(writer); - return 0; - } - say_syserror("WAL writer: thread join failed"); - return -1; -} - -struct wal_fifo -wal_writer_pop(struct wal_writer *writer, bool wait) -{ - struct wal_fifo input; - do { - input = writer->input; - STAILQ_INIT(&writer->input); - if (STAILQ_EMPTY(&input) == false || wait == false) - break; - tt_pthread_cond_wait(&writer->cond, &writer->mutex); - } while (writer->is_shutdown == false); - return input; -} - -static int -write_to_disk(struct recovery_state *r, struct wal_write_request *req) +static struct tbuf * +write_to_disk(void *_state, struct tbuf *t) { static struct log_io *wal = NULL, *wal_to_close = NULL; static ev_tstamp last_flush = 0; + struct tbuf *reply, *header; + struct recovery_state *r = _state; + u32 result = 0; -#if 0 /* we're not running inside ev_loop, so update ev_now manually */ ev_now_update(); -#endif /* caller requested termination */ - if (req == NULL) { + if (t == NULL) { if (wal != NULL) - log_io_close(&wal); -#if 0 - if (wal_to_close != NULL) - log_io_close(&wal_to_close); + close_log(&wal); recover_free((struct recovery_state*)_state); -#endif - return 0; + return NULL; } + reply = tbuf_alloc(t->pool); + if (wal == NULL) { int unused; /* Open WAL with '.inprogress' suffix. */ - wal = log_io_open_for_write(r, r->wal_class, req->lsn, -1, - &unused); + wal = open_for_write(r, r->wal_class, wal_write_request(t)->lsn, -1, + &unused); } else if (wal->rows == 1) { /* rename WAL after first successful write to name * without inprogress suffix*/ - if (log_io_inprogress_rename(wal->filename) != 0) { + if (inprogress_log_rename(wal->filename) != 0) { say_error("can't rename inprogress wal"); goto fail; } } if (wal_to_close != NULL) { - if (log_io_close(&wal_to_close) != 0) + if (close_log(&wal_to_close) != 0) goto fail; } if (wal == NULL) { say_syserror("can't open wal"); goto fail; } - req->marker = marker_v11; - req->tm = ev_now(); - req->data_crc32c = crc32_calc(0, (u8 *) &req->tag, req->len); - /* Header size. */ - size_t sz = (sizeof(req->lsn) + sizeof(req->tm) + sizeof(req->len) + - sizeof(req->data_crc32c)); - req->header_crc32c = crc32_calc(0, (u8 *) &req->lsn, sz); - /* Total size. */ - sz += sizeof(req->marker) + sizeof(req->header_crc32c) + req->len; - /* Write the request. */ - if (fwrite(&req->marker, sz, 1, wal->f) != 1) { + if (fwrite(&wal->class->marker, wal->class->marker_size, 1, wal->f) != 1) { + say_syserror("can't write marker to wal"); + goto fail; + } + + header = tbuf_alloc(t->pool); + tbuf_ensure(header, sizeof(struct row_v11)); + header->size = sizeof(struct row_v11); + + row_v11(header)->lsn = wal_write_request(t)->lsn; + row_v11(header)->tm = ev_now(); + row_v11(header)->len = wal_write_request(t)->len; + row_v11(header)->data_crc32c = + calc_crc32c(0, wal_write_request(t)->data, wal_write_request(t)->len); + row_v11(header)->header_crc32c = + calc_crc32c(0, header->data + field_sizeof(struct row_v11, header_crc32c), + sizeof(struct row_v11) - field_sizeof(struct row_v11, header_crc32c)); + + if (fwrite(header->data, header->size, 1, wal->f) != 1) { say_syserror("can't write row header to wal"); goto fail; } + if (fwrite(wal_write_request(t)->data, wal_write_request(t)->len, 1, wal->f) != 1) { + say_syserror("can't write row data to wal"); + goto fail; + } + /* flush stdio buffer to keep replication in sync */ if (fflush(wal->f) < 0) { say_syserror("can't flush wal"); goto fail; } - if (wal->class->fsync_delay > 0 && - ev_now() - last_flush >= wal->class->fsync_delay) { - if (log_io_flush(wal) < 0) { + if (wal->class->fsync_delay > 0 && ev_now() - last_flush >= wal->class->fsync_delay) { + if (flush_log(wal) < 0) { say_syserror("can't flush wal"); goto fail; } @@ -1395,100 +1280,55 @@ write_to_disk(struct recovery_state *r, struct wal_write_request *req) wal->rows++; if (wal->class->rows_per_file <= wal->rows || - (req->lsn + 1) % wal->class->rows_per_file == 0) { + (wal_write_request(t)->lsn + 1) % wal->class->rows_per_file == 0) { wal_to_close = wal; wal = NULL; } - req->out_lsn = req->lsn; - return 0; + tbuf_append(reply, &result, sizeof(result)); + return reply; -fail: - req->out_lsn = 0; - return -1; + fail: + result = 1; + tbuf_append(reply, &result, sizeof(result)); + return reply; } -static void * -wal_writer_thread(void *worker_args) +bool +wal_write(struct recovery_state *r, u16 tag, u64 cookie, i64 lsn, struct tbuf *row) { - struct recovery_state *r = worker_args; - struct wal_writer *writer = r->writer; - struct wal_fifo output = STAILQ_HEAD_INITIALIZER(output); - struct wal_write_request *req; - - tt_pthread_mutex_lock(&writer->mutex); - while (writer->is_shutdown == false) { - struct wal_fifo input = - wal_writer_pop(writer, STAILQ_EMPTY(&output)); - pthread_mutex_unlock(&writer->mutex); - /* - * Check the old list of fibers to wakeup *here* - * since we needed a membar for its out_lsn's to - * sync up. - */ - STAILQ_FOREACH(req, &output, wal_fifo_entry) { - /* - * @todo: - * Even though wal_write() is not - * a cancellation point, check the fiber - * wasn't cancelled and recycled. - * */ - fiber_wakeup(req->fiber); - } - STAILQ_FOREACH(req, &input, wal_fifo_entry) { - (void) write_to_disk(r, req); - } - output = input; - tt_pthread_mutex_lock(&writer->mutex); - } - tt_pthread_mutex_unlock(&writer->mutex); - write_to_disk(r, NULL); - return NULL; -} + struct tbuf *m = tbuf_alloc(row->pool); + struct msg *a; -int -wal_write(struct recovery_state *r, u16 tag, u16 op, u64 cookie, - i64 lsn, struct tbuf *row) -{ say_debug("wal_write lsn=%" PRIi64, lsn); - struct wal_writer *writer = r->writer; - - struct wal_write_request *req = - palloc(fiber->gc_pool, sizeof(struct wal_write_request) - + row->size); - - req->fiber = fiber; - req->lsn = lsn; - req->tag = tag; - req->cookie = cookie; - req->op = op; - req->len = sizeof(tag) + sizeof(cookie) + sizeof(op) + row->size; - memcpy(&req->data, row->data, row->size); - - tt_pthread_mutex_lock(&writer->mutex); - - bool was_empty = STAILQ_EMPTY(&writer->input); - - STAILQ_INSERT_TAIL(&writer->input, req, wal_fifo_entry); - - if (was_empty) - tt_pthread_cond_signal(&writer->cond); - - tt_pthread_mutex_unlock(&writer->mutex); - - fiber_yield(); + tbuf_reserve(m, sizeof(struct wal_write_request) + sizeof(tag) + sizeof(cookie) + row->size); + m->size = sizeof(struct wal_write_request); + wal_write_request(m)->lsn = lsn; + wal_write_request(m)->len = row->size + sizeof(tag) + sizeof(cookie); + tbuf_append(m, &tag, sizeof(tag)); + tbuf_append(m, &cookie, sizeof(cookie)); + tbuf_append(m, row->data, row->size); + + if (write_inbox(r->wal_writer->out, m) == false) { + say_warn("wal writer inbox is full"); + return false; + } + a = read_inbox(); - return req->out_lsn == 0 ? -1 : 0; + u32 reply = read_u32(a->msg); + say_debug("wal_write reply=%" PRIu32, reply); + if (reply != 0) + say_warn("wal writer returned error status"); + return reply == 0; } -void -recovery_init(const char *snap_dirname, const char *wal_dirname, - row_handler row_handler, int rows_per_file, - const char *wal_mode, double fsync_delay, int flags, void *data) +struct recovery_state * +recover_init(const char *snap_dirname, const char *wal_dirname, + row_handler row_handler, + int rows_per_file, double fsync_delay, + int inbox_size, int flags, void *data) { - assert(recovery_state == NULL); - recovery_state = p0alloc(eter_pool, sizeof(struct recovery_state)); - struct recovery_state *r = recovery_state; + struct recovery_state *r = p0alloc(eter_pool, sizeof(*r)); if (rows_per_file <= 1) panic("unacceptable value of 'rows_per_file'"); @@ -1503,36 +1343,27 @@ recovery_init(const char *snap_dirname, const char *wal_dirname, r->wal_class = xlog_class_create(wal_dirname); r->wal_class->rows_per_file = rows_per_file; r->wal_class->fsync_delay = fsync_delay; - r->wal_class->open_wflags = strcasecmp(wal_mode, "fsync") ? 0 : WAL_SYNC_FLAG; wait_lsn_clear(&r->wait_lsn); if ((flags & RECOVER_READONLY) == 0) - wal_writer_start(r); -} + r->wal_writer = spawn_child("wal_writer", inbox_size, write_to_disk, r); -void -recovery_update_mode(const char *mode, double fsync_delay) -{ - struct recovery_state *r = recovery_state; - (void) mode; - r->wal_class->fsync_delay = fsync_delay; + return r; } void -recovery_free() +recover_free(struct recovery_state *recovery) { - struct recovery_state *recovery = recovery_state; - if (recovery == NULL) - return; - if (recovery->writer) - wal_writer_stop(recovery); + struct child *writer = recovery->wal_writer; + if (writer && writer->out && writer->out->fd > 0) { + close(writer->out->fd); + usleep(1000); + } v11_class_free(recovery->snap_class); v11_class_free(recovery->wal_class); if (recovery->current_wal) - log_io_close(&recovery->current_wal); - - recovery_state = NULL; + close_log(&recovery->current_wal); } void @@ -1562,13 +1393,12 @@ write_rows(struct log_io_iter *i) panic("fwrite"); row_v11(row)->lsn = 0; /* unused */ - /* @todo: check if we can safely use ev_now() here. */ row_v11(row)->tm = ev_now(); row_v11(row)->len = data->size; - row_v11(row)->data_crc32c = crc32_calc(0, data->data, data->size); + row_v11(row)->data_crc32c = calc_crc32c(0, data->data, data->size); row_v11(row)->header_crc32c = - crc32_calc(0, row->data + field_sizeof(struct row_v11, header_crc32c), - sizeof(struct row_v11) - field_sizeof(struct row_v11, + calc_crc32c(0, row->data + field_sizeof(struct row_v11, header_crc32c), + sizeof(struct row_v11) - field_sizeof(struct row_v11, header_crc32c)); if (fwrite(row->data, row->size, 1, l->f) != 1) @@ -1604,7 +1434,7 @@ snapshot_write_row(struct log_io_iter *i, u16 tag, u64 cookie, struct tbuf *row) bytes += row->size + sizeof(struct row_v11); while (bytes >= i->io_rate_limit) { - log_io_flush(i->log); + flush_log(i->log); ev_now_update(); elapsed = ev_now() - last; @@ -1632,7 +1462,7 @@ snapshot_save(struct recovery_state *r, void (*f) (struct log_io_iter *)) memset(&i, 0, sizeof(i)); - snap = log_io_open_for_write(r, r->snap_class, r->confirmed_lsn, -1, &save_errno); + snap = open_for_write(r, r->snap_class, r->confirmed_lsn, -1, &save_errno); if (snap == NULL) panic_status(save_errno, "can't open snap for writing"); @@ -1662,7 +1492,7 @@ snapshot_save(struct recovery_state *r, void (*f) (struct log_io_iter *)) if (unlink(snap->filename) == -1) say_syserror("can't unlink 'inprogress' snapshot"); - log_io_close(&snap); + close_log(&snap); say_info("done"); } diff --git a/core/log_io_remote.m b/core/log_io_remote.m index eefa828637860f46e9ef1079f698369c768880fd..4b14427f11e57bf39662f34e5bc3209ffaabbe24 100644 --- a/core/log_io_remote.m +++ b/core/log_io_remote.m @@ -149,7 +149,6 @@ default_remote_row_handler(struct recovery_state *r, struct tbuf *row) struct tbuf *data; i64 lsn = row_v11(row)->lsn; u16 tag; - u16 op; /* save row data since wal_row_handler may clobber it */ data = tbuf_alloc(row->pool); @@ -160,9 +159,8 @@ default_remote_row_handler(struct recovery_state *r, struct tbuf *row) tag = read_u16(data); (void)read_u64(data); /* drop the cookie */ - op = read_u16(data); - if (wal_write(r, tag, op, r->cookie, lsn, data)) + if (wal_write(r, tag, r->cookie, lsn, data) == false) panic("replication failure: can't write row to WAL"); next_lsn(r, lsn); diff --git a/core/replication.m b/core/replication.m index 0c58898e9a3352a10c42d54dfb9a8fd7d383eff2..b7644fd19ae60e7b337becf235ce83220a8d4cb7 100644 --- a/core/replication.m +++ b/core/replication.m @@ -607,12 +607,9 @@ replication_relay_loop(int client_sock) ev_io_init(&sock_read_ev, replication_relay_recv, sock_read_fd, EV_READ); ev_io_start(&sock_read_ev); - /* Initialize the recovery process */ - recovery_init(NULL, cfg.wal_dir, replication_relay_send_row, - INT32_MAX, "fsync_delay", 0, - RECOVER_READONLY, false); - - log_io = recovery_state; + /* 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); diff --git a/core/tarantool.m b/core/tarantool.m index ee745d90bd217a90c407a622d8ecbc2942e46d5f..055b0696f78e1bbc6824fb14d4fbe5cefd96a20e 100644 --- a/core/tarantool.m +++ b/core/tarantool.m @@ -48,7 +48,6 @@ #include <iproto.h> #include <latch.h> #include <log_io.h> -#include <crc32.h> #include <palloc.h> #include <salloc.h> #include <say.h> @@ -70,22 +69,11 @@ char **main_argv; int main_argc; static void *main_opt = NULL; struct tarantool_cfg cfg; +struct recovery_state *recovery_state; static ev_signal *sigs = NULL; bool init_storage, booting = true; -static int -core_check_config(struct tarantool_cfg *conf) -{ - /* Check that the mode is a supported one. */ - if (strcmp(conf->wal_mode, "fsync") != 0 && - strcmp(conf->wal_mode, "fsync_delay") != 0) { - out_warning(0, "wal_mode is not one of 'fsync', 'fsync_delay'"); - return -1; - } - return 0; -} - static i32 load_cfg(struct tarantool_cfg *conf, i32 check_rdonly) { @@ -114,50 +102,12 @@ load_cfg(struct tarantool_cfg *conf, i32 check_rdonly) if (n_accepted == 0 || n_skipped != 0) return -1; - if (core_check_config(conf) != 0) - return -1; - if (replication_check_config(conf) != 0) return -1; return mod_check_config(conf); } -static int -core_reload_config(const struct tarantool_cfg *old_conf, - const struct tarantool_cfg *new_conf) -{ - if (strcasecmp(old_conf->wal_mode, new_conf->wal_mode) == 0 && - old_conf->wal_fsync_delay == new_conf->wal_fsync_delay) - return 0; - - double new_delay = new_conf->wal_fsync_delay; - - /* Mode has changed: */ - if (strcasecmp(old_conf->wal_mode, new_conf->wal_mode)) { - if (strcasecmp(old_conf->wal_mode, "fsync") == 0 || - strcasecmp(new_conf->wal_mode, "fsync") == 0) { - out_warning(0, "wal_mode cannot switch to/from fsync"); - return -1; - } - say_debug("%s: wal_mode [%s] -> [%s]", - __func__, old_conf->wal_mode, new_conf->wal_mode); - } - - /* - * Unless wal_mode=fsync_delay, wal_fsync_delay is irrelevant and must be 0. - */ - if (strcasecmp(new_conf->wal_mode, "fsync_delay") != 0) - new_delay = 0.0; - - if (old_conf->wal_fsync_delay != new_delay) - say_debug("%s: wal_fsync_delay [%f] -> [%f]", - __func__, old_conf->wal_fsync_delay, new_delay); - - recovery_update_mode(new_conf->wal_mode, new_delay); - - return 0; -} i32 reload_cfg(struct tbuf *out) @@ -209,10 +159,6 @@ reload_cfg(struct tbuf *out) return -1; } - /* Process wal-writer-related changes. */ - if (core_reload_config(&cfg, &new_cfg) != 0) - return -1; - /* Now pass the config to the module, to take action. */ if (mod_reload_config(&cfg, &new_cfg) != 0) return -1; @@ -404,7 +350,8 @@ error: void tarantool_free(void) { - recovery_free(); + if (recovery_state != NULL) + recover_free(recovery_state); stat_free(); if (cfg_filename_fullpath) @@ -444,6 +391,12 @@ initialize_minimal() initialize(0.1, 4, 2); } +inline static void +mach_init() +{ + mach_setup_crc32(); +} + int main(int argc, char **argv) { @@ -462,9 +415,9 @@ main(int argc, char **argv) #endif master_pid = getpid(); - crc32_init(); stat_init(); palloc_init(); + mach_init(); #ifdef HAVE_BFD symbols_load(argv[0]); diff --git a/core/tarantool_lua.m b/core/tarantool_lua.m index 66d4615ec90e601f75b80a1ba693fd735180d397..d32d299da51f17d935282f72b6394d864b689b06 100644 --- a/core/tarantool_lua.m +++ b/core/tarantool_lua.m @@ -135,8 +135,6 @@ static char format_to_opcode(char format) case '^': return 3; case '|': return 4; case ':': return 5; - case '#': return 6; - case '!': return 7; default: return format; } } @@ -232,8 +230,6 @@ lbox_pack(struct lua_State *L) case '|': /* set field|=val */ case '^': /* set field^=val */ case ':': /* splice */ - case '#': /* delete field */ - case '!': /* insert field */ u32buf= (u32) lua_tointeger(L, i); /* field no */ luaL_addlstring(&b, (char *) &u32buf, sizeof(u32)); luaL_addchar(&b, format_to_opcode(*format)); diff --git a/doc/www-data.in/index b/doc/www-data.in/index index 3947d664908220a8d945bf6b551171f54df97521..19e586ca070a7bfbe6abed76daadeaf288c348fc 100644 --- a/doc/www-data.in/index +++ b/doc/www-data.in/index @@ -84,7 +84,7 @@ Get Involved ============ - [Browse Git source](https://github.com/mailru/tarantool) -- [Read the Developer Guide](tarantool_developer_guide.html) +- [Read the developer guide](tarantool_developer_guide.html) - [IRC chat with developers](http://webchat.freenode.net/?channels=tarantool) - [Developer list archives](https://lists.launchpad.net/tarantool-developers/) - [Help improve our Wiki](http://github.com/mailru/tarantool/wiki) diff --git a/include/config.h.cmake b/include/config.h.cmake index 961fdf11cefb36b88c6b3c103eb935cb0820099b..b09c4a209ad95a4dda06b4287f6e08f43d4c7b99 100644 --- a/include/config.h.cmake +++ b/include/config.h.cmake @@ -42,19 +42,6 @@ #define MAP_ANONYMOUS MAP_ANON #endif -/* - * Defined if O_DSYNC mode exists for open(2). - */ -#cmakedefine HAVE_O_DSYNC 1 -#if defined(HAVE_O_DSYNC) - #define WAL_SYNC_FLAG O_DSYNC -#else - #define WAL_SYNC_FLAG O_SYNC -#endif -/* - * Defined if fdatasync(2) call is present. - */ -#cmakedefine HAVE_FDATASYNC 1 /* * Set if this is a GNU system and libc has __libc_stack_end. */ diff --git a/include/cpu_feature.h b/include/cpu_feature.h index fad19e75e8d459e870a1b8859547f1a71cc4c0f2..34cef8040ea72b3290b81aecc6e593ba1746e887 100644 --- a/include/cpu_feature.h +++ b/include/cpu_feature.h @@ -26,15 +26,23 @@ */ #include <sys/types.h> -#include <stdbool.h> -/* Check whether CPU supports SSE 4.2 (needed to compute CRC32 in hardware). +/* CPU feature capabilities to use with cpu_has (feature). */ + +#if defined (__i386__) || defined (__x86_64__) +enum { + cpuf_ht = 0, cpuf_sse4_1, cpuf_sse4_2, cpuf_hypervisor +}; +#endif + +/* Check whether CPU has a certain feature. * * @param feature indetifier (see above) of the target feature * - * @return true if feature is available, false if unavailable. + * @return 1 if feature is available, 0 if unavailable, + * -EINVAL if unsupported CPU, -ERANGE if invalid feature */ -bool sse42_enabled_cpu(); +int cpu_has(unsigned int feature); /* Hardware-calculate CRC32 for the given data buffer. @@ -43,7 +51,7 @@ bool sse42_enabled_cpu(); * @param buf data buffer * @param len buffer length * - * @pre true == cpu_has (cpuf_sse4_2) + * @pre 1 == cpu_has (cpuf_sse4_2) * @return CRC32 value */ u_int32_t crc32c_hw(u_int32_t crc, const unsigned char *buf, unsigned int len); @@ -51,3 +59,5 @@ u_int32_t crc32c_hw(u_int32_t crc, const unsigned char *buf, unsigned int len); #endif /* TARANTOOL_CPU_FEATURES_H */ +/* __EOF__ */ + diff --git a/include/crc32.h b/include/crc32.h deleted file mode 100644 index 1e5d0aa65e64f472d65e25d227e5e699a02e59c1..0000000000000000000000000000000000000000 --- a/include/crc32.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef TARANTOOL_CRC32_H_INCLUDED -#define TARANTOOL_CRC32_H_INCLUDED -/* - * 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 <COPYRIGHT HOLDER> ``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 - * <COPYRIGHT HOLDER> 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 <sys/types.h> -#include <util.h> - -typedef u_int32_t (*crc32_func)(u_int32_t crc, const unsigned char *buf, unsigned int len); - -/* - * Pointer to an architecture-specific implementation of - * CRC32 calculation method. - */ -extern crc32_func crc32_calc; - -void crc32_init(); - -#endif /* TARANTOOL_CRC32_H_INCLUDED */ diff --git a/include/errcode.h b/include/errcode.h index f200eb0b701d567c2b86e5f9ce0f22706c2cd018..0af265d21e23aa11a9a1d4b16c2794efc51a62b3 100644 --- a/include/errcode.h +++ b/include/errcode.h @@ -77,7 +77,7 @@ enum { TNT_ERRMSG_MAX = 512 }; /* 23 */_(ER_RESERVED23, 0, "Reserved23") \ /* end of silverproxy error codes */ \ /* 24 */_(ER_CANNOT_REGISTER, 1, "Can't register new user") \ - /* 25 */_(ER_TUPLE_IS_EMPTY, 0, "UPDATE error: the new tuple has no fields") \ + /* 25 */_(ER_UNUSED25, 0, "Unused25") \ /* 26 */_(ER_CANNOT_INIT_ALERT_ID, 1, "Can't generate alert id") \ /* 27 */_(ER_CANNOT_DEL, 2, "Can't del node") \ /* 28 */_(ER_USER_NOT_REGISTERED, 2, "User isn't registered") \ diff --git a/include/log_io.h b/include/log_io.h index 0450d48b32ced148cd9f10569e5ca7da51cea3f0..e157a2bb0e0666e74015f0fd8fc156fe1595539a 100644 --- a/include/log_io.h +++ b/include/log_io.h @@ -34,7 +34,6 @@ #include <util.h> #include <palloc.h> #include <netinet/in.h> /* struct sockaddr_in */ -#include <third_party/queue.h> struct tbuf; @@ -58,12 +57,9 @@ struct log_io_class { u64 marker, eof_marker; size_t marker_size, eof_marker_size; size_t rows_per_file; - /* wal_fsync_delay value for the log class. */ double fsync_delay; bool panic_if_error; - /* Additional flags to apply at open(2) to write. */ - int open_wflags; const char *filetype; const char *version; const char *suffix; @@ -103,15 +99,13 @@ struct log_io { bool is_inprogress; }; -struct wal_writer; - struct recovery_state { i64 lsn, confirmed_lsn; struct log_io *current_wal; /* the WAL we'r currently reading/writing from/to */ struct log_io_class *snap_class; struct log_io_class *wal_class; - struct wal_writer *writer; + struct child *wal_writer; /* row_handler will be presented by most recent format of data log_io_class->reader is responsible of converting data from old format */ @@ -132,28 +126,12 @@ struct recovery_state { void *data; }; -struct recovery_state *recovery_state; - struct wal_write_request { - STAILQ_ENTRY(wal_write_request) wal_fifo_entry; - /* Auxiliary. */ - u64 out_lsn; - struct fiber *fiber; - /** Header. */ - u32 marker; - u32 header_crc32c; i64 lsn; - double tm; u32 len; - u32 data_crc32c; - /* Data. */ - u16 tag; - u64 cookie; - u16 op; u8 data[]; } __attribute__((packed)); -/* @todo: merge with wal_write_request. */ struct row_v11 { u32 header_crc32c; i64 lsn; @@ -163,26 +141,24 @@ struct row_v11 { u8 data[]; } __attribute__((packed)); - static inline struct row_v11 *row_v11(const struct tbuf *t) { return (struct row_v11 *)t->data; } +void mach_setup_crc32 (); + struct tbuf *convert_to_v11(struct tbuf *orig, u16 tag, u64 cookie, i64 lsn); -void recovery_init(const char *snap_dirname, const char *xlog_dirname, - row_handler row_handler, - int rows_per_file, const char *wal_mode, - double fsync_delay, - int flags, void *data); -void recovery_update_mode(const char *wal_mode, double fsync_delay); -void recovery_free(); +struct recovery_state *recover_init(const char *snap_dirname, const char *xlog_dirname, + row_handler row_handler, + int rows_per_file, double fsync_delay, int inbox_size, + int flags, void *data); +void recover_free(struct recovery_state *recovery); int recover(struct recovery_state *, i64 lsn); void recover_follow(struct recovery_state *r, ev_tstamp wal_dir_rescan_delay); void recover_finalize(struct recovery_state *r); -int wal_write(struct recovery_state *r, u16 tag, u16 op, - u64 cookie, i64 lsn, struct tbuf *data); +bool wal_write(struct recovery_state *r, u16 tag, u64 cookie, i64 lsn, struct tbuf *data); void recovery_setup_panic(struct recovery_state *r, bool on_snap_error, bool on_wal_error); diff --git a/include/tarantool.h b/include/tarantool.h index def71b5ca535d22e61f5dfba493cadfeb9cb814e..20dbb5b7ca69f895e844b17d5d27f42d105eb764 100644 --- a/include/tarantool.h +++ b/include/tarantool.h @@ -33,6 +33,7 @@ struct lua_State; struct luaL_Reg; +extern struct recovery_state *recovery_state; void mod_init(void); void mod_free(void); struct tarantool_cfg; diff --git a/include/tarantool_pthread.h b/include/tarantool_pthread.h deleted file mode 100644 index 7c102660f5183ba33a8def3d6fa413db80b90310..0000000000000000000000000000000000000000 --- a/include/tarantool_pthread.h +++ /dev/null @@ -1,163 +0,0 @@ -#ifndef TARANTOOL_PTHREAD_H_INCLUDED -#define TARANTOOL_PTHREAD_H_INCLUDED -/* - * 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 <COPYRIGHT HOLDER> ``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 - * <COPYRIGHT HOLDER> 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 <pthread.h> - -#include <util.h> -#include <say.h> - -/** - * Assert on any pthread* error in debug mode. In release, - * write into the log file where and what has failed. - * - * Still give the user an opportunity to manually - * check for error, by returning the pthread_* - * function status up. - */ - -#define tt_pthread_error(e) \ - if (e != 0) \ - say_error("%s error %d", __func__, e);\ - assert(e == 0); \ - e - -/** - * Debug/logging friendly wrappers around pthread - * functions. - */ - -#define tt_pthread_mutex_init(mutex, attr) \ -({ int e = pthread_mutex_init(mutex, attr);\ - tt_pthread_error(e); \ -}) - -#define tt_pthread_mutex_destroy(mutex) \ -({ int e = pthread_mutex_destroy(mutex); \ - tt_pthread_error(e); \ -}) - -#define tt_pthread_mutex_lock(mutex) \ -({ int e = pthread_mutex_lock(mutex); \ - say_debug("%s: locking %s", __func__, #mutex);\ - tt_pthread_error(e);\ -}) - -#define tt_pthread_mutex_trylock(mutex) \ -({ int e = pthread_mutex_trylock(mutex); \ - if (e != 0 && e != EBUSY) \ - say_error("%s error %d at %s:%d", __func__, e, __FILE__, __LINE__);\ - assert(e == 0 || e == EBUSY); \ - e \ -}) - -#define tt_pthread_mutex_unlock(mutex) \ -({ int e = pthread_mutex_unlock(mutex); \ - say_debug("%s: unlocking %s", __func__, #mutex);\ - tt_pthread_error(e); \ -}) - -#define tt_pthread_mutex_destroy(mutex) \ -({ int e = pthread_mutex_destroy(mutex); \ - tt_pthread_error(e); \ -}) - -#define tt_pthread_mutexattr_init(attr) \ -({ int e = pthread_mutexattr_init(attr); \ - tt_pthread_error(e); \ -}) - -#define tt_pthread_mutexattr_destroy(attr) \ -({ int e = pthread_mutexattr_destroy(attr);\ - tt_pthread_error(e); \ -}) - -#define tt_pthread_mutexattr_gettype(attr, type)\ -({ int e = pthread_mutexattr_gettype(attr, type);\ - tt_pthread_error(e); \ -}) - -#define tt_pthread_mutexattr_settype(attr, type)\ -({ int e = pthread_mutexattr_settype(attr, type);\ - tt_pthread_error(e); \ -}) - -#define tt_pthread_condattr_init(attr) \ -({ int e = pthread_condattr_init(attr); \ - tt_pthread_error(e); \ -}) - -#define tt_pthread_condattr_destroy(attr) \ -({ int e = pthread_condattr_destroy(attr); \ - tt_pthread_error(e); \ -}) - -#define tt_pthread_condattr_getclock(attr, clock_id)\ -({ int e = pthread_condattr_getclock(attr, clock_id);\ - tt_pthread_error(e); \ -}) - -#define tt_pthread_condattr_setclock(attr, clock_id)\ -({ int e = pthread_condattr_setclock(attr, clock_id);\ - tt_pthread_error(e); \ -}) - -#define tt_pthread_cond_init(cond, attr) \ -({ int e = pthread_cond_init(cond, attr); \ - tt_pthread_error(e); \ -}) - -#define tt_pthread_cond_destroy(cond) \ -({ int e = pthread_cond_destroy(cond); \ - tt_pthread_error(e); \ -}) - -#define tt_pthread_cond_signal(cond) \ -({ int e = pthread_cond_signal(cond); \ - tt_pthread_error(e); \ -}) - -#define tt_pthread_cond_wait(cond, mutex) \ -({ int e = pthread_cond_wait(cond, mutex);\ - tt_pthread_error(e); \ -}) - -#define tt_pthread_cond_timedwait(cond, mutex, timeout) \ -({ int e = pthread_cond_timedwait(cond, mutex, timeout);\ - if (ETIMEDOUT != e) \ - tt_pthread_error(e); \ -}) - -#define tt_pthread_once(control, function) \ -({ int e = pthread_once(control, function);\ - tt_pthread_error(e); \ -}) - - -#endif /* TARANTOOL_PTHREAD_H_INCLUDED */ diff --git a/mod/box/box.h b/mod/box/box.h index 4b7cbf8768960997dace3bb8958fb7384ca41d8b..4ec097ce71fe2e92c0cb8d1a5fde7cfc7dfdcf42 100644 --- a/mod/box/box.h +++ b/mod/box/box.h @@ -158,9 +158,8 @@ ENUM(messages, MESSAGES); _(UPDATE_OP_OR, 4) \ _(UPDATE_OP_SPLICE, 5) \ _(UPDATE_OP_DELETE, 6) \ - _(UPDATE_OP_INSERT, 7) \ - _(UPDATE_OP_NONE, 8) \ - _(UPDATE_OP_MAX, 9) \ + _(UPDATE_OP_NONE, 7) \ + _(UPDATE_OP_MAX, 8) \ ENUM(update_op_codes, UPDATE_OP_CODES); diff --git a/mod/box/box.lua b/mod/box/box.lua index e582ca72e8c0e245b1ca82a09beed2d375535145..a7887721dd60bf9d02068349fba3d768b145eff6 100644 --- a/mod/box/box.lua +++ b/mod/box/box.lua @@ -40,15 +40,6 @@ function box.select_range(sno, ino, limit, ...) return box.space[tonumber(sno)].index[tonumber(ino)]:select_range(tonumber(limit), ...) end --- --- Select a range of tuples in a given namespace via a given --- index in reverse order. If key is NULL, starts from the end, otherwise --- starts from the key. --- -function box.select_reverse_range(sno, ino, limit, ...) - return box.space[tonumber(sno)].index[tonumber(ino)]:select_reverse_range(tonumber(limit), ...) -end - -- -- delete can be done only by the primary key, whose -- index is always 0. It doesn't accept compound keys @@ -112,8 +103,6 @@ function box.on_reload_configuration() -- index_mt.next = function(index, ...) return index.idx:next(...) end - index_mt.prev = function(index, ...) - return index.idx:prev(...) end -- index_mt.select_range = function(index, limit, ...) local range = {} @@ -125,16 +114,6 @@ function box.on_reload_configuration() end return unpack(range) end - index_mt.select_reverse_range = function(index, limit, ...) - local range = {} - for k, v in index.idx.prev, index.idx, ... do - if #range >= limit then - break - end - table.insert(range, v) - end - return unpack(range) - end -- local space_mt = {} space_mt.len = function(space) return space.index[0]:len() end @@ -143,9 +122,6 @@ function box.on_reload_configuration() space_mt.select_range = function(space, ino, limit, ...) return space.index[ino]:select_range(limit, ...) end - space_mt.select_reverse_range = function(space, ino, limit, ...) - return space.index[ino]:select_reverse_range(limit, ...) - end space_mt.select_limit = function(space, ino, offset, limit, ...) return box.select_limit(space.n, ino, offset, limit, ...) end diff --git a/mod/box/box.m b/mod/box/box.m index 3635efecf6b0441014d9d65fd3fabcce6e8170b9..b97bac3d7a8374263c1fab96dec739d88c404fa1 100644 --- a/mod/box/box.m +++ b/mod/box/box.m @@ -59,7 +59,6 @@ static char status[64] = "unknown"; static int stat_base; STRS(messages, MESSAGES); -STRS(update_op_codes, UPDATE_OP_CODES); /* For tuples of size below this threshold, when sending a tuple @@ -294,9 +293,6 @@ rollback_replace(struct box_txn *txn) * Supported operations are: SET, ADD, bitwise AND, XOR and OR, * SPLICE and DELETE. * - * The typical case is when the operation count is much less - * than field count in a tuple. - * * To ensure minimal use of intermediate memory, UPDATE is * performed in a streaming fashion: all operations in the request * are sorted by field number. The resulting tuple length is @@ -379,20 +375,15 @@ struct update_op { * A descriptor of one changed field. */ struct update_field { - /** Pointer to the first operation on this field. */ - struct update_op *first; - /** Points after the last operation on this field. */ - struct update_op *end; - /** Points at start of field *data* in the old tuple. */ - void *old; - /** The final length of the new field. */ - u32 new_len; - /** End of the old field. */ - void *tail; - /** Copy old data after this field. */ - u32 tail_len; - /** How many fields we're copying. */ - int tail_field_count; + struct update_op *first; /** first operation on this field */ + struct update_op *end; /** points after last operation on + this field. */ + void *old; /** points at start of field *data* in old + tuple. */ + void *old_end; /** end of the old field. */ + u32 new_len; /** final length of the new field. */ + u32 tail_len; /** copy old data after this field */ + int tail_field_count; /** how many fields we're copying. */ }; /** UPDATE command context. */ @@ -418,39 +409,16 @@ update_op_cmp(const void *op1_ptr, const void *op2_ptr) const struct update_op *op1 = op1_ptr; const struct update_op *op2 = op2_ptr; - /* Compare operations by field number. */ - int result = (int) op1->field_no - (int) op2->field_no; - if (result) - return result; - /* - * INSERT operations create a new field - * at index field_no, shifting other fields to the right. - * Operations on field_no are done on the field - * in the old tuple and do not affect the inserted - * field. Therefore, field insertion should be - * done first, followed by all other operations - * on the given field_no. - */ - result = (op2->opcode == UPDATE_OP_INSERT) - - (op1->opcode == UPDATE_OP_INSERT); - if (result) - return result; - /* - * We end up here in two cases: - * 1) both operations are INSERTs, - * 2) both operations are not INSERTs. - * - * Preserve the original order of operations on the same - * field. To do it, order them by their address in the - * UPDATE request. - * - * The expression below should work even if sizeof(ptrdiff_t) - * is greater than sizeof(int) because we presume that both - * value addresses belong to the same UPDATE command buffer - * and therefore their difference must be small enough to fit - * into an int comfortably. - */ - return (int) (op1->arg.set.value - op2->arg.set.value); + if (op1->field_no < op2->field_no) + return -1; + if (op1->field_no > op2->field_no) + return 1; + + if (op1->arg.set.value < op2->arg.set.value) + return -1; + if (op1->arg.set.value > op2->arg.set.value) + return 1; + return 0; } static void @@ -522,13 +490,6 @@ do_update_op_splice(struct op_splice_arg *arg, void *in, void *out) memcpy(out, in + arg->tail_offset, arg->tail_length); /* copy tail */ } -static void -do_update_op_insert(struct op_set_arg *arg, void *in __attribute__((unused)), - void *out) -{ - memcpy(out, arg->value, arg->length); -} - static void do_update_op_none(struct op_set_arg *arg, void *in, void *out) { @@ -651,32 +612,16 @@ static void init_update_op_delete(struct update_cmd *cmd, struct update_field *field, struct update_op *op) { - /* - * Either DELETE is the last op on a field or next op - * on this field is SET. - */ - if (op + 1 < cmd->op_end) { - struct update_op *next_op = op + 1; - if (next_op->field_no == op->field_no && - next_op->opcode != UPDATE_OP_SET && - next_op->opcode != UPDATE_OP_DELETE) { - tnt_raise(ClientError, :ER_NO_SUCH_FIELD, - op->field_no); - } - } + /* Either this is the last op on this field or next op is SET. */ + if (op + 1 < cmd->op_end && op[1].field_no == op->field_no && + op[1].opcode != UPDATE_OP_SET && op[1].opcode != UPDATE_OP_DELETE) + tnt_raise(ClientError, :ER_NO_SUCH_FIELD, op->field_no); + /* Skip all ops on this field, including this one. */ field->first = op + 1; op->new_field_len = 0; } -static void -init_update_op_insert(struct update_cmd *cmd __attribute__((unused)), - struct update_field *field __attribute__((unused)), - struct update_op *op) -{ - op->new_field_len = op->arg.set.length; -} - static void init_update_op_none(struct update_cmd *cmd __attribute__((unused)), struct update_field *field, struct update_op *op) @@ -700,7 +645,6 @@ static struct update_op_meta update_op_meta[UPDATE_OP_MAX + 1] = { { init_update_op_arith, (do_op_func) do_update_op_or, true }, { init_update_op_splice, (do_op_func) do_update_op_splice, false }, { init_update_op_delete, (do_op_func) NULL, true }, - { init_update_op_insert, (do_op_func) do_update_op_insert, true }, { init_update_op_none, (do_op_func) do_update_op_none, false }, { init_update_op_error, (do_op_func) NULL, true } }; @@ -755,58 +699,47 @@ parse_update_cmd(struct tbuf *data) return cmd; } +/** + * Skip fields unaffected by UPDATE. + * @return length of skipped data + */ +static u32 +skip_fields(u32 field_count, void **data) +{ + void *begin = *data; + while (field_count-- > 0) { + u32 len = load_varint32(data); + *data += len; + } + return *data - begin; +} + static void -update_field_init(struct update_field *field, struct update_op *op, - void **old_data, int old_field_count) +update_field_init(struct update_cmd *cmd, struct update_field *field, + struct update_op *op, void **old_data, int old_field_count) { field->first = op; - - if (op->field_no >= old_field_count || - op->opcode == UPDATE_OP_INSERT) { - /* Insert operation always creates a new field. */ + if (op->field_no < old_field_count) { + /* + * Find out the new field length and + * shift the data pointer. + */ + field->new_len = load_varint32(old_data); + field->old = *old_data; + *old_data += field->new_len; + field->old_end = *old_data; + } else { field->new_len = 0; field->old = ""; /* Beyond old fields. */ + field->old_end = field->old; /* * Old tuple must have at least one field and we * always have an op on the first field. */ - assert(op->field_no > 0 || op->opcode == UPDATE_OP_INSERT); - return; + assert(op->field_no > 0 && op > cmd->op); } - /* - * Find out the new field length and - * shift the data pointer. - */ - field->new_len = load_varint32(old_data); - field->old = *old_data; - *old_data += field->new_len; -} - -/** - * Skip fields unaffected by UPDATE. - * @return length of skipped data - */ -static void -update_field_skip_fields(struct update_field *field, i32 skip_count, - void **data) -{ - if (skip_count < 0) { - /* Happens when there are fields added by SET. */ - skip_count = 0; - } - - field->tail_field_count = skip_count; - - field->tail = *data; - while (skip_count-- > 0) { - u32 len = load_varint32(data); - *data += len; - } - - field->tail_len = *data - field->tail; } - /** * We found a tuple to do the update on. Prepare and optimize * the operations. @@ -820,7 +753,6 @@ init_update_operations(struct box_txn *txn, struct update_cmd *cmd) */ qsort(cmd->op, cmd->op_end - cmd->op, sizeof(struct update_op), update_op_cmp); - /* * 2. Take care of the old tuple head. */ @@ -837,7 +769,6 @@ init_update_operations(struct box_txn *txn, struct update_cmd *cmd) cmd->op->meta = &update_op_meta[UPDATE_OP_NONE]; cmd->op->field_no = 0; } - /* * 3. Initialize and optimize the operations. */ @@ -850,90 +781,58 @@ init_update_operations(struct box_txn *txn, struct update_cmd *cmd) void *old_data = txn->old_tuple->data; int old_field_count = txn->old_tuple->cardinality; - update_field_init(field, op, &old_data, old_field_count); + update_field_init(cmd, field, op, &old_data, old_field_count); do { - struct update_op *prev_op = op - 1; - struct update_op *next_op = op + 1; - /* * Various checks for added fields: + * 1) we can not do anything with a new field unless a + * previous field exists. + * 2) we can not do any op except SET on a field + * which does not exist. */ - if (op->field_no >= old_field_count) { - /* - * We can not do anything with a new field unless a - * previous field exists. - */ - int prev_field_no = MAX(old_field_count, - prev_op->field_no + 1); - if (op->field_no > prev_field_no) - tnt_raise(ClientError, :ER_NO_SUCH_FIELD, - op->field_no); - /* - * We can not do any op except SET or INSERT - * on a field which does not exist. - */ - if (prev_op->field_no != op->field_no && - (op->opcode != UPDATE_OP_SET && - op->opcode != UPDATE_OP_INSERT)) - tnt_raise(ClientError, :ER_NO_SUCH_FIELD, - op->field_no); + if (op->field_no >= old_field_count && + /* check case 1. */ + (op->field_no > MAX(old_field_count, + op[-1].field_no + 1) || + /* check case 2. */ + (op->opcode != UPDATE_OP_SET && + op[-1].field_no != op->field_no))) { + + tnt_raise(ClientError, :ER_NO_SUCH_FIELD, op->field_no); } op->meta->init_op(cmd, field, op); field->new_len = op->new_field_len; - /* - * Find out how many fields to copy to the - * new tuple intact once this op is done. - */ - int skip_count; - if (next_op >= cmd->op_end) { - /* This is the last op in the request. */ - skip_count = old_field_count - op->field_no - 1; - } else if (op->field_no < next_op->field_no || - op->opcode == UPDATE_OP_INSERT) { - /* - * This is the last op on this field. UPDATE_OP_INSERT - * creates a new field, so it falls - * into this category. Find out length of - * the gap between the op->field_no and - * next and copy the gap. - */ - skip_count = MIN(next_op->field_no, old_field_count) - - op->field_no - 1; - } else { - /* Continue, we have more operations on this field */ - continue; - } - if (op->opcode == UPDATE_OP_INSERT) { - /* - * We're adding a new field, take this - * into account. - */ - skip_count++; - } - /* Jumping over a gap. */ - update_field_skip_fields(field, skip_count, &old_data); - - field->end = next_op; - if (field->first < field->end) { - /* Field is not deleted. */ - cmd->new_tuple_len += varint32_sizeof(field->new_len); - cmd->new_tuple_len += field->new_len; - } - cmd->new_tuple_len += field->tail_len; - /* Move to the next field. */ - field++; - if (next_op < cmd->op_end) { - update_field_init(field, next_op, &old_data, - old_field_count); + if (op + 1 >= cmd->op_end || op[1].field_no != op->field_no) { + /* Last op on this field. */ + int skip_to = old_field_count; + if (op + 1 < cmd->op_end && op[1].field_no < old_field_count) + skip_to = op[1].field_no; + if (skip_to > op->field_no + 1) { + /* Jumping over a gap. */ + field->tail_field_count = skip_to - op->field_no - 1; + field->tail_len = + skip_fields(field->tail_field_count, + &old_data); + } else { + field->tail_len = 0; + field->tail_field_count = 0; + } + field->end = op + 1; + if (field->first < field->end) { /* Field is not deleted. */ + cmd->new_tuple_len += varint32_sizeof(field->new_len); + cmd->new_tuple_len += field->new_len; + } + cmd->new_tuple_len += field->tail_len; + field++; /** Move to the next field. */ + if (op + 1 < cmd->op_end) { + update_field_init(cmd, field, op + 1, + &old_data, old_field_count); + } } - } while (++op < cmd->op_end); cmd->field_end = field; - - if (cmd->new_tuple_len == 0) - tnt_raise(ClientError, :ER_TUPLE_IS_EMPTY); } static void @@ -963,8 +862,7 @@ do_update(struct box_txn *txn, struct update_cmd *cmd) * (can happen when a big SET is then * shrunk by a SPLICE). */ - if ((old_field == new_field && - !op->meta->works_in_place) || + if ((old_field == new_field && !op->meta->works_in_place) || /* * Sic: this predicate must function even if * new_field != new_data. @@ -975,7 +873,7 @@ do_update(struct box_txn *txn, struct update_cmd *cmd) * conditions above got us here, simply * palloc a *new* buffer of sufficient * size. - */ + */ new_field = palloc(fiber->gc_pool, op->new_field_len); } @@ -991,7 +889,7 @@ do_update(struct box_txn *txn, struct update_cmd *cmd) memcpy(new_data, new_field, field->new_len); new_data += field->new_len; if (field->tail_field_count) { - memcpy(new_data, field->tail, field->tail_len); + memcpy(new_data, field->old_end, field->tail_len); new_data += field->tail_len; txn->tuple->cardinality += field->tail_field_count; } @@ -1072,7 +970,7 @@ process_select(struct box_txn *txn, u32 limit, u32 offset, struct tbuf *data) } struct iterator *it = index->position; - [index initIterator: it :ITER_FORWARD :key :key_cardinality]; + [index initIterator: it :key :key_cardinality]; while ((tuple = it->next_equal(it)) != NULL) { if (tuple->flags & GHOST) @@ -1247,10 +1145,13 @@ txn_commit(struct box_txn *txn) ; else { fiber_peer_name(fiber); /* fill the cookie */ + struct tbuf *t = tbuf_alloc(fiber->gc_pool); + tbuf_append(t, &txn->op, sizeof(txn->op)); + tbuf_append(t, txn->req.data, txn->req.size); i64 lsn = next_lsn(recovery_state, 0); - int res = wal_write(recovery_state, wal_tag, txn->op, - fiber->cookie, lsn, &txn->req); + bool res = !wal_write(recovery_state, wal_tag, + fiber->cookie, lsn, t); confirm_lsn(recovery_state, lsn); if (res) tnt_raise(LoggedError, :ER_WAL_IO); @@ -2148,10 +2049,10 @@ mod_init(void) space_init(); /* recovery initialization */ - recovery_init(cfg.snap_dir, cfg.wal_dir, - recover_row, cfg.rows_per_wal, cfg.wal_mode, - cfg.wal_fsync_delay, - init_storage ? RECOVER_READONLY : 0, NULL); + recovery_state = recover_init(cfg.snap_dir, cfg.wal_dir, + recover_row, cfg.rows_per_wal, cfg.wal_fsync_delay, + cfg.wal_writer_inbox_size, + init_storage ? RECOVER_READONLY : 0, NULL); recovery_state->snap_io_rate_limit = cfg.snap_io_rate_limit * 1024 * 1024; recovery_setup_panic(recovery_state, cfg.panic_on_snap_error, cfg.panic_on_wal_error); @@ -2241,7 +2142,7 @@ mod_snapshot(struct log_io_iter *i) Index *pk = space[n].index[0]; struct iterator *it = pk->position; - [pk initIterator: it :ITER_FORWARD]; + [pk initIterator: it]; while ((tuple = it->next(it))) { snapshot_write_tuple(i, n, tuple); } @@ -2254,6 +2155,8 @@ mod_info(struct tbuf *out) tbuf_printf(out, " version: \"%s\"" CRLF, tarantool_version()); tbuf_printf(out, " uptime: %i" CRLF, (int)tarantool_uptime()); tbuf_printf(out, " pid: %i" CRLF, getpid()); + tbuf_printf(out, " wal_writer_pid: %" PRIi64 CRLF, + (i64) recovery_state->wal_writer->pid); tbuf_printf(out, " lsn: %" PRIi64 CRLF, recovery_state->confirmed_lsn); tbuf_printf(out, " recovery_lag: %.3f" CRLF, recovery_state->recovery_lag); tbuf_printf(out, " recovery_last_update: %.3f" CRLF, diff --git a/mod/box/box_cfg.cfg_tmpl b/mod/box/box_cfg.cfg_tmpl index 318b287932bfc11d20f909ca24195819d9f56f17..d8b124e5cf4746b33aa2806990ed05ae1a90e98e 100644 --- a/mod/box/box_cfg.cfg_tmpl +++ b/mod/box/box_cfg.cfg_tmpl @@ -1,6 +1,12 @@ ## BOX +# Snapshot directory (where snapshots get saved/read) +snap_dir=".", ro + +# WAL directory (where WALs get saved/read) +wal_dir=".", ro + # Primary port (where updates are accepted) primary_port=0, ro, required @@ -25,6 +31,36 @@ memcached_expire_per_loop=1024 # tarantool will try to iterate over all rows within this time memcached_expire_full_sweep=3600.0 +# Do not write into snapshot faster than snap_io_rate_limit MB/sec +snap_io_rate_limit=0.0, ro + +# Write no more rows in WAL +rows_per_wal=500000, ro + +# fsync WAL delay, only issue fsync if last fsync was wal_fsync_delay +# seconds ago. +# WARNING: actually, several last requests may stall fsync for much longer +wal_fsync_delay=0.0, ro + +# size of WAL writer request buffer +wal_writer_inbox_size=128, ro + +# 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=false, ro +# Delay, in seconds, between successive re-readings of wal_dir. +# The re-scan is necessary to discover new WAL files or snapshots. +wal_dir_rescan_delay=0.1, ro + + +# Panic if there is an error reading a snapshot or WAL. +# By default, panic on any snapshot reading error and ignore errors +# when reading WALs. +panic_on_snap_error=true, ro +panic_on_wal_error=false, ro + # Replication mode (if enabled, the server, once # bound to the primary port, will connect to # replication_source (ipaddr:port) and run continously diff --git a/mod/box/box_lua.m b/mod/box/box_lua.m index e652a999832f33b0364744a9d5134f8fd6b5c5c9..6e6b16238b2d3d65c229b0cc2417926789d10057 100644 --- a/mod/box/box_lua.m +++ b/mod/box/box_lua.m @@ -372,7 +372,6 @@ void append_key_part(struct lua_State *L, int i, * Lua iterator over a Taratnool/Box index. * * (iteration_state, tuple) = index.next(index, [iteration_state]) - * (iteration_state, tuple) = index.prev(index, [iteration_state]) * * When [iteration_state] is absent or nil * returns a pointer to a new iterator and @@ -389,7 +388,7 @@ void append_key_part(struct lua_State *L, int i, * offset. */ static int -lbox_index_move(struct lua_State *L, enum iterator_type type) +lbox_index_next(struct lua_State *L) { Index *index = lua_checkindex(L, 1); int argc = lua_gettop(L) - 1; @@ -397,11 +396,10 @@ lbox_index_move(struct lua_State *L, enum iterator_type type) if (argc == 0 || (argc == 1 && lua_type(L, 2) == LUA_TNIL)) { /* * If there is nothing or nil on top of the stack, - * start iteration from the beginning (ITER_FORWARD) or - * end (ITER_REVERSE). + * start iteration from the beginning. */ it = [index allocIterator]; - [index initIterator: it :type]; + [index initIterator: it]; lbox_pushiterator(L, it); } else if (argc > 1 || lua_type(L, 2) != LUA_TUSERDATA) { /* @@ -437,7 +435,7 @@ lbox_index_move(struct lua_State *L, enum iterator_type type) "does not match index cardinality (%d)", cardinality, index->key_def->part_count); it = [index allocIterator]; - [index initIterator: it :type :key :cardinality]; + [index initIterator: it :key :cardinality]; lbox_pushiterator(L, it); } else { /* 1 item on the stack and it's a userdata. */ it = lua_checkiterator(L, 2); @@ -448,35 +446,12 @@ lbox_index_move(struct lua_State *L, enum iterator_type type) return tuple ? 2 : 1; } -/** - * Lua forward index iterator function. - * See lbox_index_move comment for a functional - * description. - */ -static int -lbox_index_next(struct lua_State *L) -{ - return lbox_index_move(L, ITER_FORWARD); -} - -/** - * Lua reverse index iterator function. - * See lbox_index_move comment for a functional - * description. - */ -static int -lbox_index_prev(struct lua_State *L) -{ - return lbox_index_move(L, ITER_REVERSE); -} - static const struct luaL_reg lbox_index_meta[] = { {"__tostring", lbox_index_tostring}, {"__len", lbox_index_len}, {"min", lbox_index_min}, {"max", lbox_index_max}, {"next", lbox_index_next}, - {"prev", lbox_index_prev}, {NULL, NULL} }; diff --git a/mod/box/index.h b/mod/box/index.h index 07e706e74624724ad188f2bcd7c78c2c711df0b4..e3cb401c391dc15f4ece1ac8191093825c5537c3 100644 --- a/mod/box/index.h +++ b/mod/box/index.h @@ -44,8 +44,6 @@ extern const char *field_data_type_strs[]; enum index_type { HASH, TREE, index_type_MAX }; extern const char *index_type_strs[]; -enum iterator_type { ITER_FORWARD, ITER_REVERSE }; - /** Descriptor of a single part in a multipart key. */ struct key_part { u32 fieldno; @@ -126,9 +124,8 @@ struct key_def { * initialized separately. */ - (struct iterator *) allocIterator; -- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type; -- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type - :(void *) key +- (void) initIterator: (struct iterator *) iterator; +- (void) initIterator: (struct iterator *) iterator :(void *) key :(int) part_count; @end diff --git a/mod/box/index.m b/mod/box/index.m index 066745bfc2fba23f6af494e0f6e43a0fb023d910..e304c32decc241e098b6e6ac15e4ce80ec032cdb 100644 --- a/mod/box/index.m +++ b/mod/box/index.m @@ -166,19 +166,16 @@ iterator_first_equal(struct iterator *it) return NULL; } -- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type +- (void) initIterator: (struct iterator *) iterator { (void) iterator; - (void) type; [self subclassResponsibility: _cmd]; } -- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type - :(void *) key +- (void) initIterator: (struct iterator *) iterator :(void *) key :(int) part_count { (void) iterator; - (void) type; (void) part_count; (void) key; [self subclassResponsibility: _cmd]; @@ -208,7 +205,8 @@ hash_iterator(struct iterator *it) struct box_tuple * hash_iterator_next(struct iterator *iterator) { - assert(iterator->next == hash_iterator_next); + assert(iterator->next = hash_iterator_next); + struct hash_iterator *it = hash_iterator(iterator); while (it->h_pos != mh_end(it->hash)) { @@ -222,7 +220,7 @@ hash_iterator_next(struct iterator *iterator) void hash_iterator_free(struct iterator *iterator) { - assert(iterator->next == hash_iterator_next); + assert(iterator->next = hash_iterator_next); sfree(iterator); } @@ -249,7 +247,7 @@ hash_iterator_free(struct iterator *iterator) struct iterator *it = pk->position; struct box_tuple *tuple; - [pk initIterator: it :ITER_FORWARD]; + [pk initIterator: it]; while ((tuple = it->next(it))) [self replace: NULL :tuple]; @@ -389,29 +387,24 @@ hash_iterator_free(struct iterator *iterator) #endif } -- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type +- (void) initIterator: (struct iterator *) iterator { - assert(iterator->next == hash_iterator_next); struct hash_iterator *it = hash_iterator(iterator); - if (type == ITER_REVERSE) - tnt_raise(IllegalParams, :"hash iterator is forward only"); + assert(iterator->next = hash_iterator_next); it->base.next_equal = 0; /* Should not be used. */ it->h_pos = mh_begin(int_hash); it->hash = int_hash; } -- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type - :(void *) key +- (void) initIterator: (struct iterator *) iterator :(void *) key :(int) part_count { + assert(iterator->next = hash_iterator_next); (void) part_count; /* Silence gcc warning in release mode. */ - assert(iterator->next == hash_iterator_next); - struct hash_iterator *it = hash_iterator(iterator); - if (type == ITER_REVERSE) - tnt_raise(IllegalParams, :"hash iterator is forward only"); + struct hash_iterator *it = hash_iterator(iterator); if (part_count != 1) tnt_raise(IllegalParams, :"key must be single valued"); @@ -521,30 +514,25 @@ hash_iterator_free(struct iterator *iterator) #endif } -- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type +- (void) initIterator: (struct iterator *) iterator { - assert(iterator->next == hash_iterator_next); + assert(iterator->next = hash_iterator_next); + struct hash_iterator *it = hash_iterator(iterator); - if (type == ITER_REVERSE) - tnt_raise(IllegalParams, :"hash iterator is forward only"); it->base.next_equal = 0; /* Should not be used if not positioned. */ it->h_pos = mh_begin(int64_hash); it->hash = (struct mh_i32ptr_t *) int64_hash; } -- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type - :(void *) field +- (void) initIterator: (struct iterator *) iterator :(void *) field :(int) part_count { (void) part_count; /* Silence gcc warning in release mode. */ - assert(iterator->next == hash_iterator_next); + assert(iterator->next = hash_iterator_next); struct hash_iterator *it = hash_iterator(iterator); - if (type == ITER_REVERSE) - tnt_raise(IllegalParams, :"hash iterator is forward only"); - if (part_count != 1) tnt_raise(IllegalParams, :"key must be single valued"); @@ -645,30 +633,24 @@ hash_iterator_free(struct iterator *iterator) #endif } -- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type +- (void) initIterator: (struct iterator *) iterator { - assert(iterator->next == hash_iterator_next); - struct hash_iterator *it = hash_iterator(iterator); + assert(iterator->next = hash_iterator_next); - if (type == ITER_REVERSE) - tnt_raise(IllegalParams, :"hash iterator is forward only"); + struct hash_iterator *it = hash_iterator(iterator); it->base.next_equal = 0; /* Should not be used if not positioned. */ it->h_pos = mh_begin(str_hash); it->hash = (struct mh_i32ptr_t *) str_hash; } -- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type - :(void *) key +- (void) initIterator: (struct iterator *) iterator :(void *) key :(int) part_count { (void) part_count; /* Silence gcc warning in release mode. */ - assert(iterator->next == hash_iterator_next); + assert(iterator->next = hash_iterator_next); struct hash_iterator *it = hash_iterator(iterator); - if (type == ITER_REVERSE) - tnt_raise(IllegalParams, :"hash iterator is forward only"); - if (part_count != 1) tnt_raise(IllegalParams, :"key must be single valued"); diff --git a/mod/box/memcached.m b/mod/box/memcached.m index a0d57a9ab8f80a0baade5a403bce755d5a9fa106..3717294c505f4fc718ef84361c8625c2ce6d1cec 100644 --- a/mod/box/memcached.m +++ b/mod/box/memcached.m @@ -285,7 +285,7 @@ flush_all(void *data) fiber_sleep(delay - ev_now()); struct box_tuple *tuple; struct iterator *it = [memcached_index allocIterator]; - [memcached_index initIterator: it :ITER_FORWARD]; + [memcached_index initIterator: it]; while ((tuple = it->next(it))) { meta(tuple)->exptime = 1; } @@ -505,7 +505,7 @@ memcached_expire_loop(void *data __attribute__((unused))) @try { restart: if (tuple == NULL) - [memcached_index initIterator: memcached_it :ITER_FORWARD]; + [memcached_index initIterator: memcached_it]; struct tbuf *keys_to_delete = tbuf_alloc(fiber->gc_pool); diff --git a/mod/box/tree.h b/mod/box/tree.h index b4580f75f6940fca61acd3981ede1da52144c294..19b58b28b751ce5a1fdf76cac8322a4adda16536 100644 --- a/mod/box/tree.h +++ b/mod/box/tree.h @@ -50,6 +50,8 @@ typedef int (*tree_cmp_t)(const void *, const void *, void *); - (tree_cmp_t) key_node_cmp; - (void) fold: (void *) node :(struct box_tuple *) tuple; - (struct box_tuple *) unfold: (const void *) node; +- (int) compare: (const void *) node_a :(const void *) node_b; +- (int) key_compare: (const void *) key :(const void *) node; @end diff --git a/mod/box/tree.m b/mod/box/tree.m index 1b68f3854f7c34fb3f192e012280d51046e8d7b6..c1b75a31d49bd2ee8b9961798995fc8e218396c1 100644 --- a/mod/box/tree.m +++ b/mod/box/tree.m @@ -271,25 +271,6 @@ find_tree_type(struct space *space, struct key_def *key_def) } } -/** - * Check if key parts make a linear sequence of fields. - */ -static bool -key_is_linear(struct key_def *key_def) -{ - if (key_def->part_count > 1) { - int prev = key_def->parts[0].fieldno; - for (int i = 1; i < key_def->part_count; ++i) { - int next = key_def->parts[i].fieldno; - if (next != (prev + 1)) { - return false; - } - prev = next; - } - } - return true; -} - /** * Find field offsets/values for a sparse node. */ @@ -508,10 +489,13 @@ sparse_key_node_compare(struct key_def *key_def, * Compare a part for two dense keys. */ static int -dense_part_compare(enum field_data_type type, - const u8 *ad, u32 al, - const u8 *bd, u32 bl) +dense_part_compare(enum field_data_type type, const u8 *data_a, + u32 offset_a, const u8 *data_b, u32 offset_b) { + const u8 *ad = data_a + offset_a; + const u8 *bd = data_b + offset_b; + u32 al = load_varint32((void *) &ad); + u32 bl = load_varint32((void *) &bd); if (type == NUM) { u32 an, bn; assert(al == sizeof an && bl == sizeof bn); @@ -541,71 +525,33 @@ dense_node_compare(struct key_def *key_def, u32 first_field, struct box_tuple *tuple_a, u32 offset_a, struct box_tuple *tuple_b, u32 offset_b) { - int part_count = key_def->part_count; - assert(first_field + part_count <= tuple_a->cardinality); - assert(first_field + part_count <= tuple_b->cardinality); - - /* Allocate space for offsets. */ - u32 *off_a = alloca(2 * part_count * sizeof(u32)); - u32 *off_b = off_a + part_count; - - /* Find field offsets. */ - off_a[0] = offset_a; - off_b[0] = offset_b; - if (part_count > 1) { - u8 *ad = tuple_a->data + offset_a; - u8 *bd = tuple_b->data + offset_b; - for (int i = 1; i < part_count; ++i) { - u32 al = load_varint32((void**) &ad); - u32 bl = load_varint32((void**) &bd); - ad += al; - bd += bl; - off_a[i] = ad - tuple_a->data; - off_b[i] = bd - tuple_b->data; - } - } - - /* Compare key parts. */ - for (int part = 0; part < part_count; ++part) { - int field = key_def->parts[part].fieldno; - u8 *ad = tuple_a->data + off_a[field - first_field]; - u8 *bd = tuple_b->data + off_b[field - first_field]; - u32 al = load_varint32((void *) &ad); - u32 bl = load_varint32((void *) &bd); - int r = dense_part_compare(key_def->parts[part].type, - ad, al, bd, bl); - if (r) { - return r; - } - } - return 0; -} - -/** - * Compare a part for two dense keys with parts in linear order. - */ -static int -linear_node_compare(struct key_def *key_def, u32 first_field, - struct box_tuple *tuple_a, u32 offset_a, - struct box_tuple *tuple_b, u32 offset_b) -{ - int part_count = key_def->part_count; - assert(first_field + part_count <= tuple_a->cardinality); - assert(first_field + part_count <= tuple_b->cardinality); - - /* Compare key parts. */ + /* find field offsets */ + u32 off_a[key_def->part_count]; + u32 off_b[key_def->part_count]; u8 *ad = tuple_a->data + offset_a; u8 *bd = tuple_b->data + offset_b; - for (int part = 0; part < part_count; ++part) { + for (int i = 0; i < key_def->part_count; ++i) { + assert(first_field + i < tuple_a->cardinality); + assert(first_field + i < tuple_b->cardinality); + off_a[i] = ad - tuple_a->data; + off_b[i] = bd - tuple_b->data; u32 al = load_varint32((void**) &ad); u32 bl = load_varint32((void**) &bd); + ad += al; + bd += bl; + } + + /* compare key parts */ + for (int part = 0; part < key_def->part_count; ++part) { + int field = key_def->parts[part].fieldno; int r = dense_part_compare(key_def->parts[part].type, - ad, al, bd, bl); + tuple_a->data, + off_a[field - first_field], + tuple_b->data, + off_b[field - first_field]); if (r) { return r; } - ad += al; - bd += bl; } return 0; } @@ -616,8 +562,10 @@ linear_node_compare(struct key_def *key_def, u32 first_field, static int dense_key_part_compare(enum field_data_type type, const u8 *data_a, union sparse_part part_a, - const u8 *bd, u32 bl) + const u8 *data_b, u32 offset_b) { + const u8 *bd = data_b + offset_b; + u32 bl = load_varint32((void *) &bd); if (type == NUM) { u32 an, bn; an = part_a.num32; @@ -659,67 +607,28 @@ dense_key_node_compare(struct key_def *key_def, const struct key_data *key_data, u32 first_field, struct box_tuple *tuple, u32 offset) { - int part_count = key_def->part_count; - assert(first_field + part_count <= tuple->cardinality); - - /* Allocate space for offsets. */ - u32 *off = alloca(part_count * sizeof(u32)); - - /* Find field offsets. */ - off[0] = offset; - if (part_count > 1) { - u8 *data = tuple->data + offset; - for (int i = 1; i < part_count; ++i) { - u32 len = load_varint32((void**) &data); - data += len; - off[i] = data - tuple->data; - } + /* find field offsets */ + u32 off[key_def->part_count]; + u8 *data = tuple->data + offset; + for (int i = 0; i < key_def->part_count; ++i) { + assert(first_field + i < tuple->cardinality); + off[i] = data - tuple->data; + u32 len = load_varint32((void**) &data); + data += len; } - /* Compare key parts. */ - if (part_count > key_data->part_count) - part_count = key_data->part_count; + /* compare key parts */ + int part_count = MIN(key_def->part_count, key_data->part_count); for (int part = 0; part < part_count; ++part) { int field = key_def->parts[part].fieldno; - const u8 *bd = tuple->data + off[field - first_field]; - u32 bl = load_varint32((void *) &bd); - int r = dense_key_part_compare(key_def->parts[part].type, - key_data->data, - key_data->parts[part], - bd, bl); - if (r) { - return r; - } - } - return 0; -} - -/** - * Compare a key for a key search data and a dense node with parts in - * linear order. - */ -static int -linear_key_node_compare(struct key_def *key_def, - const struct key_data *key_data, - u32 first_field, struct box_tuple *tuple, u32 offset) -{ - int part_count = key_def->part_count; - assert(first_field + part_count <= tuple->cardinality); - - /* Compare key parts. */ - if (part_count > key_data->part_count) - part_count = key_data->part_count; - u8 *bd = tuple->data + offset; - for (int part = 0; part < part_count; ++part) { - u32 bl = load_varint32((void *) &bd); int r = dense_key_part_compare(key_def->parts[part].type, key_data->data, key_data->parts[part], - bd, bl); + tuple->data, + off[field - first_field]); if (r) { return r; } - bd += bl; } return 0; } @@ -751,16 +660,6 @@ tree_iterator_next(struct iterator *iterator) return [it->index unfold: node]; } -static struct box_tuple * -tree_iterator_reverse_next(struct iterator *iterator) -{ - assert(iterator->next == tree_iterator_reverse_next); - struct tree_iterator *it = tree_iterator(iterator); - - void *node = sptree_index_iterator_reverse_next(it->iter); - return [it->index unfold: node]; -} - static struct box_tuple * tree_iterator_next_equal(struct iterator *iterator) { @@ -776,26 +675,12 @@ tree_iterator_next_equal(struct iterator *iterator) return NULL; } -static struct box_tuple * -tree_iterator_reverse_next_equal(struct iterator *iterator) -{ - assert(iterator->next == tree_iterator_reverse_next); - struct tree_iterator *it = tree_iterator(iterator); - - void *node = sptree_index_iterator_reverse_next(it->iter); - if (node != NULL - && it->index->tree.compare(&it->key_data, node, it->index) == 0) { - return [it->index unfold: node]; - } - - return NULL; -} - static void tree_iterator_free(struct iterator *iterator) { - assert(iterator->free == tree_iterator_free); + assert(iterator->next == tree_iterator_next); struct tree_iterator *it = tree_iterator(iterator); + if (it->iter) sptree_index_iterator_free(it->iter); @@ -920,36 +805,30 @@ tree_iterator_free(struct iterator *iterator) if (it) { memset(it, 0, sizeof(struct tree_iterator)); it->index = self; + it->base.next = tree_iterator_next; it->base.free = tree_iterator_free; } return (struct iterator *) it; } -- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type +- (void) initIterator: (struct iterator *) iterator { - [self initIterator: iterator :type :NULL :0]; + [self initIterator: iterator :NULL :0]; } -- (void) initIterator: (struct iterator *) iterator :(enum iterator_type) type - :(void *) key - :(int) part_count +- (void) initIterator: (struct iterator *) iterator + : (void *) key + : (int) part_count { - assert(iterator->free == tree_iterator_free); + assert(iterator->next == tree_iterator_next); struct tree_iterator *it = tree_iterator(iterator); + it->base.next_equal = tree_iterator_next_equal; + it->key_data.data = key; it->key_data.part_count = part_count; fold_with_key_parts(key_def, &it->key_data); - - if (type == ITER_FORWARD) { - it->base.next = tree_iterator_next; - it->base.next_equal = tree_iterator_next_equal; - sptree_index_iterator_init_set(&tree, &it->iter, &it->key_data); - } else if (type == ITER_REVERSE) { - it->base.next = tree_iterator_reverse_next; - it->base.next_equal = tree_iterator_reverse_next_equal; - sptree_index_iterator_reverse_init_set(&tree, &it->iter, &it->key_data); - } + sptree_index_iterator_init_set(&tree, &it->iter, &it->key_data); } - (void) build: (Index *) pk @@ -973,7 +852,7 @@ tree_iterator_free(struct iterator *iterator) } struct iterator *it = pk->position; - [pk initIterator: it :ITER_FORWARD]; + [pk initIterator: it]; struct box_tuple *tuple; for (u32 i = 0; (tuple = it->next(it)) != NULL; ++i) { @@ -1032,6 +911,22 @@ tree_iterator_free(struct iterator *iterator) return NULL; } +- (int) compare: (const void *) node_a :(const void *) node_b +{ + (void) node_a; + (void) node_b; + [self subclassResponsibility: _cmd]; + return 0; +} + +- (int) key_compare: (const void *) key :(const void *) node +{ + (void) key; + (void) node; + [self subclassResponsibility: _cmd]; + return 0; +} + @end /* }}} */ @@ -1118,7 +1013,6 @@ sparse_key_node_cmp(const void *key, const void *node, void *arg) @interface DenseTreeIndex: TreeIndex { @public u32 first_field; - bool is_linear; } @end @@ -1156,47 +1050,12 @@ dense_key_node_cmp(const void *key, const void * node, void *arg) node_x->tuple, node_x->offset); } -static int -linear_dense_node_cmp(const void *node_a, const void *node_b, void *arg) -{ - DenseTreeIndex *index = (DenseTreeIndex *) arg; - const struct dense_node *node_xa = node_a; - const struct dense_node *node_xb = node_b; - return linear_node_compare(index->key_def, index->first_field, - node_xa->tuple, node_xa->offset, - node_xb->tuple, node_xb->offset); -} - -static int -linear_dense_dup_node_cmp(const void *node_a, const void *node_b, void *arg) -{ - int r = linear_dense_node_cmp(node_a, node_b, arg); - if (r == 0) { - const struct dense_node *node_xa = node_a; - const struct dense_node *node_xb = node_b; - r = ta_cmp(node_xa->tuple, node_xb->tuple); - } - return r; -} - -static int -linear_dense_key_node_cmp(const void *key, const void * node, void *arg) -{ - DenseTreeIndex *index = (DenseTreeIndex *) arg; - const struct key_data *key_data = key; - const struct dense_node *node_x = node; - return linear_key_node_compare(index->key_def, key_data, - index->first_field, - node_x->tuple, node_x->offset); -} - @implementation DenseTreeIndex - (void) enable { [super enable]; first_field = find_first_field(key_def); - is_linear = key_is_linear(key_def); } - (size_t) node_size @@ -1206,17 +1065,17 @@ linear_dense_key_node_cmp(const void *key, const void * node, void *arg) - (tree_cmp_t) node_cmp { - return is_linear ? linear_dense_node_cmp : dense_node_cmp; + return dense_node_cmp; } - (tree_cmp_t) dup_node_cmp { - return is_linear ? linear_dense_dup_node_cmp : dense_dup_node_cmp; + return dense_dup_node_cmp; } - (tree_cmp_t) key_node_cmp { - return is_linear ? linear_dense_key_node_cmp : dense_key_node_cmp; + return dense_key_node_cmp; } - (void) fold: (void *) node :(struct box_tuple *) tuple @@ -1316,7 +1175,6 @@ num32_key_node_cmp(const void * key, const void * node, void *arg) @public u32 first_field; u32 first_offset; - bool is_linear; } @end @@ -1354,40 +1212,6 @@ fixed_key_node_cmp(const void *key, const void * node, void *arg) node_x->tuple, index->first_offset); } -static int -linear_fixed_node_cmp(const void *node_a, const void *node_b, void *arg) -{ - FixedTreeIndex *index = (FixedTreeIndex *) arg; - const struct fixed_node *node_xa = node_a; - const struct fixed_node *node_xb = node_b; - return linear_node_compare(index->key_def, index->first_field, - node_xa->tuple, index->first_offset, - node_xb->tuple, index->first_offset); -} - -static int -linear_fixed_dup_node_cmp(const void *node_a, const void *node_b, void *arg) -{ - int r = linear_fixed_node_cmp(node_a, node_b, arg); - if (r == 0) { - const struct fixed_node *node_xa = node_a; - const struct fixed_node *node_xb = node_b; - r = ta_cmp(node_xa->tuple, node_xb->tuple); - } - return r; -} - -static int -linear_fixed_key_node_cmp(const void *key, const void * node, void *arg) -{ - FixedTreeIndex *index = (FixedTreeIndex *) arg; - const struct key_data *key_data = key; - const struct fixed_node *node_x = node; - return linear_key_node_compare(index->key_def, key_data, - index->first_field, - node_x->tuple, index->first_offset); -} - @implementation FixedTreeIndex - (void) enable @@ -1395,7 +1219,6 @@ linear_fixed_key_node_cmp(const void *key, const void * node, void *arg) [super enable]; first_field = find_first_field(key_def); first_offset = find_fixed_offset(space, first_field, 0); - is_linear = key_is_linear(key_def); } - (size_t) node_size @@ -1405,17 +1228,17 @@ linear_fixed_key_node_cmp(const void *key, const void * node, void *arg) - (tree_cmp_t) node_cmp { - return is_linear ? linear_fixed_node_cmp : fixed_node_cmp; + return fixed_node_cmp; } - (tree_cmp_t) dup_node_cmp { - return is_linear ? linear_fixed_dup_node_cmp : fixed_dup_node_cmp; + return fixed_dup_node_cmp; } - (tree_cmp_t) key_node_cmp { - return is_linear ? linear_fixed_key_node_cmp : fixed_key_node_cmp; + return fixed_key_node_cmp; } - (void) fold: (void *) node :(struct box_tuple *) tuple diff --git a/test/box/admin.result b/test/box/admin.result index 078f65688c395807c0750840e0b45b50b5987776..0bd780a395a9bf4bd86dacb5814afe153e68308c 100644 --- a/test/box/admin.result +++ b/test/box/admin.result @@ -30,7 +30,6 @@ show configuration --- configuration: username: (null) - local_hot_standby: "false" bind_ipaddr: "INADDR_ANY" coredump: "false" admin_port: "33015" @@ -40,22 +39,14 @@ configuration: slab_alloc_minimal: "64" slab_alloc_factor: "2" work_dir: (null) - snap_dir: "." - wal_dir: "." pid_file: "box.pid" logger: "cat - >> tarantool.log" logger_nonblock: "true" io_collect_interval: "0" backlog: "1024" readahead: "16320" - snap_io_rate_limit: "0" - rows_per_wal: "50" - wal_writer_inbox_size: "16384" - wal_mode: "fsync_delay" - wal_fsync_delay: "0" - wal_dir_rescan_delay: "0.1" - panic_on_snap_error: "true" - panic_on_wal_error: "false" + snap_dir: "." + wal_dir: "." primary_port: "33013" secondary_port: "33014" too_long_threshold: "0.5" @@ -65,6 +56,14 @@ configuration: memcached_expire: "false" memcached_expire_per_loop: "1024" memcached_expire_full_sweep: "3600" + snap_io_rate_limit: "0" + rows_per_wal: "50" + wal_fsync_delay: "0" + wal_writer_inbox_size: "128" + local_hot_standby: "false" + wal_dir_rescan_delay: "0.1" + panic_on_snap_error: "true" + panic_on_wal_error: "false" replication_source: (null) space[0].enabled: "true" space[0].cardinality: "-1" @@ -98,6 +97,7 @@ info: version: "1.minor.patch-<rev>-<commit>" uptime: <uptime> pid: <pid> + wal_writer_pid: <pid> lsn: 3 recovery_lag: 0.000 recovery_last_update: 0.000 diff --git a/test/box/configuration.result b/test/box/configuration.result index 02ce2663e0ea8ef5208d62d04dc437e0c3129514..e84f963d5b25decb0c004351baedc83e69aa80fb 100644 --- a/test/box/configuration.result +++ b/test/box/configuration.result @@ -8,7 +8,6 @@ show configuration --- configuration: username: (null) - local_hot_standby: "false" bind_ipaddr: "INADDR_ANY" coredump: "false" admin_port: "33015" @@ -18,22 +17,14 @@ configuration: slab_alloc_minimal: "64" slab_alloc_factor: "2" work_dir: (null) - snap_dir: "." - wal_dir: "." pid_file: "box.pid" logger: "cat - >> tarantool.log" logger_nonblock: "true" io_collect_interval: "0" backlog: "1024" readahead: "16320" - snap_io_rate_limit: "0" - rows_per_wal: "50" - wal_writer_inbox_size: "16384" - wal_mode: "fsync_delay" - wal_fsync_delay: "0" - wal_dir_rescan_delay: "0.1" - panic_on_snap_error: "true" - panic_on_wal_error: "false" + snap_dir: "." + wal_dir: "." primary_port: "33013" secondary_port: "33014" too_long_threshold: "0.5" @@ -43,6 +34,14 @@ configuration: memcached_expire: "false" memcached_expire_per_loop: "1024" memcached_expire_full_sweep: "3600" + snap_io_rate_limit: "0" + rows_per_wal: "50" + wal_fsync_delay: "0" + wal_writer_inbox_size: "128" + local_hot_standby: "false" + wal_dir_rescan_delay: "0.1" + panic_on_snap_error: "true" + panic_on_wal_error: "false" replication_source: (null) space[0].enabled: "true" space[0].cardinality: "-1" @@ -71,7 +70,6 @@ show configuration --- configuration: username: (null) - local_hot_standby: "false" bind_ipaddr: "INADDR_ANY" coredump: "false" admin_port: "33015" @@ -81,22 +79,14 @@ configuration: slab_alloc_minimal: "64" slab_alloc_factor: "2" work_dir: (null) - snap_dir: "." - wal_dir: "." pid_file: "box.pid" logger: "cat - >> tarantool.log" logger_nonblock: "true" io_collect_interval: "0" backlog: "1024" readahead: "16320" - snap_io_rate_limit: "0" - rows_per_wal: "50" - wal_writer_inbox_size: "16384" - wal_mode: "fsync_delay" - wal_fsync_delay: "0" - wal_dir_rescan_delay: "0.1" - panic_on_snap_error: "true" - panic_on_wal_error: "false" + snap_dir: "." + wal_dir: "." primary_port: "33013" secondary_port: "33014" too_long_threshold: "0.5" @@ -106,6 +96,14 @@ configuration: memcached_expire: "false" memcached_expire_per_loop: "1024" memcached_expire_full_sweep: "3600" + snap_io_rate_limit: "0" + rows_per_wal: "50" + wal_fsync_delay: "0" + wal_writer_inbox_size: "128" + local_hot_standby: "false" + wal_dir_rescan_delay: "0.1" + panic_on_snap_error: "true" + panic_on_wal_error: "false" replication_source: (null) space[0].enabled: "false" space[0].cardinality: "-1" diff --git a/test/box/lua.result b/test/box/lua.result index 398da2507c8a6de94762259a8cb30f692413c2be..bc34a9d4fd314418369e25a1fb8ca6f9b5961772 100644 --- a/test/box/lua.result +++ b/test/box/lua.result @@ -17,7 +17,6 @@ lua for n in pairs(box) do print(' - box.', n) end - box.cfg - box.on_reload_configuration - box.update - - box.select_reverse_range - box.insert - box.select_limit - box.delete @@ -118,11 +117,11 @@ lua f1() call f1() Found 7 tuples: ['testing'] -['1'] +[1] ['false'] -['-1'] -['1.123'] -['1e+123'] +[4294967295] +[1] +[2784522993] ['nil'] lua f1=nil --- @@ -312,36 +311,35 @@ lua for k,v in pairs(box.cfg) do print(' - ', k, ': ', v) end --- - io_collect_interval: 0 - pid_file: box.pid + - panic_on_wal_error: false + - slab_alloc_factor: 2 - slab_alloc_minimal: 64 - - primary_port: 33013 - - log_level: 4 + - admin_port: 33015 + - logger: cat - >> tarantool.log + - too_long_threshold: 0.5 + - wal_dir_rescan_delay: 0.1 + - slab_alloc_arena: 0.1 + - wal_dir: . + - wal_writer_inbox_size: 128 + - secondary_port: 33014 + - backlog: 1024 + - rows_per_wal: 50 - logger_nonblock: true - memcached_expire_per_loop: 1024 - snap_dir: . - coredump: false + - snap_io_rate_limit: 0 + - primary_port: 33013 + - log_level: 4 + - memcached_space: 23 + - memcached_port: 0 - panic_on_snap_error: true + - local_hot_standby: false - memcached_expire_full_sweep: 3600 - replication_port: 0 + - bind_ipaddr: INADDR_ANY - wal_fsync_delay: 0 - - too_long_threshold: 0.5 - - slab_alloc_factor: 2 - - admin_port: 33015 - - logger: cat - >> tarantool.log - - snap_io_rate_limit: 0 - - wal_writer_inbox_size: 16384 - - backlog: 1024 - - wal_dir_rescan_delay: 0.1 - - wal_dir: . - - memcached_port: 0 - - wal_mode: fsync_delay - - local_hot_standby: false - readahead: 16320 - - panic_on_wal_error: false - - rows_per_wal: 50 - - secondary_port: 33014 - - bind_ipaddr: INADDR_ANY - - slab_alloc_arena: 0.1 - - memcached_space: 23 - memcached_expire: false ... lua for k,v in pairs(box.space[0]) do if type(v) ~= 'table' then print(' - ', k, ': ', v) end end @@ -359,36 +357,35 @@ lua for k,v in pairs(box.cfg) do print(' - ', k, ': ', v) end --- - io_collect_interval: 0 - pid_file: box.pid + - panic_on_wal_error: false + - slab_alloc_factor: 2 - slab_alloc_minimal: 64 - - primary_port: 33013 - - log_level: 4 + - admin_port: 33015 + - logger: cat - >> tarantool.log + - too_long_threshold: 0.5 + - wal_dir_rescan_delay: 0.1 + - slab_alloc_arena: 0.1 + - wal_dir: . + - wal_writer_inbox_size: 128 + - secondary_port: 33014 + - backlog: 1024 + - rows_per_wal: 50 - logger_nonblock: true - memcached_expire_per_loop: 1024 - snap_dir: . - coredump: false + - snap_io_rate_limit: 0 + - primary_port: 33013 + - log_level: 4 + - memcached_space: 23 + - memcached_port: 0 - panic_on_snap_error: true + - local_hot_standby: false - memcached_expire_full_sweep: 3600 - replication_port: 0 + - bind_ipaddr: INADDR_ANY - wal_fsync_delay: 0 - - too_long_threshold: 0.5 - - slab_alloc_factor: 2 - - admin_port: 33015 - - logger: cat - >> tarantool.log - - snap_io_rate_limit: 0 - - wal_writer_inbox_size: 16384 - - backlog: 1024 - - wal_dir_rescan_delay: 0.1 - - wal_dir: . - - memcached_port: 0 - - wal_mode: fsync_delay - - local_hot_standby: false - readahead: 16320 - - panic_on_wal_error: false - - rows_per_wal: 50 - - secondary_port: 33014 - - bind_ipaddr: INADDR_ANY - - slab_alloc_arena: 0.1 - - memcached_space: 23 - memcached_expire: false ... lua for k,v in pairs(box.space[0]) do if type(v) ~= 'table' then print(' - ', k, ': ', v) end end @@ -400,11 +397,11 @@ lua for k,v in pairs(box.space[0]) do if type(v) ~= 'table' then print(' - ', k, ... lua box.cfg.nosuchoption = 1 --- -error: 'Lua error: [string "box.cfg = {}..."]:51: Attempt to modify a read-only table' +error: 'Lua error: [string "box.cfg = {}..."]:50: Attempt to modify a read-only table' ... lua box.space[300] = 1 --- -error: 'Lua error: [string "box.cfg = {}..."]:51: Attempt to modify a read-only table' +error: 'Lua error: [string "box.cfg = {}..."]:50: Attempt to modify a read-only table' ... lua box.index.new('abc', 'cde') --- @@ -944,76 +941,3 @@ lua string.byte(box.pack('p', tonumber64(123))) --- - 8 ... -lua box.space[0]:truncate() ---- -... -call box.insert(0, 'tes1', 'tes2', 'tes3', 'tes4', 'tes5') -Found 1 tuple: -[829646196, 846423412, 863200628, 879977844, 896755060] -call box.update(0, 'tes1', '#p', 0, '') -Found 1 tuple: -[846423412, 863200628, 879977844, 896755060] -call box.update(0, 'tes2', '#p', 0, '') -Found 1 tuple: -[863200628, 879977844, 896755060] -call box.update(0, 'tes3', '#p', 0, '') -Found 1 tuple: -[879977844, 896755060] -call box.update(0, 'tes4', '#p', 0, '') -Found 1 tuple: -[896755060] -lua box.update(0, 'tes5', '#p', 0, '') ---- -error: 'UPDATE error: the new tuple has no fields' -... -lua box.space[0]:truncate() ---- -... - -# test box.update: INSERT field - -lua box.insert(0, 1, 3, 6, 9) ---- - - 1: {3, 6, 9} -... -lua box.update(0, 1, '!p', 1, 2) ---- - - 1: {2, 3, 6, 9} -... -lua box.update(0, 1, '!p!p!p!p', 3, 4, 3, 5, 4, 7, 4, 8) ---- - - 1: {2, 3, 4, 5, 6, 7, 8, 9} -... -lua box.update(0, 1, '!p!p!p', 9, 10, 9, 11, 9, 12) ---- - - 1: {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12} -... -lua box.space[0]:truncate() ---- -... -lua box.insert(0, 1, 'tuple') ---- - - 1: {'tuple'} -... -lua box.update(0, 1, '#p!p=p', 1, '', 1, 'inserted tuple', 1, 'set tuple') ---- - - 1: {'inserted tuple', 'set tuple'} -... -lua box.space[0]:truncate() ---- -... -lua box.insert(0, 1, 'tuple') ---- - - 1: {'tuple'} -... -lua box.update(0, 1, '=p!p#p', 1, 'set tuple', 1, 'inerted tuple', 1, '') ---- - - 1: {'inerted tuple'} -... -lua box.update(0, 1, '!p!p', 0, 3, 0, 2) ---- - - 3: {2, 1, 'inerted tuple'} -... -lua box.space[0]:truncate() ---- -... diff --git a/test/box/lua.test b/test/box/lua.test index 1b8c73a5086ddc0b9201a5a8d40375e19cf6a757..03020203ef27aeac37c9ff22c5d5bc62e10c5c5d 100644 --- a/test/box/lua.test +++ b/test/box/lua.test @@ -288,28 +288,3 @@ exec admin "lua tonumber64('18446744073709551615') + 1" exec admin "lua tonumber64(-1)" exec admin "lua tonumber64('184467440737095516155')" exec admin "lua string.byte(box.pack('p', tonumber64(123)))" -# test delete field -exec admin "lua box.space[0]:truncate()" -exec sql "call box.insert(0, 'tes1', 'tes2', 'tes3', 'tes4', 'tes5')" -exec sql "call box.update(0, 'tes1', '#p', 0, '')" -exec sql "call box.update(0, 'tes2', '#p', 0, '')" -exec sql "call box.update(0, 'tes3', '#p', 0, '')" -exec sql "call box.update(0, 'tes4', '#p', 0, '')" -exec admin "lua box.update(0, 'tes5', '#p', 0, '')" -exec admin "lua box.space[0]:truncate()" - -print """ -# test box.update: INSERT field -""" -exec admin "lua box.insert(0, 1, 3, 6, 9)" -exec admin "lua box.update(0, 1, '!p', 1, 2)" -exec admin "lua box.update(0, 1, '!p!p!p!p', 3, 4, 3, 5, 4, 7, 4, 8)" -exec admin "lua box.update(0, 1, '!p!p!p', 9, 10, 9, 11, 9, 12)" -exec admin "lua box.space[0]:truncate()" -exec admin "lua box.insert(0, 1, 'tuple')" -exec admin "lua box.update(0, 1, '#p!p=p', 1, '', 1, 'inserted tuple', 1, 'set tuple')" -exec admin "lua box.space[0]:truncate()" -exec admin "lua box.insert(0, 1, 'tuple')" -exec admin "lua box.update(0, 1, '=p!p#p', 1, 'set tuple', 1, 'inerted tuple', 1, '')" -exec admin "lua box.update(0, 1, '!p!p', 0, 3, 0, 2)" -exec admin "lua box.space[0]:truncate()" diff --git a/test/box/xlog.result b/test/box/xlog.result index 8faf70ef7bf22a5ae04a09d3289844e222f3d3c3..ba345f63be7ea6ca88bcef3857b726ffe294ab32 100644 --- a/test/box/xlog.result +++ b/test/box/xlog.result @@ -16,7 +16,7 @@ Insert OK, 1 row affected Stopping the server... 00000000000000000004.xlog.inprogress has been successfully renamed -# An inprogress xlog file with one record must be renamed during recovery. +# An inprogress xlog fle with one record must be renamed during recovery. 00000000000000000005.xlog.inprogress hash been successfully renamed diff --git a/test/box/xlog.test b/test/box/xlog.test index 170bbec31e1a76806a5833accc0be4b576d474db..748634e95b85b79ba873d47ffe962ac90420dfa2 100644 --- a/test/box/xlog.test +++ b/test/box/xlog.test @@ -44,7 +44,7 @@ if os.access(wal, os.F_OK) and not os.access(wal_inprogress, os.F_OK): print "00000000000000000004.xlog.inprogress has been successfully renamed" print """ -# An inprogress xlog file with one record must be renamed during recovery. +# An inprogress xlog fle with one record must be renamed during recovery. """ wal_inprogress = os.path.join(vardir, "00000000000000000005.xlog.inprogress") diff --git a/test/box_big/lua.result b/test/box_big/lua.result index f42e59f83b6602b689e6c7ebec3c6d5ec35ba69f..7824c223facbbab8a642fb92e964a64334222bac 100644 --- a/test/box_big/lua.result +++ b/test/box_big/lua.result @@ -70,10 +70,6 @@ call box.select_range(5, 1, 2, 'of') Found 2 tuples: ['00000001', 'of', 'might', 'and', 'magic'] ['00000000', 'of', 'puppets'] -call box.select_reverse_range(5, 1, 2, 'of') -Found 2 tuples: -['00000000', 'of', 'puppets'] -['00000001', 'of', 'might', 'and', 'magic'] lua box.space[5]:truncate() --- ... @@ -114,76 +110,3 @@ lua num2 == tonumber64('18446744073709551615') --- - true ... -lua box.insert('9', 0, 0) ---- - - 0: {0} -... -lua box.insert('9', 1, 0) ---- - - 1: {0} -... -lua box.insert('9', 2, 0) ---- - - 2: {0} -... -lua box.insert('9', 3, 0) ---- - - 3: {0} -... -lua box.insert('9', 4, 0) ---- - - 4: {0} -... -lua box.insert('9', 5, 0) ---- - - 5: {0} -... -lua box.insert('9', 6, 0) ---- - - 6: {0} -... -lua box.insert('9', 7, 0) ---- - - 7: {0} -... -lua box.insert('9', 8, 0) ---- - - 8: {0} -... -lua box.insert('9', 9, 0) ---- - - 9: {0} -... -lua box.select_range(9, 1, 10) ---- - - 0: {0} - - 1: {0} - - 2: {0} - - 3: {0} - - 4: {0} - - 5: {0} - - 6: {0} - - 7: {0} - - 8: {0} - - 9: {0} -... -lua box.select_reverse_range(9, 1, 10) ---- - - 9: {0} - - 8: {0} - - 7: {0} - - 6: {0} - - 5: {0} - - 4: {0} - - 3: {0} - - 2: {0} - - 1: {0} - - 0: {0} -... -lua box.select_reverse_range(9, 1, 4) ---- - - 9: {0} - - 8: {0} - - 7: {0} - - 6: {0} -... diff --git a/test/box_big/lua.test b/test/box_big/lua.test index 3484b4163ce145dff4e730815b17076aed4e9823..557f85498b9b7acc86008536441694908eeed1fb 100644 --- a/test/box_big/lua.test +++ b/test/box_big/lua.test @@ -36,7 +36,6 @@ exec sql "insert into t5 values ('01234567', 'new', 'world')" exec sql "insert into t5 values ('00000000', 'of', 'puppets')" exec sql "insert into t5 values ('00000001', 'of', 'might', 'and', 'magic')" exec sql "call box.select_range(5, 1, 2, 'of')" -exec sql "call box.select_reverse_range(5, 1, 2, 'of')" exec admin "lua box.space[5]:truncate()" # @@ -52,20 +51,3 @@ exec admin "lua num,num1,num2 = box.unpack('lll', tu[0], tu[0], tu[0])" exec admin "lua num == tonumber64('18446744073709551615')" exec admin "lua num1 == tonumber64('18446744073709551615')" exec admin "lua num2 == tonumber64('18446744073709551615')" - -# -# Lua select_reverse_range -# -exec admin "lua box.insert('9', 0, 0)" -exec admin "lua box.insert('9', 1, 0)" -exec admin "lua box.insert('9', 2, 0)" -exec admin "lua box.insert('9', 3, 0)" -exec admin "lua box.insert('9', 4, 0)" -exec admin "lua box.insert('9', 5, 0)" -exec admin "lua box.insert('9', 6, 0)" -exec admin "lua box.insert('9', 7, 0)" -exec admin "lua box.insert('9', 8, 0)" -exec admin "lua box.insert('9', 9, 0)" -exec admin "lua box.select_range(9, 1, 10)" -exec admin "lua box.select_reverse_range(9, 1, 10)" -exec admin "lua box.select_reverse_range(9, 1, 4)" diff --git a/test/box_big/sql.result b/test/box_big/sql.result index b306d8e1bcbf897c61fc6edc5d5e346ebc388869..edd17c839a35967ff17488eaaec2f02062072bb1 100644 --- a/test/box_big/sql.result +++ b/test/box_big/sql.result @@ -127,11 +127,11 @@ insert into t5 values ('41234567', 'part1_a', 'part2_a') Insert OK, 1 row affected lua for k, v in box.space[5]:pairs() do print(v) end --- -3978425819141910832: {'part1', 'part2'} -3978425819141910833: {'part1', 'part2'} -3978425819141910834: {'part1', 'part2_a'} -3978425819141910835: {'part1_a', 'part2'} -3978425819141910836: {'part1_a', 'part2_a'} +'01234567': {'part1', 'part2'} +'11234567': {'part1', 'part2'} +'21234567': {'part1', 'part2_a'} +'31234567': {'part1_a', 'part2'} +'41234567': {'part1_a', 'part2_a'} ... select * from t5 where k0='01234567' Found 1 tuple: @@ -337,8 +337,8 @@ insert into t4 values(3, 'Creature') Insert OK, 1 row affected lua for k, v in box.space[4]:pairs() do print(v) end --- -3: {7310034287886430787} -1: {7742357870522556737} +3: {'Creature'} +1: {'Aardvark'} 2: {'Bilimbi'} ... lua box.space[4].index[0].idx:min() @@ -351,11 +351,11 @@ error: 'Unsupported' ... lua box.space[4].index[1].idx:min() --- - - 1: {7742357870522556737} + - 1: {'Aardvark'} ... lua box.space[4].index[1].idx:max() --- - - 3: {7310034287886430787} + - 3: {'Creature'} ... delete from t4 where k0=1 Delete OK, 1 row affected diff --git a/test/box_big/tarantool.cfg b/test/box_big/tarantool.cfg index 97c4840d02e5f9550aadc677c5089d212c2850d5..ff574b31e74268e76ebb80fad58b3750ceebfa1b 100644 --- a/test/box_big/tarantool.cfg +++ b/test/box_big/tarantool.cfg @@ -143,17 +143,3 @@ space[8].index[0].type = "TREE" space[8].index[0].unique = 1 space[8].index[0].key_field[0].fieldno = 0 space[8].index[0].key_field[0].type = "NUM64" - -# lua select_reverse_range() testing -# https://blueprints.launchpad.net/tarantool/+spec/backward-tree-index-iterator -space[9].enabled = true -space[9].index[0].type = "TREE" -space[9].index[0].unique = 1 -space[9].index[0].key_field[0].fieldno = 0 -space[9].index[0].key_field[0].type = "NUM" -space[9].index[1].type = "TREE" -space[9].index[1].unique = 1 -space[9].index[1].key_field[0].fieldno = 1 -space[9].index[1].key_field[0].type = "NUM" -space[9].index[1].key_field[1].fieldno = 0 -space[9].index[1].key_field[1].type = "NUM" diff --git a/test/box_big/tree_variants.result b/test/box_big/tree_variants.result index 59f9601165245193ddbc2ec3b943d9513643c5d6..dcc277aced44fce47032a086a234ceac92e21254 100644 --- a/test/box_big/tree_variants.result +++ b/test/box_big/tree_variants.result @@ -31,34 +31,34 @@ Found 3 tuples: [5, '00000005', '00000300', 'Joe', 'Sixpack', 'Drinks', 'Miller Genuine Draft', 'bar', 2005] lua box.space[6]:select(3, 'Joe', 'Sixpack') --- - - 0: {3472328296227680304, 3472329395739308080, 'Joe', 'Sixpack', 'Drinks', 'Amstel', 'bar', 2000} - - 1: {3544385890265608240, 3472330495250935856, 'Joe', 'Sixpack', 'Drinks', 7954882400208119112, 'bar', 2001} - - 2: {3616443484303536176, 3472330495250935856, 'Joe', 'Sixpack', 'Drinks', 'Carlsberg', 'bar', 2002} - - 3: {3688501078341464112, 3472331594762563632, 'Joe', 'Sixpack', 'Drinks', 'Corona Extra', 'bar', 2003} - - 4: {3760558672379392048, 3472331594762563632, 'Joe', 'Sixpack', 'Drinks', 'Stella Artois', 'bar', 2004} - - 5: {3832616266417319984, 3472331594762563632, 'Joe', 'Sixpack', 'Drinks', 'Miller Genuine Draft', 'bar', 2005} + - 0: {'00000000', '00000100', 'Joe', 'Sixpack', 'Drinks', 'Amstel', 'bar', 2000} + - 1: {'00000001', '00000200', 'Joe', 'Sixpack', 'Drinks', 'Heineken', 'bar', 2001} + - 2: {'00000002', '00000200', 'Joe', 'Sixpack', 'Drinks', 'Carlsberg', 'bar', 2002} + - 3: {'00000003', '00000300', 'Joe', 'Sixpack', 'Drinks', 'Corona Extra', 'bar', 2003} + - 4: {'00000004', '00000300', 'Joe', 'Sixpack', 'Drinks', 'Stella Artois', 'bar', 2004} + - 5: {'00000005', '00000300', 'Joe', 'Sixpack', 'Drinks', 'Miller Genuine Draft', 'bar', 2005} ... lua box.space[6]:select(3, 'John') --- - - 6: {3904673860455247920, 3472332694274191408, 1852337994, 'Smoker', 1937008968, 'A Pipe', 'foo', 2006} - - 7: {3976731454493175856, 3472332694274191408, 1852337994, 'Smoker', 1937008968, 'A Bong', 'foo', 2007} - - 8: {4048789048531103792, 3472332694274191408, 1852337994, 'Smoker', 'Rolls', 'A Joint', 'foo', 2008} - - 9: {4120846642569031728, 3472332694274191408, 1852337994, 'Smoker', 'Rolls', 'A Blunt', 'foo', 2009} + - 6: {'00000006', '00000400', 1852337994, 'Smoker', 1937008968, 'A Pipe', 'foo', 2006} + - 7: {'00000007', '00000400', 1852337994, 'Smoker', 1937008968, 'A Bong', 'foo', 2007} + - 8: {'00000008', '00000400', 1852337994, 'Smoker', 'Rolls', 'A Joint', 'foo', 2008} + - 9: {'00000009', '00000400', 1852337994, 'Smoker', 'Rolls', 'A Blunt', 'foo', 2009} ... lua box.space[6]:select(4, 'A Pipe') --- - - 6: {3904673860455247920, 3472332694274191408, 1852337994, 'Smoker', 1937008968, 'A Pipe', 'foo', 2006} + - 6: {'00000006', '00000400', 1852337994, 'Smoker', 1937008968, 'A Pipe', 'foo', 2006} ... lua box.space[6]:select(4, 'Miller Genuine Draft', 'Drinks') --- - - 5: {3832616266417319984, 3472331594762563632, 'Joe', 'Sixpack', 'Drinks', 'Miller Genuine Draft', 'bar', 2005} + - 5: {'00000005', '00000300', 'Joe', 'Sixpack', 'Drinks', 'Miller Genuine Draft', 'bar', 2005} ... select * from t6 where k5 = 2007 Found 1 tuple: [7, '00000007', '00000400', 1852337994, 'Smoker', 1937008968, 'A Bong', 'foo', 2007] lua box.space[6]:select(6, 'Miller Genuine Draft', 'Drinks') --- - - 5: {3832616266417319984, 3472331594762563632, 'Joe', 'Sixpack', 'Drinks', 'Miller Genuine Draft', 'bar', 2005} + - 5: {'00000005', '00000300', 'Joe', 'Sixpack', 'Drinks', 'Miller Genuine Draft', 'bar', 2005} ... delete from t6 where k0 = 6 Delete OK, 1 row affected @@ -70,10 +70,10 @@ delete from t6 where k0 = 9 Delete OK, 1 row affected lua for k,v in box.space[6]:pairs() do print(v) end --- -0: {3472328296227680304, 3472329395739308080, 'Joe', 'Sixpack', 'Drinks', 'Amstel', 'bar', 2000} -1: {3544385890265608240, 3472330495250935856, 'Joe', 'Sixpack', 'Drinks', 7954882400208119112, 'bar', 2001} -2: {3616443484303536176, 3472330495250935856, 'Joe', 'Sixpack', 'Drinks', 'Carlsberg', 'bar', 2002} -3: {3688501078341464112, 3472331594762563632, 'Joe', 'Sixpack', 'Drinks', 'Corona Extra', 'bar', 2003} -4: {3760558672379392048, 3472331594762563632, 'Joe', 'Sixpack', 'Drinks', 'Stella Artois', 'bar', 2004} -5: {3832616266417319984, 3472331594762563632, 'Joe', 'Sixpack', 'Drinks', 'Miller Genuine Draft', 'bar', 2005} +0: {'00000000', '00000100', 'Joe', 'Sixpack', 'Drinks', 'Amstel', 'bar', 2000} +1: {'00000001', '00000200', 'Joe', 'Sixpack', 'Drinks', 'Heineken', 'bar', 2001} +2: {'00000002', '00000200', 'Joe', 'Sixpack', 'Drinks', 'Carlsberg', 'bar', 2002} +3: {'00000003', '00000300', 'Joe', 'Sixpack', 'Drinks', 'Corona Extra', 'bar', 2003} +4: {'00000004', '00000300', 'Joe', 'Sixpack', 'Drinks', 'Stella Artois', 'bar', 2004} +5: {'00000005', '00000300', 'Joe', 'Sixpack', 'Drinks', 'Miller Genuine Draft', 'bar', 2005} ... diff --git a/test/box_memcached/off.result b/test/box_memcached/off.result index 09a66bf7754dd681f95093698f8bb76967666aa2..24d2b54646cc080677bc67e4183a80a0d6360071 100644 --- a/test/box_memcached/off.result +++ b/test/box_memcached/off.result @@ -7,7 +7,6 @@ show configuration --- configuration: username: (null) - local_hot_standby: "false" bind_ipaddr: "INADDR_ANY" coredump: "false" admin_port: "33015" @@ -17,22 +16,14 @@ configuration: slab_alloc_minimal: "64" slab_alloc_factor: "2" work_dir: (null) - snap_dir: "." - wal_dir: "." pid_file: "box.pid" logger: "cat - >> tarantool.log" logger_nonblock: "true" io_collect_interval: "0" backlog: "1024" readahead: "16320" - snap_io_rate_limit: "0" - rows_per_wal: "50" - wal_writer_inbox_size: "16384" - wal_mode: "fsync_delay" - wal_fsync_delay: "0" - wal_dir_rescan_delay: "0.1" - panic_on_snap_error: "true" - panic_on_wal_error: "false" + snap_dir: "." + wal_dir: "." primary_port: "33013" secondary_port: "33014" too_long_threshold: "0.5" @@ -42,6 +33,14 @@ configuration: memcached_expire: "false" memcached_expire_per_loop: "1024" memcached_expire_full_sweep: "3600" + snap_io_rate_limit: "0" + rows_per_wal: "50" + wal_fsync_delay: "0" + wal_writer_inbox_size: "128" + local_hot_standby: "false" + wal_dir_rescan_delay: "0.1" + panic_on_snap_error: "true" + panic_on_wal_error: "false" replication_source: (null) space[0].enabled: "true" space[0].cardinality: "-1" diff --git a/test/box_replication/cfg/hot_standby.cfg b/test/box_replication/cfg/hot_standby.cfg index fc74b3539f9fe30a6b173f2f691567e6ad56d7ce..942b30442b4042c4a68a1687cd48dd20e6cc1a31 100644 --- a/test/box_replication/cfg/hot_standby.cfg +++ b/test/box_replication/cfg/hot_standby.cfg @@ -1,5 +1,3 @@ -slab_alloc_arena = 0.1 - pid_file = "tarantool.pid" logger="cat - >> tarantool.log" diff --git a/test/box_replication/cfg/master.cfg b/test/box_replication/cfg/master.cfg index 9118e6d22ee79571a91fe71a07062b6d105ad913..4309c50cc3b6ef86c6b8e1b04777fb7046f3637e 100644 --- a/test/box_replication/cfg/master.cfg +++ b/test/box_replication/cfg/master.cfg @@ -1,5 +1,3 @@ -slab_alloc_arena = 0.1 - pid_file = "tarantool.pid" logger="cat - >> tarantool.log" diff --git a/test/box_replication/cfg/master_to_replica.cfg b/test/box_replication/cfg/master_to_replica.cfg index 5d2ae2420cc0ee1f3924074f48c8335dfa60f3e2..54b9527dd21b6e5bb08b61b84ac3da606e902e91 100644 --- a/test/box_replication/cfg/master_to_replica.cfg +++ b/test/box_replication/cfg/master_to_replica.cfg @@ -1,5 +1,3 @@ -slab_alloc_arena = 0.1 - pid_file = "tarantool.pid" logger="cat - >> tarantool.log" diff --git a/test/box_replication/cfg/replica.cfg b/test/box_replication/cfg/replica.cfg index 590da237525087c01b6e96ce70b698bd7f8c6622..bc83fce68105a4ec41f6c9f9e764f53ec8891a86 100644 --- a/test/box_replication/cfg/replica.cfg +++ b/test/box_replication/cfg/replica.cfg @@ -1,5 +1,3 @@ -slab_alloc_arena = 0.1 - pid_file = "tarantool.pid" logger="cat - >> tarantool.log" diff --git a/test/box_replication/cfg/replica_to_master.cfg b/test/box_replication/cfg/replica_to_master.cfg index df97d6e341536dd90078f7c98ffa4daa4c0b03b0..aafe2c9aaffc5fb091bd25b4cdd3cd7b72e2f915 100644 --- a/test/box_replication/cfg/replica_to_master.cfg +++ b/test/box_replication/cfg/replica_to_master.cfg @@ -1,5 +1,3 @@ -slab_alloc_arena = 0.1 - pid_file = "tarantool.pid" logger="cat - >> tarantool.log" diff --git a/test/connector_c/update.c b/test/connector_c/update.c index c07db58b5a86897cad038b773e789fbf9c3a5e42..00a14198a2a1e7f118b4ec78b05779d3e30ba1c1 100644 --- a/test/connector_c/update.c +++ b/test/connector_c/update.c @@ -97,13 +97,6 @@ update_splice_str(struct tnt_stream *stream, i32 field, i32 offset, i32 length, void update_delete_field(struct tnt_stream *stream, i32 field); -/** add update fields operation: insert before int32 */ -void -update_insert_i32(struct tnt_stream *stream, i32 field, i32 value); - -/** add update fields operation: insert before string */ -void -update_insert_str(struct tnt_stream *stream, i32 field, char *str); /** receive reply from server */ void @@ -178,10 +171,6 @@ test_set_and_splice(); void test_delete_field(); -/** update fields test case: insert field operations test */ -void -test_insert_field(); - /** update fields test case: boundary arguments values test */ void test_boundary_args(); @@ -192,7 +181,7 @@ test_boundary_args(); *==========================================================================*/ int -main() +main(void) { /* initialize suite */ test_suite_setup(); @@ -206,7 +195,6 @@ main() test_splice(); test_set_and_splice(); test_delete_field(); - test_insert_field(); test_boundary_args(); /* clean-up suite */ test_suite_tear_down(); @@ -268,15 +256,13 @@ update_set_str(struct tnt_stream *stream, i32 field, char *str) { int result = tnt_update_assign(stream, field, str, strlen(str)); if (result < 0) - fail_tnt_error("tnt_update_assign", result); + fail_tnt_error("tnt_update_delete_field", result); } void -update_splice_str(struct tnt_stream *stream, i32 field, i32 offset, i32 length, - char *list) +update_splice_str(struct tnt_stream *stream, i32 field, i32 offset, i32 length, char *list) { - int result = tnt_update_splice(stream, field, offset, length, list, - strlen(list)); + int result = tnt_update_splice(stream, field, offset, length, list, strlen(list)); if (result < 0) fail_tnt_error("tnt_update_splice", result); } @@ -289,23 +275,6 @@ update_delete_field(struct tnt_stream *stream, i32 field) fail_tnt_error("tnt_update_delete", result); } -void -update_insert_i32(struct tnt_stream *stream, i32 field, i32 value) -{ - int result = tnt_update_insert(stream, field, (char *)&value, - sizeof(value)); - if (result < 0) - fail_tnt_error("tnt_update_insert", result); -} - -void -update_insert_str(struct tnt_stream *stream, i32 field, char *str) -{ - int result = tnt_update_insert(stream, field, str, strlen(str)); - if (result < 0) - fail_tnt_error("tnt_update_insert_before", result); -} - void recv_command(char *command) { @@ -814,6 +783,7 @@ test_set_and_splice() printf("<<< test set and splice done\n"); } +/** update fields test case: delete field operations test */ void test_delete_field() { @@ -922,87 +892,6 @@ test_delete_field() printf("<<< test delete field done\n"); } -void -test_insert_field() -{ - printf(">>> test insert field\n"); - - printf("# insert tuple\n"); - struct tnt_tuple *tuple = tnt_tuple(NULL, "%d%s", 9, "eleven"); - insert_tuple(tuple); - tnt_tuple_free(tuple); - - printf("# insert new field before primary key\n"); - struct tnt_stream *stream = tnt_buf(NULL); - update_insert_i32(stream, 0, 7); - update_insert_i32(stream, 0, 8); - update(9, stream); - tnt_stream_free(stream); - - printf("# insert a new field before last field\n"); - stream = tnt_buf(NULL); - update_insert_i32(stream, 3, 10); - update(7, stream); - tnt_stream_free(stream); - - printf("# double insert before set\n"); - stream = tnt_buf(NULL); - update_set_i32(stream, 5, 14); - update_insert_i32(stream, 5, 12); - update_insert_i32(stream, 5, 13); - update(7, stream); - tnt_stream_free(stream); - - printf("# insert before next to last field\n"); - stream = tnt_buf(NULL); - update_insert_i32(stream, 8, 15); - update(7, stream); - tnt_stream_free(stream); - - printf("# insert before next to last field\n"); - stream = tnt_buf(NULL); - update_set_i32(stream, 9, 17); - update_insert_i32(stream, 9, 16); - update_set_i32(stream, 10, 19); - update_insert_i32(stream, 10, 18); - update(7, stream); - tnt_stream_free(stream); - - printf("# insert second tuple\n"); - tuple = tnt_tuple(NULL, "%d%s%d", 0, "one", 11); - insert_tuple(tuple); - tnt_tuple_free(tuple); - - stream = tnt_buf(NULL); - printf("# multi insert\n"); - update_set_i32(stream, 1, -11); - tnt_update_arith(stream, 1, TNT_UPDATE_ADD, 1); - update_insert_i32(stream, 1, 1); - tnt_update_arith(stream, 1, TNT_UPDATE_ADD, 2); - update_insert_i32(stream, 1, 2); - update_insert_i32(stream, 1, 3); - tnt_update_arith(stream, 1, TNT_UPDATE_ADD, 3); - tnt_update_arith(stream, 1, TNT_UPDATE_ADD, 4); - tnt_update_arith(stream, 1, TNT_UPDATE_ADD, 5); - update_insert_i32(stream, 1, 4); - update_insert_i32(stream, 1, 5); - tnt_update_arith(stream, 1, TNT_UPDATE_ADD, 6); - update_insert_i32(stream, 1, 6); - update_insert_i32(stream, 1, 7); - update_insert_i32(stream, 1, 8); - update_insert_i32(stream, 1, 9); - update(0, stream); - tnt_stream_free(stream); - - printf("# insert before invalid field number\n"); - stream = tnt_buf(NULL); - update_insert_str(stream, 100000, "ooppps!"); - update(7, stream); - tnt_stream_free(stream); - - printf("<<< insert field test done\n"); -} - void test_boundary_args() { diff --git a/test/connector_c/update.result b/test/connector_c/update.result index 91fae1d54837d53c6115f214f37336ac5fae6ff1..6bb832216e84b4089acb403ba9360a42c53d7d96 100644 --- a/test/connector_c/update.result +++ b/test/connector_c/update.result @@ -241,34 +241,6 @@ update fields: respond ok (op: 19, reqid: 0, code: 13826, count: 0) select: respond ok (op: 17, reqid: 0, code: 0, count: 1) (1 (0x00000001), 9 (0x00000009), 10 (0x0000000a), 'fourth', 'fifth', 'eighth', 'ninth') <<< test delete field done ->>> test insert field -# insert tuple -insert: respond ok (op: 13, reqid: 0, code: 0, count: 1) -(9 (0x00000009), 'eleven') -# insert new field before primary key -update fields: respond ok (op: 19, reqid: 0, code: 0, count: 1) -(7 (0x00000007), 8 (0x00000008), 9 (0x00000009), 'eleven') -# insert a new field before last field -update fields: respond ok (op: 19, reqid: 0, code: 0, count: 1) -(7 (0x00000007), 8 (0x00000008), 9 (0x00000009), 10 (0x0000000a), 'eleven') -# double insert before set -update fields: respond ok (op: 19, reqid: 0, code: 0, count: 1) -(7 (0x00000007), 8 (0x00000008), 9 (0x00000009), 10 (0x0000000a), 'eleven', 12 (0x0000000c), 13 (0x0000000d), 14 (0x0000000e)) -# insert before next to last field -update fields: respond ok (op: 19, reqid: 0, code: 0, count: 1) -(7 (0x00000007), 8 (0x00000008), 9 (0x00000009), 10 (0x0000000a), 'eleven', 12 (0x0000000c), 13 (0x0000000d), 14 (0x0000000e), 15 (0x0000000f)) -# insert before next to last field -update fields: respond ok (op: 19, reqid: 0, code: 0, count: 1) -(7 (0x00000007), 8 (0x00000008), 9 (0x00000009), 10 (0x0000000a), 'eleven', 12 (0x0000000c), 13 (0x0000000d), 14 (0x0000000e), 15 (0x0000000f), 16 (0x00000010), 17 (0x00000011), 18 (0x00000012), 19 (0x00000013)) -# insert second tuple -insert: respond ok (op: 13, reqid: 0, code: 0, count: 1) -(0 (0x00000000), 'one', 11 (0x0000000b)) -# multi insert -update fields: respond ok (op: 19, reqid: 0, code: 0, count: 1) -(0 (0x00000000), 1 (0x00000001), 2 (0x00000002), 3 (0x00000003), 4 (0x00000004), 5 (0x00000005), 6 (0x00000006), 7 (0x00000007), 8 (0x00000008), 9 (0x00000009), 10 (0x0000000a), 11 (0x0000000b)) -# insert before invalid field number -update fields: respond ok (op: 19, reqid: 0, code: 13826, count: 0) -<<< insert field test done >>> test boundaty argumets values # insert tuple insert: respond ok (op: 13, reqid: 0, code: 0, count: 1) diff --git a/third_party/compat/sys/bsd_time.h b/third_party/compat/sys/bsd_time.h deleted file mode 100644 index a2cfe663efeb0030d971f5c6558a36d1839fbfe7..0000000000000000000000000000000000000000 --- a/third_party/compat/sys/bsd_time.h +++ /dev/null @@ -1,122 +0,0 @@ -/* $OpenBSD: time.h,v 1.11 2000/10/10 13:36:48 itojun Exp $ */ -/* $NetBSD: time.h,v 1.18 1996/04/23 10:29:33 mycroft Exp $ */ - -/* - * Copyright (c) 1982, 1986, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 THE REGENTS 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. - * - * @(#)time.h 8.2 (Berkeley) 7/10/94 - */ - -#ifndef _SYS_TTL_COMPAT_TIME_H_ -#define _SYS_TTL_COMPAT_TIME_H_ - -#include <sys/types.h> - -#ifndef TIMEVAL_TO_TIMESPEC -#define TIMEVAL_TO_TIMESPEC(tv, ts) { \ - (ts)->tv_sec = (tv)->tv_sec; \ - (ts)->tv_nsec = (tv)->tv_usec * 1000; \ -} -#endif - -#ifndef TIMESPEC_TO_TIMEVAL -#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ - (tv)->tv_sec = (ts)->tv_sec; \ - (tv)->tv_usec = (ts)->tv_nsec / 1000; \ -} -#endif - -/** - * Enable BSD timer macros for non-BSD code. - */ -#if !defined(__BSD) && !defined(__USE_BSD) - -/* Operations on timevals. */ -#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#define timercmp(tvp, uvp, cmp) \ - (((tvp)->tv_sec == (uvp)->tv_sec) ? \ - ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ - ((tvp)->tv_sec cmp (uvp)->tv_sec)) -#define timeradd(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ - if ((vvp)->tv_usec >= 1000000) { \ - (vvp)->tv_sec++; \ - (vvp)->tv_usec -= 1000000; \ - } \ - } while (0) -#define timersub(tvp, uvp, vvp) \ - do { \ - (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ - (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ - if ((vvp)->tv_usec < 0) { \ - (vvp)->tv_sec--; \ - (vvp)->tv_usec += 1000000; \ - } \ - } while (0) - -#endif /* !defined(__BSD) && !defined(__USE_BSD) */ - - -/* Operations on timespecs. - Include if missing (one API-call check should suffice). */ -#if !defined(timespecclear) - -#define timespecclear(tsp) (tsp)->tv_sec = (tsp)->tv_nsec = 0 -#define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec) -#define timespeccmp(tsp, usp, cmp) \ - (((tsp)->tv_sec == (usp)->tv_sec) ? \ - ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \ - ((tsp)->tv_sec cmp (usp)->tv_sec)) -#define timespecadd(tsp, usp, vsp) \ - do { \ - (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \ - (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \ - if ((vsp)->tv_nsec >= 1000000000L) { \ - (vsp)->tv_sec++; \ - (vsp)->tv_nsec -= 1000000000L; \ - } \ - } while (0) -#define timespecsub(tsp, usp, vsp) \ - do { \ - (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ - (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ - if ((vsp)->tv_nsec < 0) { \ - (vsp)->tv_sec--; \ - (vsp)->tv_nsec += 1000000000L; \ - } \ - } while (0) - -#endif /* !defined(timespecclear) */ - - -/* --- stuff got cut here - kostja, niels --- */ - -#endif /* !_SYS_TTL_COMPAT_TIME_H_ */ diff --git a/third_party/sptree.h b/third_party/sptree.h index 5a65bf9533aa886f9fe4414f6ea345a1064ab45c..0bae478873bcf39e611abe98111d696ba3d30d66 100644 --- a/third_party/sptree.h +++ b/third_party/sptree.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Mail.RU + * Copyright (C) 2010 Mail.RU * Copyright (C) 2010 Teodor Sigaev * * Redistribution and use in source and binary forms, with or without @@ -47,16 +47,16 @@ typedef struct sptree_node_pointers { } sptree_node_pointers; #define GET_SPNODE_LEFT(snp) ( (snp)->left ) -#define SET_SPNODE_LEFT(snp, v) (snp)->left = (v) -#define GET_SPNODE_RIGHT(snp) ( (snp)->right ) +#define SET_SPNODE_LEFT(snp, v) (snp)->left = (v) +#define GET_SPNODE_RIGHT(snp) ( (snp)->right ) #define SET_SPNODE_RIGHT(snp, v) (snp)->right = (v) #endif /* SPTREE_NODE_SELF */ #ifndef alpha -#define alpha ((double)0.75) +#define alpha ((double)0.75) #endif -#define COUNTALPHA(size) floor(log((double)(size))/log((double)1.0/alpha)) +#define COUNTALPHA(size) floor(log((double)(size))/log((double)1.0/alpha)) #define _GET_SPNODE_LEFT(n) GET_SPNODE_LEFT( t->lrpointers + (n) ) #define _SET_SPNODE_LEFT(n, v) SET_SPNODE_LEFT( t->lrpointers + (n), (v) ) @@ -76,22 +76,15 @@ typedef struct sptree_node_pointers { * int (*compare)(const void *key, const void *elem, void *arg), * int (*elemcompare)(const void *e1, const void *e2, void *arg), * void *arg) - * + * void* sptree_NAME_find(sptree_NAME *tree, void *key) * void sptree_NAME_insert(sptree_NAME *tree, void *value) * void sptree_NAME_delete(sptree_NAME *tree, void *value) - * void* sptree_NAME_find(sptree_NAME *tree, void *key) - * * spnode_t sptree_NAME_walk(sptree_NAME *t, void* array, spnode_t limit, spnode_t offset) - * void sptree_NAME_walk_cb(sptree_NAME *t, int (*cb)(void* cb_arg, void* elem), void *cb_arg) - * + * sptree_NAME_walk_cb(sptree_NAME *t, int (*cb)(void* cb_arg, void* elem), void *cb_arg ) * sptree_NAME_iterator* sptree_NAME_iterator_init(sptree_NAME *t) * void sptree_NAME_iterator_init_set(sptree_NAME *t, sptree_NAME_iterator **iterator, void *start) - * sptree_NAME_iterator* sptree_NAME_iterator_reverse_init(sptree_NAME *t) - * void sptree_NAME_iterator_reverse_init_set(sptree_NAME *t, sptree_NAME_iterator **iterator, void *start) - * void sptree_NAME_iterator_free(sptree_NAME_iterator *i) - * * void* sptree_NAME_iterator_next(sptree_NAME_iterator *i) - * void* sptree_NAME_iterator_reverse_next(sptree_NAME_iterator *i) + * void sptree_NAME_iterator_free(sptree_NAME_iterator *i) */ #define SPTREE_DEF(name, realloc) \ @@ -115,7 +108,8 @@ typedef struct sptree_##name { } sptree_##name; \ \ static spnode_t \ -sptree_##name##_mktree(sptree_##name *t, spnode_t depth, spnode_t start, spnode_t end) { \ +sptree_##name##_mktree(sptree_##name *t, spnode_t depth, \ + spnode_t start, spnode_t end) { \ spnode_t half = ( (end + start) >> 1 ), tmp; \ \ if (depth > t->max_depth) t->max_depth = depth; \ @@ -136,16 +130,16 @@ sptree_##name##_mktree(sptree_##name *t, spnode_t depth, spnode_t start, spnode_ \ static inline void \ sptree_##name##_init(sptree_##name *t, size_t elemsize, void *m, \ - spnode_t nm, spnode_t nt, \ - int (*compare)(const void *, const void *, void *), \ - int (*elemcompare)(const void *, const void *, void *), \ - void *arg) { \ + spnode_t nm, spnode_t nt, \ + int (*compare)(const void *, const void *, void *), \ + int (*elemcompare)(const void *, const void *, void *), \ + void *arg) { \ memset(t, 0, sizeof(*t)); \ t->members = m; \ t->max_size = t->size = t->nmember = nm; \ t->ntotal = (nt==0) ? nm : nt; \ t->compare = compare != NULL ? compare : elemcompare; \ - t->elemcompare = elemcompare != NULL ? elemcompare : compare; \ + t->elemcompare = elemcompare != NULL ? elemcompare : compare; \ t->arg = arg; \ t->elemsize = elemsize; \ t->garbage_head = t->root = SPNIL; \ @@ -175,12 +169,12 @@ sptree_##name##_init(sptree_##name *t, size_t elemsize, void *m, static inline void \ sptree_##name##_destroy(sptree_##name *t) { \ if (t == NULL) return; \ - free(t->members); \ - free(t->lrpointers); \ + free(t->members); \ + free(t->lrpointers); \ } \ \ static inline void* \ -sptree_##name##_find(sptree_##name *t, void *k) { \ +sptree_##name##_find(sptree_##name *t, void *k) { \ spnode_t node = t->root; \ while(node != SPNIL) { \ int r = t->compare(k, ITHELEM(t, node), t->arg); \ @@ -196,7 +190,7 @@ sptree_##name##_find(sptree_##name *t, void *k) { } \ \ static inline void* \ -sptree_##name##_first(sptree_##name *t) { \ +sptree_##name##_first(sptree_##name *t) { \ spnode_t node = t->root; \ spnode_t first = SPNIL; \ while (node != SPNIL) { \ @@ -209,7 +203,7 @@ sptree_##name##_first(sptree_##name *t) { } \ \ static inline void* \ -sptree_##name##_last(sptree_##name *t) { \ +sptree_##name##_last(sptree_##name *t) { \ spnode_t node = t->root; \ spnode_t last = SPNIL; \ while (node != SPNIL) { \ @@ -253,7 +247,7 @@ sptree_##name##_get_place(sptree_##name *t) { } \ \ static inline spnode_t \ -sptree_##name##_flatten_tree(sptree_##name *t, spnode_t root, spnode_t head) { \ +sptree_##name##_flatten_tree(sptree_##name *t, spnode_t root, spnode_t head){ \ spnode_t node; \ if (root == SPNIL) \ return head; \ @@ -516,22 +510,16 @@ typedef struct sptree_##name##_iterator { } sptree_##name##_iterator; \ \ static inline sptree_##name##_iterator * \ -sptree_##name##_iterator_alloc(sptree_##name *t) { \ - sptree_##name##_iterator *i = \ - realloc(NULL, sizeof(*i) + sizeof(spnode_t) * (t->max_depth + 1)); \ - i->t = t; \ - i->level = 0; \ - i->stack[0] = t->root; \ - return i; \ -} \ - \ -static inline sptree_##name##_iterator * \ -sptree_##name##_iterator_init(sptree_##name *t) { \ - sptree_##name##_iterator *i; \ +sptree_##name##_iterator_init(sptree_##name *t) { \ + sptree_##name##_iterator *i; \ spnode_t node; \ \ if (t->root == SPNIL) return NULL; \ - i = sptree_##name##_iterator_alloc(t); \ + \ + i = realloc(NULL, sizeof(*i) + sizeof(spnode_t) * (t->max_depth + 1)); \ + i->t = t; \ + i->level = 0; \ + i->stack[0] = t->root; \ \ while( (node = _GET_SPNODE_LEFT( i->stack[i->level] )) != SPNIL ) { \ i->level++; \ @@ -542,8 +530,7 @@ sptree_##name##_iterator_init(sptree_##name *t) { } \ \ static inline void \ -sptree_##name##_iterator_init_set(sptree_##name *t, sptree_##name##_iterator **i, \ - void *k) { \ +sptree_##name##_iterator_init_set(sptree_##name *t, sptree_##name##_iterator **i, void *k) { \ spnode_t node; \ int lastLevelEq = -1, cmp; \ \ @@ -582,71 +569,14 @@ sptree_##name##_iterator_init_set(sptree_##name *t, sptree_##name##_iterator **i (*i)->level = lastLevelEq; \ } \ \ -static inline sptree_##name##_iterator * \ -sptree_##name##_iterator_reverse_init(sptree_##name *t) { \ - sptree_##name##_iterator *i; \ - spnode_t node; \ - \ - if (t->root == SPNIL) return NULL; \ - i = sptree_##name##_iterator_alloc(t); \ - \ - while( (node = _GET_SPNODE_RIGHT( i->stack[i->level] )) != SPNIL ) { \ - i->level++; \ - i->stack[i->level] = node; \ - } \ - \ - return i; \ -} \ - \ -static inline void \ -sptree_##name##_iterator_reverse_init_set(sptree_##name *t, sptree_##name##_iterator **i, \ - void *k) { \ - spnode_t node; \ - int lastLevelEq = -1, cmp; \ - \ - if ((*i) == NULL || t->max_depth > (*i)->max_depth) \ - *i = realloc(*i, sizeof(**i) + sizeof(spnode_t) * (t->max_depth + 1)); \ - \ - (*i)->t = t; \ - (*i)->level = -1; \ - if (t->root == SPNIL) { \ - (*i)->max_depth = 0; \ - return; \ - } \ - \ - (*i)->max_depth = t->max_depth; \ - (*i)->stack[0] = t->root; \ - \ - node = t->root; \ - while(node != SPNIL) { \ - cmp = t->compare(k, ITHELEM(t, node), t->arg); \ - \ - (*i)->level++; \ - (*i)->stack[(*i)->level] = node; \ - \ - if (cmp < 0) { \ - (*i)->level--; \ - node = _GET_SPNODE_LEFT(node); \ - } else if (cmp > 0) { \ - node = _GET_SPNODE_RIGHT(node); \ - } else { \ - lastLevelEq = (*i)->level; \ - node = _GET_SPNODE_RIGHT(node); \ - } \ - } \ - \ - if (lastLevelEq >= 0) \ - (*i)->level = lastLevelEq; \ -} \ - \ static inline void \ -sptree_##name##_iterator_free(sptree_##name##_iterator *i) { \ +sptree_##name##_iterator_free(sptree_##name##_iterator *i) { \ if (i == NULL) return; \ free(i); \ } \ \ static inline void* \ -sptree_##name##_iterator_next(sptree_##name##_iterator *i) { \ +sptree_##name##_iterator_next(sptree_##name##_iterator *i) { \ sptree_##name *t; \ spnode_t node, returnNode = SPNIL; \ \ @@ -666,29 +596,6 @@ sptree_##name##_iterator_next(sptree_##name##_iterator *i) { } \ \ return (returnNode == SPNIL) ? NULL : ITHELEM(t, returnNode); \ -} \ - \ -static inline void* \ -sptree_##name##_iterator_reverse_next(sptree_##name##_iterator *i) { \ - sptree_##name *t; \ - spnode_t node, returnNode = SPNIL; \ - \ - if (i == NULL) return NULL; \ - \ - t = i->t; \ - if ( i->level >= 0 ) { \ - returnNode = i->stack[i->level]; \ - \ - node = _GET_SPNODE_LEFT( i->stack[i->level] ); \ - i->level--; \ - while( node != SPNIL ) { \ - i->level++; \ - i->stack[i->level] = node; \ - node = _GET_SPNODE_RIGHT( i->stack[i->level] ); \ - } \ - } \ - \ - return (returnNode == SPNIL) ? NULL : ITHELEM(t, returnNode); \ } #endif