From f92473f39ae7f10ad9254ec004ef83658084d10d Mon Sep 17 00:00:00 2001
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
Date: Thu, 15 Feb 2018 22:07:47 +0300
Subject: [PATCH] test: vinyl secondary idx iterator skips changes of read keys

If a key is updated after a secondary index scan, but before a
primary index lookup, then ignore this update.

Closes #2442
---
 src/box/vinyl.c            |  8 +++++
 src/errinj.h               |  1 +
 test/box/errinj.result     |  2 ++
 test/vinyl/errinj.result   | 65 ++++++++++++++++++++++++++++++++++++++
 test/vinyl/errinj.test.lua | 23 ++++++++++++++
 5 files changed, 99 insertions(+)

diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index 69db2c81d3..df518fcc15 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -3868,6 +3868,14 @@ vinyl_iterator_next(struct iterator *base, struct tuple **ret)
 	}
 
 	if (it->index->id > 0) {
+#ifndef NDEBUG
+		struct errinj *delay = errinj(ERRINJ_VY_DELAY_PK_LOOKUP,
+					      ERRINJ_BOOL);
+		if (delay && delay->bparam) {
+			while (delay->bparam)
+				fiber_sleep(0.01);
+		}
+#endif
 		/* Get the full tuple from the primary index. */
 		if (vy_index_get(it->index->pk, it->tx, it->rv,
 				 tuple, &tuple) != 0)
diff --git a/src/errinj.h b/src/errinj.h
index 512d2342f3..20f3824cfa 100644
--- a/src/errinj.h
+++ b/src/errinj.h
@@ -105,6 +105,7 @@ struct errinj {
 	_(ERRINJ_BUILD_SECONDARY, ERRINJ_INT, {.iparam = -1}) \
 	_(ERRINJ_VY_POINT_ITER_WAIT, ERRINJ_BOOL, {.bparam = false}) \
 	_(ERRINJ_RELAY_EXIT_DELAY, ERRINJ_DOUBLE, {.dparam = 0}) \
+	_(ERRINJ_VY_DELAY_PK_LOOKUP, ERRINJ_BOOL, {.bparam = false}) \
 
 ENUM0(errinj_id, ERRINJ_LIST);
 extern struct errinj errinjs[];
diff --git a/test/box/errinj.result b/test/box/errinj.result
index 3551851694..4ef7e887c1 100644
--- a/test/box/errinj.result
+++ b/test/box/errinj.result
@@ -30,6 +30,8 @@ errinj.info()
     state: false
   ERRINJ_VYRUN_INDEX_GARBAGE:
     state: false
+  ERRINJ_VY_DELAY_PK_LOOKUP:
+    state: false
   ERRINJ_VY_TASK_COMPLETE:
     state: false
   ERRINJ_PORT_DUMP:
diff --git a/test/vinyl/errinj.result b/test/vinyl/errinj.result
index 8aaa47457d..5e4037cfda 100644
--- a/test/vinyl/errinj.result
+++ b/test/vinyl/errinj.result
@@ -1194,3 +1194,68 @@ box.commit()
 s:drop()
 ---
 ...
+--
+-- gh-2442: secondary index cursor must skip key update, made
+-- after the secondary index scan, but before a primary index
+-- lookup. It is ok, and the test checks this.
+--
+s = box.schema.create_space('test', {engine = 'vinyl'})
+---
+...
+pk = s:create_index('pk')
+---
+...
+sk = s:create_index('sk', {parts = {{2, 'unsigned'}}})
+---
+...
+s:replace{1, 1}
+---
+- [1, 1]
+...
+s:replace{3, 3}
+---
+- [3, 3]
+...
+box.snapshot()
+---
+- ok
+...
+ret = nil
+---
+...
+function do_read() ret = sk:select({2}, {iterator = 'GE'}) end
+---
+...
+errinj.set("ERRINJ_VY_DELAY_PK_LOOKUP", true)
+---
+- ok
+...
+f = fiber.create(do_read)
+---
+...
+f:status()
+---
+- suspended
+...
+ret
+---
+- null
+...
+s:replace{2, 2}
+---
+- [2, 2]
+...
+errinj.set("ERRINJ_VY_DELAY_PK_LOOKUP", false)
+---
+- ok
+...
+while ret == nil do fiber.sleep(0.01) end
+---
+...
+ret
+---
+- - [3, 3]
+...
+s:drop()
+---
+...
diff --git a/test/vinyl/errinj.test.lua b/test/vinyl/errinj.test.lua
index 45eed72eba..bbfb44abda 100644
--- a/test/vinyl/errinj.test.lua
+++ b/test/vinyl/errinj.test.lua
@@ -466,3 +466,26 @@ value
 box.commit()
 
 s:drop()
+
+--
+-- gh-2442: secondary index cursor must skip key update, made
+-- after the secondary index scan, but before a primary index
+-- lookup. It is ok, and the test checks this.
+--
+s = box.schema.create_space('test', {engine = 'vinyl'})
+pk = s:create_index('pk')
+sk = s:create_index('sk', {parts = {{2, 'unsigned'}}})
+s:replace{1, 1}
+s:replace{3, 3}
+box.snapshot()
+ret = nil
+function do_read() ret = sk:select({2}, {iterator = 'GE'}) end
+errinj.set("ERRINJ_VY_DELAY_PK_LOOKUP", true)
+f = fiber.create(do_read)
+f:status()
+ret
+s:replace{2, 2}
+errinj.set("ERRINJ_VY_DELAY_PK_LOOKUP", false)
+while ret == nil do fiber.sleep(0.01) end
+ret
+s:drop()
-- 
GitLab