diff --git a/src/box/vy_log.c b/src/box/vy_log.c index c17c00e192bfa24d5402473938d4617ca82585ab..8214b054e249557ccdc0109614f89282326335d6 100644 --- a/src/box/vy_log.c +++ b/src/box/vy_log.c @@ -1026,6 +1026,51 @@ vy_log_bootstrap(void) return 0; } +/** + * Return true if the last vylog is new and contains no user data + * (i.e. last entry is VY_LOG_SNAPSHOT). + * In case of any errors log them and return false. + */ +static bool +vy_log_last_entry_is_snapshot(void) +{ + const char *path = + vy_log_filename(vclock_sum(&vy_log.last_checkpoint)); + if (access(path, F_OK) < 0) { + say_error("Failed to access last vylog"); + return false; + } + struct xlog_cursor cursor; + if (xdir_open_cursor(&vy_log.dir, + vclock_sum(&vy_log.last_checkpoint), + &cursor) < 0) { + diag_log(); + diag_clear(diag_get()); + return false; + } + int rc; + struct xrow_header row; + while ((rc = xlog_cursor_next(&cursor, &row, false)) == 0) { + struct vy_log_record record; + rc = vy_log_record_decode(&record, &row); + if (rc < 0) + break; + if (record.type == VY_LOG_SNAPSHOT) { + rc = xlog_cursor_next(&cursor, &row, false); + if (rc <= 0) + break; + xlog_cursor_close(&cursor, false); + return true; + } + } + xlog_cursor_close(&cursor, false); + if (rc < 0) { + diag_log(); + diag_clear(diag_get()); + } + return false; +} + struct vy_recovery * vy_log_begin_recovery(const struct vclock *vclock, bool force_recovery) { @@ -1065,7 +1110,12 @@ vy_log_begin_recovery(const struct vclock *vclock, bool force_recovery) * So in case we are anyway in force recovery mode, let's * try to delete last .vylog file and continue recovery process. */ - if (!force_recovery) { + bool is_vylog_empty = vy_log_last_entry_is_snapshot(); + if (!is_vylog_empty) { + say_info("Last vylog is not empty. Its removal " + "may cause data loss!"); + } + if (!force_recovery && !is_vylog_empty) { diag_set(ClientError, ER_MISSING_SNAPSHOT); say_info("To bootstrap instance try to remove last " ".vylog file or run in force_recovery mode"); diff --git a/test/vinyl/gh-5823-crash_snapshot.lua b/test/vinyl/gh-5823-crash_snapshot.lua index fc48f94b2a42670f3ba02041c3a49513226a0692..fb408618ae9e3674438494d760162687fbaffa55 100644 --- a/test/vinyl/gh-5823-crash_snapshot.lua +++ b/test/vinyl/gh-5823-crash_snapshot.lua @@ -1,13 +1,11 @@ #!/usr/bin/env tarantool -- --- mode == 0: casual bootstrap; --- mode == 1: force recovery bootstrap; +-- mode == 1: casual bootstrap; -- mode == 2: casual bootstrap and fill in data. -- local mode = tonumber(arg[1]) box.cfg ({ - force_recovery = (mode == 1), }) if mode == 2 then diff --git a/test/vinyl/gh-5823-skip-newer-than-snap-vylog.result b/test/vinyl/gh-5823-skip-newer-than-snap-vylog.result index ed5ae19046b963f23fe082121e186bef3024c967..7e462bb158afabcc2393766accfeffe9ae6d1f18 100644 --- a/test/vinyl/gh-5823-skip-newer-than-snap-vylog.result +++ b/test/vinyl/gh-5823-skip-newer-than-snap-vylog.result @@ -7,9 +7,7 @@ test_run = require('test_run').new() -- 1. There's both memtx and vinyl data; -- 2. User starts checkpoint process; -- 3. In the most unsuitable moment instance crashes; --- 4. Recovering in the casual mode does not help; --- 5. Recovering in the force recovery mode solves the problem (deletes --- redundant vylog file). +-- 4. Recovering in the casual mode successes. -- test_run:cmd("create server test with script='vinyl/gh-5823-crash_snapshot.lua'") | --- @@ -19,38 +17,6 @@ test_run:cmd("start server test with args='2' with crash_expected=True") | --- | - false | ... --- Can't bootstrap instance without force_recovery. --- -test_run:cmd("start server test with args='0' with crash_expected=True") - | --- - | - false - | ... - -fio = require('fio') - | --- - | ... -fh = fio.open(fio.pathjoin(fio.cwd(), 'gh-5823-crash_snapshot.log'), {'O_RDONLY'}) - | --- - | ... -size = fh:seek(0, 'SEEK_END') - | --- - | ... -fh:seek(-256, 'SEEK_END') ~= nil - | --- - | - true - | ... -line = fh:read(256) - | --- - | ... -fh:close() - | --- - | - true - | ... -string.match(line, "Can\'t find snapshot") ~= nil - | --- - | - true - | ... - test_run:cmd("start server test with args='1'") | --- | - true diff --git a/test/vinyl/gh-5823-skip-newer-than-snap-vylog.test.lua b/test/vinyl/gh-5823-skip-newer-than-snap-vylog.test.lua index 829224f59b94cbeaa380710d72b219406a42b457..7db71638fe1e8ddaef914aa999dcbe6e7af6e32f 100644 --- a/test/vinyl/gh-5823-skip-newer-than-snap-vylog.test.lua +++ b/test/vinyl/gh-5823-skip-newer-than-snap-vylog.test.lua @@ -4,17 +4,10 @@ test_run = require('test_run').new() -- 1. There's both memtx and vinyl data; -- 2. User starts checkpoint process; -- 3. In the most unsuitable moment instance crashes; --- 4. Recovering in the casual mode does not help; --- 5. Recovering in the force recovery mode solves the problem (deletes --- redundant vylog file). +-- 4. Recovering in the casual mode successes. -- test_run:cmd("create server test with script='vinyl/gh-5823-crash_snapshot.lua'") test_run:cmd("start server test with args='2' with crash_expected=True") --- Can't bootstrap instance without force_recovery. --- -test_run:cmd("start server test with args='0' with crash_expected=True") -test_run:grep_log('test', "Can\'t find snapshot", nil, {filename='gh-5823-crash_snapshot.log'}) ~= nil - test_run:cmd("start server test with args='1'") test_run:cmd("switch test") box.space.test_v:select({5})