diff --git a/cfg/core_cfg.cfg_tmpl b/cfg/core_cfg.cfg_tmpl index 0bf06176f640c3631157e0b5ec74c6f27f870f80..9c695ebef3606f2f2159cbbc4acb0dbf8554b02a 100644 --- a/cfg/core_cfg.cfg_tmpl +++ b/cfg/core_cfg.cfg_tmpl @@ -76,6 +76,7 @@ rows_per_wal=500000, ro wal_writer_inbox_size=16384, ro # Defines fiber/data synchronization fsync(2) policy: +# "none": does not write to WAL # "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, diff --git a/include/recovery.h b/include/recovery.h index 0e46a5da0e6b1b325d97e19a6a730acc3af97293..d650604df253a9ddf1260bc36836440d2d13a908 100644 --- a/include/recovery.h +++ b/include/recovery.h @@ -71,6 +71,11 @@ struct remote { ev_tstamp recovery_lag, recovery_last_update_tstamp; }; +enum wal_mode { WAL_NONE = 0, WAL_WRITE, WAL_FSYNC, WAL_FSYNC_DELAY, WAL_MODE_MAX }; + +/** String constants for the supported modes. */ +extern const char *wal_mode_STRS[]; + struct recovery_state { i64 lsn, confirmed_lsn; /* The WAL we're currently reading/writing from/to. */ @@ -93,6 +98,7 @@ struct recovery_state { int flags; double wal_fsync_delay; struct wait_lsn wait_lsn; + enum wal_mode wal_mode; bool finalize; }; @@ -104,8 +110,10 @@ void recovery_init(const char *snap_dirname, const char *xlog_dirname, int rows_per_wal, const char *wal_mode, double wal_fsync_delay, int flags); -void recovery_update_mode(const char *wal_mode, double fsync_delay); -void recovery_update_io_rate_limit(double new_limit); +void recovery_update_mode(struct recovery_state *r, + const char *wal_mode, double fsync_delay); +void recovery_update_io_rate_limit(struct recovery_state *r, + double new_limit); void recovery_free(); void recover_snap(struct recovery_state *); void recover_existing_wals(struct recovery_state *); diff --git a/mod/box/box.m b/mod/box/box.m index 81114b3fdc8f47020b6a3774afd1f7001c2711fb..5bacba6c962a853fae7ef083c58783b1c0c058ad 100644 --- a/mod/box/box.m +++ b/mod/box/box.m @@ -485,8 +485,7 @@ mod_init(void) recover_row, cfg.rows_per_wal, cfg.wal_mode, cfg.wal_fsync_delay, init_storage ? RECOVER_READONLY : 0); - - recovery_update_io_rate_limit(cfg.snap_io_rate_limit); + recovery_update_io_rate_limit(recovery_state, cfg.snap_io_rate_limit); recovery_setup_panic(recovery_state, cfg.panic_on_snap_error, cfg.panic_on_wal_error); stat_base = stat_register(requests_strs, requests_MAX); diff --git a/src/recovery.m b/src/recovery.m index a29b39709c24c397cb3ad43dc04ba0e370a94f3f..f013631defe190ec11c0ec43ef7f9f59df69386d 100644 --- a/src/recovery.m +++ b/src/recovery.m @@ -102,6 +102,8 @@ struct recovery_state *recovery_state; static const u64 snapshot_cookie = 0; +const char *wal_mode_STRS[] = { "none", "write", "fsync", "fsync_delay", NULL }; + /* {{{ LSN API */ void @@ -185,6 +187,7 @@ recovery_init(const char *snap_dirname, const char *wal_dirname, assert(recovery_state == NULL); recovery_state = p0alloc(eter_pool, sizeof(struct recovery_state)); struct recovery_state *r = recovery_state; + recovery_update_mode(r, wal_mode, wal_fsync_delay); if (rows_per_wal <= 1) panic("unacceptable value of 'rows_per_wal'"); @@ -195,7 +198,7 @@ recovery_init(const char *snap_dirname, const char *wal_dirname, r->snap_dir->dirname = strdup(snap_dirname); r->wal_dir = &wal_dir; r->wal_dir->dirname = strdup(wal_dirname); - r->wal_dir->open_wflags = strcasecmp(wal_mode, "fsync") ? 0 : WAL_SYNC_FLAG; + r->wal_dir->open_wflags = r->wal_mode == WAL_FSYNC ? WAL_SYNC_FLAG : 0; r->rows_per_wal = rows_per_wal; r->wal_fsync_delay = wal_fsync_delay; wait_lsn_clear(&r->wait_lsn); @@ -203,10 +206,11 @@ recovery_init(const char *snap_dirname, const char *wal_dirname, } void -recovery_update_mode(const char *mode, double fsync_delay) +recovery_update_mode(struct recovery_state *r, + const char *mode, double fsync_delay) { - struct recovery_state *r = recovery_state; - (void) mode; + r->wal_mode = strindex(wal_mode_STRS, mode, WAL_MODE_MAX); + assert(r->wal_mode != WAL_MODE_MAX); /* No mutex lock: let's not bother with whether * or not a WAL writer thread is present, and * if it's present, the delay will be propagated @@ -217,9 +221,9 @@ recovery_update_mode(const char *mode, double fsync_delay) } void -recovery_update_io_rate_limit(double new_limit) +recovery_update_io_rate_limit(struct recovery_state *r, double new_limit) { - recovery_state->snap_io_rate_limit = new_limit * 1024 * 1024; + r->snap_io_rate_limit = new_limit * 1024 * 1024; } void @@ -1101,6 +1105,9 @@ wal_write(struct recovery_state *r, i64 lsn, u64 cookie, say_debug("wal_write lsn=%" PRIi64, lsn); ERROR_INJECT_RETURN(ERRINJ_WAL_IO); + if (r->wal_mode == WAL_NONE) + return 0; + struct wal_writer *writer = r->writer; struct wal_write_request *req = diff --git a/src/tarantool.m b/src/tarantool.m index f89e6f20229cd98874618a865d04cafa75d7f084..9baeddf8fad0a720c2148b52e3a68a41b221cd59 100644 --- a/src/tarantool.m +++ b/src/tarantool.m @@ -83,10 +83,9 @@ 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'"); + if (strindex(wal_mode_STRS, conf->wal_mode, + WAL_MODE_MAX) == WAL_MODE_MAX) { + out_warning(0, "wal_mode %s is not recognized", conf->wal_mode); return -1; } return 0; @@ -167,9 +166,9 @@ core_reload_config(const struct tarantool_cfg *old_conf, 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); + recovery_update_mode(recovery_state, new_conf->wal_mode, new_delay); - recovery_update_io_rate_limit(new_conf->snap_io_rate_limit); + recovery_update_io_rate_limit(recovery_state, new_conf->snap_io_rate_limit); ev_set_io_collect_interval(new_conf->io_collect_interval); diff --git a/src/util.m b/src/util.m index 1e6b0eaf9ca33f836f943d10884f057ce7dea4b5..e5d8bacdb581bb6f023bf3c8138462bce395c962 100644 --- a/src/util.m +++ b/src/util.m @@ -64,7 +64,7 @@ uint32_t strindex(const char **haystack, const char *needle, uint32_t hmax) { for (int index = 0; index != hmax && haystack[index]; index++) - if (strcmp(haystack[index], needle) == 0) + if (strcasecmp(haystack[index], needle) == 0) return index; return hmax; } diff --git a/test/box_wal/suite.ini b/test/box_wal/suite.ini new file mode 100644 index 0000000000000000000000000000000000000000..4e6e1ac3b279ef8d018b780017de1bb4ec13fc21 --- /dev/null +++ b/test/box_wal/suite.ini @@ -0,0 +1,9 @@ +[default] +description = tarantool/box, wal_mode = none +config = tarantool.cfg +# put disabled tests here +#disabled = xlog.test +# disabled = lua.test +# put disabled in valgrind test here +#valgrind_disabled = admin_coredump.test +#release_disabled = errinj.test diff --git a/test/box_wal/tarantool.cfg b/test/box_wal/tarantool.cfg new file mode 100644 index 0000000000000000000000000000000000000000..112bbd03a1f1fab0027f9926cfdfcb4abc393970 --- /dev/null +++ b/test/box_wal/tarantool.cfg @@ -0,0 +1,46 @@ +# +# Limit of memory used to store tuples to 100MB +# (0.1 GB) +# This effectively limits the memory, used by +# Tarantool. However, index and connection memory +# is stored outside the slab allocator, hence +# the effective memory usage can be higher (sometimes +# twice as high). +# +slab_alloc_arena = 0.1 + +# +# Store the pid in this file. Relative to +# startup dir. +# +pid_file = "box.pid" + +# +# Pipe the logs into the following process. +# +logger="cat - >> tarantool.log" + +# +# Read only and read-write port. +primary_port = 33013 +# Read-only port. +secondary_port = 33014 +# +# The port for administrative commands. +# +admin_port = 33015 +# +# Each write ahead log contains this many rows. +# When the limit is reached, Tarantool closes +# the WAL and starts a new one. +rows_per_wal = 50 +wal_mode = none + +# Define a simple space with 1 HASH-based +# primary key. +space[0].enabled = 1 +space[0].index[0].type = "HASH" +space[0].index[0].unique = 1 +space[0].index[0].key_field[0].fieldno = 0 +space[0].index[0].key_field[0].type = "NUM" + diff --git a/test/box_wal/wal_mode.result b/test/box_wal/wal_mode.result new file mode 100644 index 0000000000000000000000000000000000000000..f3e75a32d3578bcb543fd60873f5f41d18c9bc4d --- /dev/null +++ b/test/box_wal/wal_mode.result @@ -0,0 +1,36 @@ +lua box.cfg.wal_mode +--- + - none +... +insert into t0 values (1) +Insert OK, 1 row affected +insert into t0 values (2) +Insert OK, 1 row affected +insert into t0 values (3) +Insert OK, 1 row affected +select * from t0 where k0 = 1 +Found 1 tuple: +[1] +select * from t0 where k0 = 2 +Found 1 tuple: +[2] +select * from t0 where k0 = 3 +Found 1 tuple: +[3] +select * from t0 where k0 = 4 +No match +save snapshot +--- +ok +... +save snapshot +--- +fail: can't save snapshot, errno 17 (File exists) +... +lua box.space[0]:truncate() +--- +... +save snapshot +--- +ok +... diff --git a/test/box_wal/wal_mode.test b/test/box_wal/wal_mode.test new file mode 100644 index 0000000000000000000000000000000000000000..6f48bbf0d70c7404f9ec75f8b53ef32ac2ac5847 --- /dev/null +++ b/test/box_wal/wal_mode.test @@ -0,0 +1,13 @@ +# encoding: tarantool +exec admin "lua box.cfg.wal_mode" +exec sql "insert into t0 values (1)" +exec sql "insert into t0 values (2)" +exec sql "insert into t0 values (3)" +exec sql "select * from t0 where k0 = 1" +exec sql "select * from t0 where k0 = 2" +exec sql "select * from t0 where k0 = 3" +exec sql "select * from t0 where k0 = 4" +exec admin "save snapshot" +exec admin "save snapshot" +exec admin "lua box.space[0]:truncate()" +exec admin "save snapshot"