From 3a73e5dcaa8c5e6cf647e94eb6dab98964c0193c Mon Sep 17 00:00:00 2001
From: Vladimir Davydov <vdavydov.dev@gmail.com>
Date: Mon, 10 Jul 2017 13:51:21 +0300
Subject: [PATCH] vinyl: add missing mem_list_version increment

vy_task_dump_new() deletes empty in-memory trees right away, but
doesn't increment vy_index->mem_list_version, which may result in
a read iterator crash accessing a deleted vy_mem.
---
 src/box/vinyl.c | 24 ++++++++++++++++--------
 1 file changed, 16 insertions(+), 8 deletions(-)

diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index a430adee78..8234da545c 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -1389,6 +1389,20 @@ vy_index_rotate_mem(struct vy_index *index)
 	return 0;
 }
 
+/**
+ * Remove an in-memory tree from the sealed list of a vinyl index,
+ * unaccount and delete it.
+ */
+static void
+vy_index_delete_mem(struct vy_index *index, struct vy_mem *mem)
+{
+	assert(!rlist_empty(&mem->in_sealed));
+	rlist_del_entry(mem, in_sealed);
+	vy_stmt_counter_sub(&index->stat.memory.count, &mem->count);
+	vy_mem_delete(mem);
+	index->mem_list_version++;
+}
+
 /**
  * Split a range if it has grown too big, return true if the range
  * was split. Splitting is done by making slices of the runs used
@@ -2467,12 +2481,9 @@ vy_task_dump_complete(struct vy_task *task)
 	rlist_foreach_entry_safe(mem, &index->sealed, in_sealed, next_mem) {
 		if (mem->generation > scheduler->dump_generation)
 			continue;
-		rlist_del_entry(mem, in_sealed);
-		vy_stmt_counter_sub(&index->stat.memory.count, &mem->count);
 		vy_stmt_counter_add(&index->stat.disk.dump.in, &mem->count);
-		vy_mem_delete(mem);
+		vy_index_delete_mem(index, mem);
 	}
-	index->mem_list_version++;
 	index->dump_lsn = dump_lsn;
 	index->stat.disk.dump.count++;
 
@@ -2584,10 +2595,7 @@ vy_task_dump_new(struct vy_index *index, struct vy_task **p_task)
 			 * The tree is empty so we can delete it
 			 * right away, without involving a worker.
 			 */
-			vy_stmt_counter_sub(&index->stat.memory.count,
-					    &mem->count);
-			rlist_del_entry(mem, in_sealed);
-			vy_mem_delete(mem);
+			vy_index_delete_mem(index, mem);
 			continue;
 		}
 		dump_lsn = MAX(dump_lsn, mem->max_lsn);
-- 
GitLab