diff --git a/.gitmodules b/.gitmodules index 3fe5a7f033aff5ea06feebcc9290bb19f8667238..0705e3f49682503bc64771c3768d95969d31ece7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -17,6 +17,6 @@ path = third_party/luafun url = https://github.com/rtsisyk/luafun.git [submodule "sophia"] - path = third_party/sophia - url = https://github.com/pmwkaa/sophia.git - branch = dev + path = third_party/sophia + url = https://github.com/pmwkaa/sophia.git + branch = dev diff --git a/extra/dist/default/tarantool b/extra/dist/default/tarantool new file mode 100644 index 0000000000000000000000000000000000000000..3efafa35fe99bd8ec5450ad140cf5af840e87af4 --- /dev/null +++ b/extra/dist/default/tarantool @@ -0,0 +1,10 @@ + + +SNAPS=/var/lib/tarantool +XLOGS=/var/lib/tarantool +LOGS=/var/log/tarantool +PIDS=/var/pid/tarantool +USERNAME=tarantool + + +# vim: set ft=sh : diff --git a/extra/dist/dist.lua b/extra/dist/dist.lua new file mode 100755 index 0000000000000000000000000000000000000000..533bef8d9d2b3c4755d57fdbcc9ddb85b405928c --- /dev/null +++ b/extra/dist/dist.lua @@ -0,0 +1,216 @@ +#!env tarantool + +local DEFAULTS = '/etc/default/tarantool' +local DEFAULT_CFG = { + PIDS = '/var/pid/tarantool', + SNAPS = '/var/lib/tarantool', + XLOGS = '/var/lib/tarantool', + LOGS = '/var/log/tarantool', + USERNAME = 'tarantool', +} + +if os.getenv('TARANTOOL_DEFAULTS') ~= nil then + local nd = os.getenv('TARANTOOL_DEFAULTS') + if #nd then + DEFAULTS = nd + end +end + +local fio = require 'fio' +local log = require 'log' +local errno = require 'errno' +local yaml = require 'yaml' +local console = require 'console' +local socket = require 'socket' +local ffi = require 'ffi' + +ffi.cdef[[ int kill(int pid, int sig); ]] + + +function read_cfg(name) + if name == nil then + return {} + end + local stat = fio.stat(name) + if stat == nil then + log.error("Can't stat file %s: %s", name, errno.strerror()) + return {} + end + + local f = fio.open(name, 'O_RDONLY') + if f == nil then + log.error("Can't open file %s: %s", name, errno.strerror()) + return {} + end + + local data = f:read(32768) + if data == nil then + log.error("Can't read file %s: %s", name, errno.strerror()) + f:close() + return {} + end + f:close() + + local result = {} + repeat + local line + if string.match(data, "\n") == nil then + line = data + data = '' + else + line = string.match(data, "^(.-)\n") + data = string.sub(data, #line + 1 + 1) + end + + + local name, value = string.match(line, "^%s*(.-)%s*=%s*(.-)%s*$") + + if name ~= nil and value ~= nil and #name > 0 and #value > 0 then + if string.match(value, '^".*"$') ~= nil then + value = string.sub(value, 2, #value - 2) + elseif string.match(value, "^'.*'$") ~= nil then + value = string.sub(value, 2, #value - 2) + end + + if string.match(name, '^%s*#') == nil then + result[name] = value + end + end + + until #data == 0 + + return result +end + +if arg[1] == nil or arg[2] == nil then + log.error("Usage: dist.lua {start|stop} user_script.lua [ ... ]") + os.exit(-1) +end + + +local cfg = read_cfg(DEFAULTS) +for i, v in pairs(DEFAULT_CFG) do + if cfg[i] == nil then + cfg[i] = v + end +end + +local function mkdir(dirname) + log.info("mkdir %s", dirname) + if not fio.mkdir(dirname, tonumber('0750', 8)) then + log.error("Can't mkdir %s: %s", dirname, errno.strerror()) + os.exit(-1) + end + + if not fio.chown(dirname, cfg.USERNAME, cfg.USERNAME) then + log.error("Can't chown(%s, %s, %s): %s", + cfg.USERNAME, cfg.USERNAME, dirname, errno.strerror()) + end +end + +local cmd = arg[1] +local main_lua = arg[2] +for i = 0, 128 do + arg[i] = arg[i + 2] + if arg[i] == nil then + break + end +end + +local instance = fio.basename(main_lua, '.lua') + +local force_cfg = { + pid_file = fio.pathjoin(cfg.PIDS, instance .. '.pid'), + wal_dir = fio.pathjoin(cfg.XLOGS, instance), + snap_dir = fio.pathjoin(cfg.SNAPS, instance), + work_dir = fio.pathjoin(cfg.XLOGS, instance), + username = cfg.USERNAME, + logger = fio.pathjoin(cfg.LOGS, instance .. '.log'), + console = fio.pathjoin(cfg.PIDS, instance .. '.control'), + background = true, +} + + + +local orig_cfg = box.cfg +box.cfg = function(cfg) + for i, v in pairs(force_cfg) do + cfg[i] = v + end + local res = orig_cfg(cfg) + + log.info('Run console at %s', force_cfg.console) + console.listen(force_cfg.console) + + return res +end + + +if cmd == 'start' then + -- create PIDDIR + if fio.stat(cfg.PIDS) == nil then + mkdir(cfg.PIDS) + end + + -- create xlogdir + if fio.stat(force_cfg.wal_dir) == nil then + mkdir(force_cfg.wal_dir) + end + + -- create snapdir + if fio.stat(force_cfg.snap_dir) == nil then + mkdir(force_cfg.snap_dir) + end + dofile(main_lua) + +elseif cmd == 'stop' then + if fio.stat(force_cfg.pid_file) == nil then + log.error("Process is not running (pid: %s)", force_cfg.pid_file) + os.exit(-1) + end + + local f = fio.open(force_cfg.pid_file, 'O_RDONLY') + if f == nil then + log.error("Can't read pid file %s: %s", + force_cfg.pid_file, errno.strerror()) + end + + local str = f:read(64) + f:close() + + local pid = tonumber(str) + + if pid == nil or pid <= 0 then + log.error("Broken pid file %s", force_cfg.pid_file) + fio.unlink(force_cfg.pid_file) + os.exit(-1) + end + + if ffi.C.kill(pid, 15) < 0 then + log.error("Can't kill process %d: %s", pid, errno.strerror()) + fio.unlink(force_cfg.pid_file) + end + os.exit(-1) + +elseif cmd == 'logrotate' then + if fio.stat(force_cfg.console) == nil then + log.error("Process is not running (pid: %s)", force_cfg.pid_file) + os.exit(-1) + end + + local s = socket.tcp_connect('unix/', force_cfg.console) + if s == nil then + log.error("Can't connect to %s: %s", + force_cfg.console, errno.strerror()) + end + + s:write[[ + require('log'):rotate() + require('log').info("Rotate log file") + ]] + + os.exit(-1) +else + log.error("Unknown command '%s'", cmd) + os.exit(-1) +end diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt index a827e95026c59b53c14fea87538fa6790e496576..867cfb0404dc5ecf2a7cd491374fa98ba5d74569 100644 --- a/src/box/CMakeLists.txt +++ b/src/box/CMakeLists.txt @@ -7,6 +7,7 @@ lua_source(lua_sources lua/load_cfg.lua) lua_source(lua_sources lua/schema.lua) lua_source(lua_sources lua/tuple.lua) lua_source(lua_sources lua/session.lua) +lua_source(lua_sources lua/snap_daemon.lua) set(bin_sources) bin_source(bin_sources bootstrap.snap bootstrap.h) diff --git a/src/box/lua/call.cc b/src/box/lua/call.cc index 5e3a8171d5123973fed17118e62f7de992fdc3f4..9c3ab1c83086da95f8ced73b3e1a9af4df543189 100644 --- a/src/box/lua/call.cc +++ b/src/box/lua/call.cc @@ -51,8 +51,18 @@ #include "box/schema.h" /* contents of box.lua, misc.lua, box.net.lua respectively */ -extern char session_lua[], schema_lua[], load_cfg_lua[]; -static const char *lua_sources[] = { session_lua, schema_lua, load_cfg_lua, NULL }; +extern char session_lua[], + schema_lua[], + load_cfg_lua[], + snap_daemon_lua[]; + +static const char *lua_sources[] = { + session_lua, + schema_lua, + snap_daemon_lua, + load_cfg_lua, + NULL +}; /* * Functions, exported in box_lua.h should have prefix diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua index 232e4d2d26223064dfb9933b65d361890f642831..39e0de7ddafd117750e569f85891410d98297424 100644 --- a/src/box/lua/load_cfg.lua +++ b/src/box/lua/load_cfg.lua @@ -50,6 +50,10 @@ local default_cfg = { background = false, username = nil , coredump = false, + + -- snap_daemon + snapshot_period = 3600 * 4, + snapshot_count = 6, } -- dynamically settable options @@ -60,6 +64,10 @@ local dynamic_cfg = { io_collect_interval = ffi.C.box_set_io_collect_interval, too_long_threshold = ffi.C.box_set_too_long_threshold, snap_io_rate_limit = ffi.C.box_set_snap_io_rate_limit, + + -- snap_daemon + snapshot_period = box.internal.snap_daemon.set_snapshot_period, + snapshot_count = box.internal.snap_daemon.set_snapshot_count, } local function reload_cfg(oldcfg, newcfg) @@ -120,12 +128,14 @@ function box.cfg(cfg) box_configured = nil box.cfg = setmetatable(cfg, { - __newindex = function(table, index) - error('Attempt to modify a read-only table') - end, - __call = reload_cfg + __newindex = function(table, index) + error('Attempt to modify a read-only table') + end, + __call = reload_cfg, }) ffi.C.load_cfg() + + box.internal.snap_daemon.start() end jit.off(box.cfg) jit.off(reload_cfg) diff --git a/src/box/lua/snap_daemon.lua b/src/box/lua/snap_daemon.lua new file mode 100644 index 0000000000000000000000000000000000000000..aec2d047bf133f23a2f4be2d9e0162b402de0b1f --- /dev/null +++ b/src/box/lua/snap_daemon.lua @@ -0,0 +1,253 @@ +-- snap_daemon.lua (internal file) + +do + local log = require 'log' + local fiber = require 'fiber' + local fio = require 'fio' + local yaml = require 'yaml' + local errno = require 'errno' + + local PREFIX = 'snap_daemon' + + local daemon = { status = 'stopped' } + + local function sprintf(fmt, ...) return string.format(fmt, ...) end + + -- create snapshot, return true if no errors + local function snapshot() + log.info("%s: making snapshot...", PREFIX) + local s, e = pcall(function() box.snapshot() end) + if s then + return true + end + -- don't complain log if snapshot is already exists + if errno() == errno.EEXIST then + return false + end + log.error("%s: error while creating snapshot: %s", PREFIX, e) + return false + end + + -- create snapshot by several options + local function make_snapshot(last_snap) + + if box.cfg.snapshot_period == nil then + return false + end + + if not(box.cfg.snapshot_period > 0) then + return false + end + + + if last_snap == nil then + return snapshot() + end + + local vclock = box.info.vclock + local lsn = 0 + for i, vlsn in pairs(vclock) do + lsn = lsn + vlsn + end + + local snap_name = sprintf('%020d.snap', tonumber(lsn)) + if fio.basename(last_snap) == snap_name then + log.debug('%s: snapshot %s is already exists', PREFIX, last_snap) + return false + end + + local snstat = fio.stat(last_snap) + if snstat == nil then + log.error("%s: Can't stat %s: %s", + PREFIX, snaps[#snaps], errno.strerror()) + return false + end + if snstat.mtime <= fiber.time() + box.cfg.snapshot_period then + return snapshot(snaps) + end + end + + -- check filesystem and current time + local function process() + local snaps = fio.glob(fio.pathjoin(box.cfg.snap_dir, '*.snap')) + + if snaps == nil then + log.error("%s: Can't read snap_dir: %s", PREFIX, errno.strerror()) + return + end + + if not make_snapshot(snaps[#snaps]) then + return + end + + -- cleanup code + if box.cfg.snapshot_count == nil then + return + end + + if not (box.cfg.snapshot_count > 0) then + return + end + + + -- reload snap list after snapshot + snaps = fio.glob(fio.pathjoin(box.cfg.snap_dir, '*.snap')) + local xlogs = fio.glob(fio.pathjoin(box.cfg.wal_dir, '*.xlog')) + if xlogs == nil then + log.error("%s: Can't read wal_dir: %s", PREFIX, errno.strerror()) + return + end + + while #snaps > box.cfg.snapshot_count do + local rm = snaps[1] + table.remove(snaps, 1) + + log.info("%s: Removing old snapshot %s", PREFIX, rm) + if not fio.unlink(rm) then + log.error("%s: Error while removing %s: %s", + PREFIX, rm, errno.strerror()) + return + end + end + + + local snapno = fio.basename(snaps[1], '.snap') + + while #xlogs > 0 do + if #xlogs < 2 then + break + end + + if fio.basename(xlogs[1], '.xlog') > snapno then + break + end + + if fio.basename(xlogs[2], '.xlog') > snapno then + break + end + + + local rm = xlogs[1] + table.remove(xlogs, 1) + log.info("%s: Removing old xlog %s", PREFIX, rm) + + if not fio.unlink(rm) then + log.error("%s: Error while removing %s: %s", + PREFIX, rm, errno.strerror()) + return + end + end + end + + + local function next_snap_interval() + local interval + + if box.cfg.snapshot_period == nil or box.cfg.snapshot_period <= 0 then + return interval + end + + local interval = box.cfg.snapshot_period / 10 + + local time = fiber.time() + local snaps = fio.glob(fio.pathjoin(box.cfg.snap_dir, '*.snap')) + if snaps == nil or #snaps == 0 then + return interval + end + + local last_snap = snaps[ #snaps ] + local stat = fio.stat(last_snap) + + if stat == nil then + return interval + end + + + -- there is no activity in xlogs + if box.cfg.snapshot_period * 2 + stat.mtime < time then + return interval + end + + local time_left = box.cfg.snapshot_period + stat.mtime - time + if time_left > 0 then + return time_left + end + + return interval + + end + + local function daemon_fiber(self) + fiber.name(PREFIX) + log.info("%s: status: %s", PREFIX, self.status) + while true do + local interval = next_snap_interval() + fiber.sleep(interval) + if self.status ~= 'started' then + break + end + + local s, e = pcall(process) + + if not s then + log.error("%s: %s", PREFIX, e) + end + end + log.info("%s: status: %s", PREFIX, self.status) + log.info("%s: finished daemon fiber", PREFIX) + end + + setmetatable(daemon, { + __index = { + start = function() + local daemon = box.internal[PREFIX] or daemon + if daemon.status == 'started' then + error( + sprintf("%s: %s", PREFIX, "Daemon is already started")) + end + daemon.status = 'started' + daemon.fiber = fiber.create(daemon_fiber, daemon) + end, + + stop = function() + local daemon = box.internal[PREFIX] or daemon + if daemon.status == 'stopped' then + error( + sprintf('%s: %s', PREFIX, "Daemon is already stopped")) + end + daemon.status = 'stopped' + if daemon.fiber ~= nil then + daemon.fiber:wakeup() + end + daemon.fiber = nil + end, + + set_snapshot_period = function(snapshot_period) + local daemon = box.internal[PREFIX] or daemon + log.info("%s: new snapshot_period: %s", PREFIX, + tostring(snapshot_period)) + if daemon.fiber ~= nil then + daemon.fiber:wakeup() + end + return snapshot_period + end, + + set_snapshot_count = function(snapshot_count) + local daemon = box.internal[PREFIX] or daemon + log.info("%s: new snapshot_count: %s", + PREFIX, tostring(snapshot_count)) + + if daemon.fiber ~= nil then + daemon.fiber:wakeup() + end + return snapshot_period + end + } + }) + + if box.internal == nil then + box.internal = { [PREFIX] = daemon } + else + box.internal[PREFIX] = daemon + end +end diff --git a/src/lua/fiber.cc b/src/lua/fiber.cc index 216096a2845c7d8361eac0511ad37f4303dd0110..ee0eb3fa4b69be686c3065698f126f4d8f9833a8 100644 --- a/src/lua/fiber.cc +++ b/src/lua/fiber.cc @@ -505,12 +505,21 @@ lbox_fiber_time64(struct lua_State *L) return 1; } +static int +lbox_fiber_wakeup(struct lua_State *L) +{ + struct fiber *f = lbox_checkfiber(L, 1); + fiber_wakeup(f); + return 0; +} + static const struct luaL_reg lbox_fiber_meta [] = { {"id", lbox_fiber_id}, {"name", lbox_fiber_name}, {"cancel", lbox_fiber_cancel}, {"status", lbox_fiber_status}, {"testcancel", lbox_fiber_testcancel}, + {"wakeup", lbox_fiber_wakeup}, {"__index", lbox_fiber_index}, {"__gc", lbox_fiber_gc}, {NULL, NULL} diff --git a/src/lua/log.lua b/src/lua/log.lua index fdad8836637dea08104a4d4c3e40e055eff822a1..8b37eab52196a980c223529b21f05e1acab8e19b 100644 --- a/src/lua/log.lua +++ b/src/lua/log.lua @@ -20,7 +20,16 @@ ffi.cdef[[ ]] local function say(level, fmt, ...) - local str = string.format(fmt, ...) + local str + + args = { ... } + if not pcall(function() str = string.format(fmt, unpack(args)) end) then + str = fmt .. ' [' + for i = 1, select('#', ...) do + str = str .. select(i, ...) .. ', ' + end + str = str .. ']' + end local frame = debug.getinfo(3, "Sl") local line = 0 local file = 'eval' diff --git a/test/app/cfg.result b/test/app/cfg.result index 95ae0c7b722267ffe46671ff400ca4330fdbedb2..17f172e65116d1b808545b324c2852e5dffe3dc7 100644 --- a/test/app/cfg.result +++ b/test/app/cfg.result @@ -1,2 +1,2 @@ -false [string "-- load_cfg.lua - internal file..."]:97: Please call box.cfg{} first +false [string "-- load_cfg.lua - internal file..."]:105: Please call box.cfg{} first true table diff --git a/test/app/float_value.result b/test/app/float_value.result index e6c4ad1368da5444942e9d4c048530e8dce8584a..a590ec2707af2d28e27b03505d839c13886c13ac 100644 --- a/test/app/float_value.result +++ b/test/app/float_value.result @@ -1,23 +1,25 @@ box.cfg -1 pid_file:box.pid -2 slab_alloc_factor:2 -3 rows_per_wal:50 -4 background:false -5 logger:tarantool.log -6 slab_alloc_arena:0.1 -7 wal_dir:. -8 logger_nonblock:true -9 snap_dir:. -10 coredump:false -11 wal_mode:write -12 panic_on_snap_error:true -13 panic_on_wal_error:false -14 log_level:5 -15 admin:3313 +1 snapshot_count:6 +2 too_long_threshold:0.01 +3 slab_alloc_factor:2 +4 rows_per_wal:50 +5 background:false +6 logger:tarantool.log +7 slab_alloc_arena:0.1 +8 log_level:5 +9 logger_nonblock:true +10 snap_dir:. +11 coredump:false +12 wal_mode:write +13 pid_file:box.pid +14 panic_on_snap_error:true +15 panic_on_wal_error:false 16 readahead:16320 -17 too_long_threshold:0.01 -18 slab_alloc_minimal:64 -19 wal_dir_rescan_delay:0.1 +17 admin:3313 +18 wal_dir:. +19 snapshot_period:14400 +20 slab_alloc_minimal:64 +21 wal_dir_rescan_delay:0.1 ------------------------------------------------------ Check that too_long_threshold = 0.01 0.01 diff --git a/test/app/init_script.result b/test/app/init_script.result index ce6ab4aa1bf947f847f16d260135e17b143d1a27..54e60c1cf385cc8f3fbf63ce550a390baef5c085 100644 --- a/test/app/init_script.result +++ b/test/app/init_script.result @@ -3,26 +3,28 @@ -- box.cfg -1 too_long_threshold:0.5 -2 slab_alloc_factor:2 -3 slab_alloc_minimal:64 -4 background:false -5 logger:tarantool.log -6 slab_alloc_arena:1 -7 wal_dir:. -8 listen:3314 -9 logger_nonblock:true -10 snap_dir:. -11 coredump:false -12 wal_mode:write -13 panic_on_snap_error:true -14 panic_on_wal_error:false -15 pid_file:box.pid -16 admin:3313 -17 rows_per_wal:500000 -18 readahead:16320 -19 log_level:5 -20 wal_dir_rescan_delay:0.1 +1 snapshot_count:6 +2 pid_file:box.pid +3 slab_alloc_factor:2 +4 slab_alloc_minimal:64 +5 background:false +6 logger:tarantool.log +7 slab_alloc_arena:1 +8 log_level:5 +9 listen:3314 +10 logger_nonblock:true +11 snap_dir:. +12 coredump:false +13 wal_mode:write +14 too_long_threshold:0.5 +15 panic_on_snap_error:true +16 panic_on_wal_error:false +17 readahead:16320 +18 admin:3313 +19 rows_per_wal:500000 +20 wal_dir:. +21 snapshot_period:14400 +22 wal_dir_rescan_delay:0.1 -- -- Test insert from detached fiber -- diff --git a/test/box/admin.result b/test/box/admin.result index 717155b1c129d3a2ec15f484fbba8c965ab0da88..b6f0ca7529b7bbb64c390326dd7c35c59a37477e 100644 --- a/test/box/admin.result +++ b/test/box/admin.result @@ -18,11 +18,12 @@ help() ... box.cfg --- -- too_long_threshold: 0.5 +- snapshot_count: 6 + too_long_threshold: 0.5 slab_alloc_factor: 2 - rows_per_wal: 50 + slab_alloc_minimal: 64 background: false - readahead: 16320 + slab_alloc_arena: 0.1 log_level: 5 listen: <uri> logger_nonblock: true @@ -31,10 +32,11 @@ box.cfg wal_mode: write panic_on_snap_error: true panic_on_wal_error: false - slab_alloc_arena: 0.1 pid_file: tarantool.pid - slab_alloc_minimal: 64 + readahead: 16320 wal_dir: . + snapshot_period: 14400 + rows_per_wal: 50 wal_dir_rescan_delay: 0.1 ... space:insert{1, 'tuple'} diff --git a/test/box/cfg.result b/test/box/cfg.result index 3dee6fc5551bdfaa79ffb7f08b0d2918a904c10a..d5f4fefb435ad7fc83ce544d6320c4eec0e2bf8d 100644 --- a/test/box/cfg.result +++ b/test/box/cfg.result @@ -2,7 +2,7 @@ --# push filter 'admin: .*' to 'admin: <uri>' box.cfg.nosuchoption = 1 --- -- error: '[string "-- load_cfg.lua - internal file..."]:124: Attempt to modify a read-only +- error: '[string "-- load_cfg.lua - internal file..."]:132: Attempt to modify a read-only table' ... t = {} for k,v in pairs(box.cfg) do if type(v) ~= 'table' and type(v) ~= 'function' then table.insert(t, k..': '..tostring(v)) end end @@ -10,11 +10,12 @@ t = {} for k,v in pairs(box.cfg) do if type(v) ~= 'table' and type(v) ~= 'functi ... t --- -- - 'too_long_threshold: 0.5' +- - 'snapshot_count: 6' + - 'too_long_threshold: 0.5' - 'slab_alloc_factor: 2' - - 'rows_per_wal: 50' + - 'slab_alloc_minimal: 64' - 'background: false' - - 'readahead: 16320' + - 'slab_alloc_arena: 0.1' - 'log_level: 5' - 'primary: <uri> - 'logger_nonblock: true' @@ -23,10 +24,11 @@ t - 'wal_mode: write' - 'panic_on_snap_error: true' - 'panic_on_wal_error: false' - - 'slab_alloc_arena: 0.1' - 'pid_file: tarantool.pid' - - 'slab_alloc_minimal: 64' + - 'readahead: 16320' - 'wal_dir: .' + - 'snapshot_period: 14400' + - 'rows_per_wal: 50' - 'wal_dir_rescan_delay: 0.1' ... -- must be read-only @@ -38,11 +40,12 @@ t = {} for k,v in pairs(box.cfg) do if type(v) ~= 'table' and type(v) ~= 'functi ... t --- -- - 'too_long_threshold: 0.5' +- - 'snapshot_count: 6' + - 'too_long_threshold: 0.5' - 'slab_alloc_factor: 2' - - 'rows_per_wal: 50' + - 'slab_alloc_minimal: 64' - 'background: false' - - 'readahead: 16320' + - 'slab_alloc_arena: 0.1' - 'log_level: 5' - 'primary: <uri> - 'logger_nonblock: true' @@ -51,10 +54,11 @@ t - 'wal_mode: write' - 'panic_on_snap_error: true' - 'panic_on_wal_error: false' - - 'slab_alloc_arena: 0.1' - 'pid_file: tarantool.pid' - - 'slab_alloc_minimal: 64' + - 'readahead: 16320' - 'wal_dir: .' + - 'snapshot_period: 14400' + - 'rows_per_wal: 50' - 'wal_dir_rescan_delay: 0.1' ... --# clear filter diff --git a/test/box/misc.result b/test/box/misc.result index f144c5debf03902a95d1cf37a324d084b26a372d..59d1a1f60e010132f48ee7731552a3e2b23ba1fc 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -22,6 +22,7 @@ t - error - index - info + - internal - rollback - schema - session diff --git a/test/box/snap_daemon.result b/test/box/snap_daemon.result new file mode 100644 index 0000000000000000000000000000000000000000..164ef5994ff2b5cfd7c4484584aeed08f48d24c9 --- /dev/null +++ b/test/box/snap_daemon.result @@ -0,0 +1,110 @@ +fio = require 'fio' +--- +... +errno = require 'errno' +--- +... +fiber = require 'fiber' +--- +... +PERIOD = 0.03 +--- +... +--# setopt delimiter ';' +ffi = require 'ffi' +ffi.cdef[[int uname(char *buf)]] + +function uname() + local name = ffi.new('char[?]', 4096) + ffi.C.uname(name) + return ffi.string(name) +end + +if uname() ~= 'Linux' then + PERIOD = 1.5 +end + +--- +... +--# setopt delimiter '' +ffi = require 'ffi' +ffi.cdef[[int uname(char *buf)]] + +function uname() + local name = ffi.new('char[?]', 4096) + ffi.C.uname(name) + return ffi.string(name) +end + +if uname() ~= 'Linux' then + PERIOD = 1.5 +end + + +--- +... +space = box.schema.create_space('snap_daemon') +--- +... +space:create_index('pk', { type = 'tree', parts = { 1, 'num' }}) +--- +... +box.cfg{snapshot_period = PERIOD, snapshot_count = 2 } +--- +... +no = 1 +--- +... +-- first xlog +for i = 1, box.cfg.rows_per_wal + 10 do space:insert { no } no = no + 1 end +--- +... +-- second xlog +for i = 1, box.cfg.rows_per_wal + 10 do space:insert { no } no = no + 1 end +--- +... +-- wait for last snapshot +fiber.sleep(1.5 * PERIOD) +--- +... +-- third xlog +for i = 1, box.cfg.rows_per_wal + 10 do space:insert { no } no = no + 1 end +--- +... +-- fourth xlog +for i = 1, box.cfg.rows_per_wal + 10 do space:insert { no } no = no + 1 end +--- +... +-- wait for last snapshot +fiber.sleep(2.5 * PERIOD) +--- +... +snaps = fio.glob(fio.pathjoin(box.cfg.snap_dir, '*.snap')) +--- +... +xlogs = fio.glob(fio.pathjoin(box.cfg.wal_dir, '*.xlog')) +--- +... +#snaps == 2 or snaps +--- +- true +... +#xlogs > 0 +--- +- true +... +fio.basename(snaps[1], '.snap') >= fio.basename(xlogs[1], '.xlog') +--- +- true +... +-- restore default options +box.cfg{snapshot_period = 3600 * 4, snapshot_count = 4 } +--- +... +space:drop() +--- +... +PERIOD +--- +- 0.03 +... diff --git a/test/box/snap_daemon.test.lua b/test/box/snap_daemon.test.lua new file mode 100644 index 0000000000000000000000000000000000000000..82eb4385640416b351de2673113962dfc5060bfc --- /dev/null +++ b/test/box/snap_daemon.test.lua @@ -0,0 +1,60 @@ +fio = require 'fio' +errno = require 'errno' +fiber = require 'fiber' + + +PERIOD = 0.03 + +--# setopt delimiter ';' + +ffi = require 'ffi' +ffi.cdef[[int uname(char *buf)]] + +function uname() + local name = ffi.new('char[?]', 4096) + ffi.C.uname(name) + return ffi.string(name) +end + +if uname() ~= 'Linux' then + PERIOD = 1.5 +end + +--# setopt delimiter '' + + +space = box.schema.create_space('snap_daemon') +space:create_index('pk', { type = 'tree', parts = { 1, 'num' }}) + + +box.cfg{snapshot_period = PERIOD, snapshot_count = 2 } + + +no = 1 +-- first xlog +for i = 1, box.cfg.rows_per_wal + 10 do space:insert { no } no = no + 1 end +-- second xlog +for i = 1, box.cfg.rows_per_wal + 10 do space:insert { no } no = no + 1 end +-- wait for last snapshot +fiber.sleep(1.5 * PERIOD) +-- third xlog +for i = 1, box.cfg.rows_per_wal + 10 do space:insert { no } no = no + 1 end +-- fourth xlog +for i = 1, box.cfg.rows_per_wal + 10 do space:insert { no } no = no + 1 end + +-- wait for last snapshot +fiber.sleep(2.5 * PERIOD) + +snaps = fio.glob(fio.pathjoin(box.cfg.snap_dir, '*.snap')) +xlogs = fio.glob(fio.pathjoin(box.cfg.wal_dir, '*.xlog')) + +#snaps == 2 or snaps +#xlogs > 0 + +fio.basename(snaps[1], '.snap') >= fio.basename(xlogs[1], '.xlog') + +-- restore default options +box.cfg{snapshot_period = 3600 * 4, snapshot_count = 4 } +space:drop() + +PERIOD