From 4d796a8c3e5b56fda8a8345e4c48c5cde270bcbc Mon Sep 17 00:00:00 2001
From: Vladimir Davydov <vdavydov.dev@gmail.com>
Date: Tue, 31 Oct 2017 17:18:22 +0300
Subject: [PATCH] vinyl: abort bootstrap if vinyl directory is not empty

If the user sets snap_dir to an empty directory by mistake while leaving
vinyl_dir the same, tarantool will still bootstrap, but there is likely
to be errors like:

  vinyl.c:835 E> 512/0: dump failed: file './512/0/00000000000000000001.run' already exists
  vy_log.c:1095 E> failed to rotate metadata log: file './00000000000000000005.vylog' already exists

Even worse, it may eventually fail to restart with:

  vy_log.c:886 E> ER_MISSING_SNAPSHOT: Can't find snapshot

To avoid that, let's check the vinyl_dir on bootstrap and abort if it
contains vylog files left from previous setups.

Closes #2872
---
 src/box/vy_log.c          |  9 +++++++++
 test/box-tap/cfg.test.lua | 20 +++++++++++++++++++-
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/src/box/vy_log.c b/src/box/vy_log.c
index b2dcf5fa73..be50b357bb 100644
--- a/src/box/vy_log.c
+++ b/src/box/vy_log.c
@@ -848,6 +848,15 @@ vy_log_next_id(void)
 int
 vy_log_bootstrap(void)
 {
+	/*
+	 * Scan the directory to make sure there is no
+	 * vylog files left from previous setups.
+	 */
+	if (xdir_scan(&vy_log.dir) < 0 && errno != ENOENT)
+		return -1;
+	if (xdir_last_vclock(&vy_log.dir, NULL) >= 0)
+		panic("vinyl directory is not empty");
+
 	/* Add initial vclock to the xdir. */
 	struct vclock *vclock = malloc(sizeof(*vclock));
 	if (vclock == NULL) {
diff --git a/test/box-tap/cfg.test.lua b/test/box-tap/cfg.test.lua
index ace2b41cb4..2106e192e5 100755
--- a/test/box-tap/cfg.test.lua
+++ b/test/box-tap/cfg.test.lua
@@ -4,7 +4,7 @@ local tap = require('tap')
 local test = tap.test('cfg')
 local socket = require('socket')
 local fio = require('fio')
-test:plan(70)
+test:plan(71)
 
 --------------------------------------------------------------------------------
 -- Invalid values
@@ -367,5 +367,23 @@ os.exit(cnt1 < cnt2 - 8 and 0 or 1)
 ]]
 test:is(run_script(code), 0, "wal_max_size xlog rotation")
 
+--
+-- gh-2872 bootstrap is aborted if vinyl_dir contains vylog files
+-- left from previous runs
+--
+vinyl_dir = fio.tempdir()
+run_script(string.format([[
+box.cfg{vinyl_dir = '%s'}
+s = box.schema.space.create('test', {engine = 'vinyl'})
+s:create_index('pk')
+os.exit(0)
+]], vinyl_dir))
+code = string.format([[
+box.cfg{vinyl_dir = '%s'}
+os.exit(0)
+]], vinyl_dir)
+test:is(run_script(code), PANIC, "bootstrap from non-empty vinyl_dir")
+fio.rmdir(vinyl_dir)
+
 test:check()
 os.exit(0)
-- 
GitLab