diff --git a/src/box/vy_cache.c b/src/box/vy_cache.c index 825bfd3b6c7f300772f6fefaec7963acd0f2c7fd..e526ab1ec1bf70f068d02469f63b90d627cf683f 100644 --- a/src/box/vy_cache.c +++ b/src/box/vy_cache.c @@ -766,11 +766,11 @@ vy_cache_iterator_restore(struct vy_cache_iterator *itr, if (!itr->search_started || itr->version == itr->cache->version) return 0; + bool pos_changed = false; itr->version = itr->cache->version; - struct tuple *prev_stmt = itr->curr_stmt; - if ((prev_stmt == NULL && itr->iterator_type == ITER_EQ) || - (prev_stmt != NULL && - prev_stmt != vy_cache_iterator_curr_stmt(itr))) { + if ((itr->curr_stmt == NULL && itr->iterator_type == ITER_EQ) || + (itr->curr_stmt != NULL && + itr->curr_stmt != vy_cache_iterator_curr_stmt(itr))) { /* * EQ search ended or the iterator was invalidated. * In either case the best we can do is restart the @@ -778,6 +778,7 @@ vy_cache_iterator_restore(struct vy_cache_iterator *itr, */ *stop = vy_cache_iterator_seek(itr, last_stmt); vy_cache_iterator_skip_to_read_view(itr, stop); + pos_changed = true; } else { /* * The iterator position is still valid, but new @@ -797,7 +798,7 @@ vy_cache_iterator_restore(struct vy_cache_iterator *itr, struct key_def *def = itr->cache->cmp_def; struct vy_cache_tree *tree = &itr->cache->cache_tree; struct vy_cache_tree_iterator pos = itr->curr_pos; - if (prev_stmt == NULL) + if (itr->curr_stmt == NULL) pos = vy_cache_tree_invalid_iterator(); while (true) { if (dir > 0) @@ -818,11 +819,14 @@ vy_cache_iterator_restore(struct vy_cache_iterator *itr, itr->curr_stmt = entry->stmt; tuple_ref(itr->curr_stmt); *stop = vy_cache_iterator_is_stop(itr, entry); + pos_changed = true; } if (cmp == 0) break; } } + if (!pos_changed) + return 0; vy_history_cleanup(history); if (itr->curr_stmt != NULL) { @@ -830,9 +834,8 @@ vy_cache_iterator_restore(struct vy_cache_iterator *itr, itr->curr_stmt); if (vy_history_append_stmt(history, itr->curr_stmt) != 0) return -1; - return prev_stmt != itr->curr_stmt; } - return 0; + return 1; } void diff --git a/src/box/vy_mem.c b/src/box/vy_mem.c index 7fa90cbd541183dd8d157484566d724e9fd6a4c6..e3b40083bba809c38968868f65750854283aaba0 100644 --- a/src/box/vy_mem.c +++ b/src/box/vy_mem.c @@ -595,10 +595,7 @@ vy_mem_iterator_restore(struct vy_mem_iterator *itr, if (!itr->search_started || itr->version == itr->mem->version) return 0; - const struct tuple *prev_stmt = itr->curr_stmt; vy_mem_iterator_seek(itr, last_stmt); - if (prev_stmt == itr->curr_stmt) - return 0; vy_history_cleanup(history); if (itr->curr_stmt != NULL && diff --git a/src/box/vy_read_iterator.c b/src/box/vy_read_iterator.c index 2864a2802e86129582ba7f0d0c3aa72b664d7d2f..ac8a410dbab60c15fc39e02b27a76a3dc554e45b 100644 --- a/src/box/vy_read_iterator.c +++ b/src/box/vy_read_iterator.c @@ -424,7 +424,9 @@ vy_read_iterator_restore_mem(struct vy_read_iterator *itr, * Make sure we don't read the old value * from the cache while applying UPSERTs. */ - itr->src[itr->cache_src].front_id = 0; + struct vy_read_src *cache_src = &itr->src[itr->cache_src]; + if (cache_src->front_id == itr->front_id) + vy_history_cleanup(&cache_src->history); } src->front_id = itr->front_id; return 0; diff --git a/src/box/vy_tx.c b/src/box/vy_tx.c index 5280befff5028353508d0266d9527eac147c8add..df3e5ec4fd0c32f362a291f1fed5c61b5d6cc797 100644 --- a/src/box/vy_tx.c +++ b/src/box/vy_tx.c @@ -1285,10 +1285,7 @@ vy_txw_iterator_restore(struct vy_txw_iterator *itr, if (!itr->search_started || itr->version == itr->tx->write_set_version) return 0; - struct txv *prev_txv = itr->curr_txv; vy_txw_iterator_seek(itr, last_stmt); - if (prev_txv == itr->curr_txv) - return 0; vy_history_cleanup(history); if (itr->curr_txv != NULL) { diff --git a/test/vinyl/stat.result b/test/vinyl/stat.result index 08da16587d840c57a730dc93af26da9eda0b3422..ff73d42af1d8b86bd4de96f9dd7a7651d5222c55 100644 --- a/test/vinyl/stat.result +++ b/test/vinyl/stat.result @@ -716,8 +716,8 @@ stat_diff(istat(), st) rows: 5 bytes: 5305 get: - rows: 9 - bytes: 9549 + rows: 5 + bytes: 5305 txw: iterator: lookup: 1 diff --git a/test/vinyl/upsert.result b/test/vinyl/upsert.result index 6c6d03d6d8924b5f358b2ebb7542422b5c856814..c807b5b52d839d39f77e36817b009a8035d78034 100644 --- a/test/vinyl/upsert.result +++ b/test/vinyl/upsert.result @@ -791,3 +791,47 @@ s:select({100}, 'GE') s:drop() --- ... +-- +-- Check that read iterator ignores a cached statement in case +-- the current key is updated while it yields on disk read. +-- +fiber = require('fiber') +--- +... +s = box.schema.space.create('test', {engine = 'vinyl'}) +--- +... +_ = s:create_index('pk') +--- +... +s:replace{10, 10} +--- +- [10, 10] +... +box.snapshot() +--- +- ok +... +s:get(10) -- add [10, 10] to the cache +--- +- [10, 10] +... +ch = fiber.channel(1) +--- +... +test_run:cmd("setopt delimiter ';'") +--- +- true +... +_ = fiber.create(function() ch:put(s:select()) end) +s:upsert({10, 10}, {{'+', 2, 10}}) +test_run:cmd("setopt delimiter ''"); +--- +... +ch:get() -- should see the UPSERT and return [10, 20] +--- +- - [10, 20] +... +s:drop() +--- +... diff --git a/test/vinyl/upsert.test.lua b/test/vinyl/upsert.test.lua index ef83e0f6f513856a4b2266740b0f725a1a582375..cf2873606098ee7fdcf92c1c0bd7c51d27030152 100644 --- a/test/vinyl/upsert.test.lua +++ b/test/vinyl/upsert.test.lua @@ -325,3 +325,21 @@ s:upsert({100}, {{'+', 2, 100}}) s:select({100}, 'GE') s:drop() + +-- +-- Check that read iterator ignores a cached statement in case +-- the current key is updated while it yields on disk read. +-- +fiber = require('fiber') +s = box.schema.space.create('test', {engine = 'vinyl'}) +_ = s:create_index('pk') +s:replace{10, 10} +box.snapshot() +s:get(10) -- add [10, 10] to the cache +ch = fiber.channel(1) +test_run:cmd("setopt delimiter ';'") +_ = fiber.create(function() ch:put(s:select()) end) +s:upsert({10, 10}, {{'+', 2, 10}}) +test_run:cmd("setopt delimiter ''"); +ch:get() -- should see the UPSERT and return [10, 20] +s:drop()