Tarantool development patches archive
 help / color / mirror / Atom feed
* [PATCH 0/4] vinyl: fix crash in vinyl_iterator_secondary_next()
@ 2018-05-15 14:08 Vladimir Davydov
  2018-05-15 14:08 ` [PATCH 1/4] vinyl: fix EQ check in run iterator Vladimir Davydov
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Vladimir Davydov @ 2018-05-15 14:08 UTC (permalink / raw)
  To: kostja; +Cc: tarantool-patches

Hopefully, this will fix the crash happening at Mail.Ru Cloud deployment.

https://github.com/tarantool/tarantool/issues/3393
https://github.com/tarantool/tarantool/commits/gh-3393-vy-fix-crash-in-sk-select

Vladimir Davydov (4):
  vinyl: fix EQ check in run iterator
  vinyl: fix lost key on dump completion
  vinyl: do not panic if secondary index is inconsistent with primary
  test: improve vinyl/select_consistency

 src/box/vinyl.c                        | 23 +++++++++++++++++++----
 src/box/vy_run.c                       | 13 ++++++++++++-
 src/box/vy_scheduler.c                 |  3 ++-
 test/vinyl/select_consistency.result   | 11 +++++++----
 test/vinyl/select_consistency.test.lua |  9 +++++----
 5 files changed, 45 insertions(+), 14 deletions(-)

-- 
2.11.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/4] vinyl: fix EQ check in run iterator
  2018-05-15 14:08 [PATCH 0/4] vinyl: fix crash in vinyl_iterator_secondary_next() Vladimir Davydov
@ 2018-05-15 14:08 ` Vladimir Davydov
  2018-05-15 19:05   ` Konstantin Osipov
  2018-05-15 14:08 ` [PATCH 2/4] vinyl: fix lost key on dump completion Vladimir Davydov
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: Vladimir Davydov @ 2018-05-15 14:08 UTC (permalink / raw)
  To: kostja; +Cc: tarantool-patches

vy_run_iterator_seek() is supposed to check that the resulting statement
matches the search key in case of ITER_EQ, but if the search key lies at
the beginning of the slice, it doesn't. As a result, vy_point_lookup()
may fail to find an existing tuple as demonstrated below.

Suppose we are looking for key {10} in the primary index which consists
of an empty mem and two runs:

    run 1: DELETE{15}
    run 2: INSERT{10}

vy_run_iterator_next() returns DELETE{15} for run 1 because of the
missing EQ check and vy_point_lookup() stops at run 1 (since the
terminal statement is found) and mistakenly returns NULL.

The issue manifests itself as crash in vinyl_iterator_secondary_next(),
when we fail to find the tuple in the primary index corresponding to a
statement found in a secondary index.

Part of #3393
---
 src/box/vy_run.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/src/box/vy_run.c b/src/box/vy_run.c
index 587cb002..8c922895 100644
--- a/src/box/vy_run.c
+++ b/src/box/vy_run.c
@@ -1316,6 +1316,7 @@ vy_run_iterator_seek(struct vy_run_iterator *itr,
 {
 	const struct key_def *cmp_def = itr->cmp_def;
 	struct vy_slice *slice = itr->slice;
+	const struct tuple *check_eq_key = NULL;
 	int cmp;
 
 	if (slice->begin != NULL &&
@@ -1340,6 +1341,8 @@ vy_run_iterator_seek(struct vy_run_iterator *itr,
 			return 0;
 		}
 		if (cmp < 0 || (cmp == 0 && iterator_type != ITER_GT)) {
+			if (iterator_type == ITER_EQ)
+				check_eq_key = key;
 			iterator_type = ITER_GE;
 			key = slice->begin;
 		}
@@ -1365,7 +1368,15 @@ vy_run_iterator_seek(struct vy_run_iterator *itr,
 		}
 	}
 
-	return vy_run_iterator_do_seek(itr, iterator_type, key, ret);
+	if (vy_run_iterator_do_seek(itr, iterator_type, key, ret) != 0)
+		return -1;
+
+	if (check_eq_key != NULL && *ret != NULL &&
+	    vy_stmt_compare(check_eq_key, *ret, cmp_def) != 0) {
+		vy_run_iterator_stop(itr);
+		*ret = NULL;
+	}
+	return 0;
 }
 
 /* }}} vy_run_iterator vy_run_iterator support functions */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 2/4] vinyl: fix lost key on dump completion
  2018-05-15 14:08 [PATCH 0/4] vinyl: fix crash in vinyl_iterator_secondary_next() Vladimir Davydov
  2018-05-15 14:08 ` [PATCH 1/4] vinyl: fix EQ check in run iterator Vladimir Davydov
@ 2018-05-15 14:08 ` Vladimir Davydov
  2018-05-15 19:20   ` Konstantin Osipov
  2018-05-15 14:08 ` [PATCH 3/4] vinyl: do not panic if secondary index is inconsistent with primary Vladimir Davydov
  2018-05-15 14:08 ` [PATCH 4/4] test: improve vinyl/select_consistency Vladimir Davydov
  3 siblings, 1 reply; 9+ messages in thread
From: Vladimir Davydov @ 2018-05-15 14:08 UTC (permalink / raw)
  To: kostja; +Cc: tarantool-patches

vy_task_dump_complete() creates a slice per each range overlapping with
the newly written run. It uses vy_range_tree_psearch(min_key) to find
the first overlapping range and nsearch(max_key) to find the range
immediately following the last overlapping range. This is incorrect as
nsearch rb tree method returns the element matching the search key if it
is present in the tree. That is, if the max key written to a run turns
out to be equal the beginning of a range, the slice won't be created for
it and it will be silently and persistently lost.

The issue manifests itself as crash in vinyl_iterator_secondary_next(),
when we fail to find the tuple in the primary index corresponding to a
statement found in a secondary index.

Part of #3393
---
 src/box/vy_scheduler.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/box/vy_scheduler.c b/src/box/vy_scheduler.c
index 912d9028..b76db587 100644
--- a/src/box/vy_scheduler.c
+++ b/src/box/vy_scheduler.c
@@ -741,7 +741,8 @@ vy_task_dump_complete(struct vy_scheduler *scheduler, struct vy_task *task)
 		goto fail;
 	}
 	begin_range = vy_range_tree_psearch(lsm->tree, min_key);
-	end_range = vy_range_tree_nsearch(lsm->tree, max_key);
+	end_range = vy_range_tree_psearch(lsm->tree, max_key);
+	end_range = vy_range_tree_next(lsm->tree, end_range);
 	tuple_unref(min_key);
 	tuple_unref(max_key);
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 3/4] vinyl: do not panic if secondary index is inconsistent with primary
  2018-05-15 14:08 [PATCH 0/4] vinyl: fix crash in vinyl_iterator_secondary_next() Vladimir Davydov
  2018-05-15 14:08 ` [PATCH 1/4] vinyl: fix EQ check in run iterator Vladimir Davydov
  2018-05-15 14:08 ` [PATCH 2/4] vinyl: fix lost key on dump completion Vladimir Davydov
@ 2018-05-15 14:08 ` Vladimir Davydov
  2018-05-15 14:08 ` [PATCH 4/4] test: improve vinyl/select_consistency Vladimir Davydov
  3 siblings, 0 replies; 9+ messages in thread
From: Vladimir Davydov @ 2018-05-15 14:08 UTC (permalink / raw)
  To: kostja; +Cc: tarantool-patches

Although the bug in vy_task_dump_complete() due to which a tuple could
be lost during dump was fixed, there still may be affected deployments
as the bug was persisted on disk. To avoid occasional crashes on such
deployments, let's make vinyl_iterator_secondary_next() skip tuples that
are present in a secondary index but missing in the primary.

Closes #3393
---
 src/box/vinyl.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index ff4c2831..05aab30b 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -3844,6 +3844,7 @@ vinyl_iterator_secondary_next(struct iterator *base, struct tuple **ret)
 	assert(it->lsm->index_id > 0);
 	struct tuple *tuple;
 
+next:
 	if (it->tx == NULL) {
 		diag_set(ClientError, ER_CURSOR_NO_TRANSACTION);
 		goto fail;
@@ -3853,7 +3854,6 @@ vinyl_iterator_secondary_next(struct iterator *base, struct tuple **ret)
 		goto fail;
 	}
 
-
 	if (vy_read_iterator_next(&it->iterator, &tuple) != 0)
 		goto fail;
 
@@ -3876,11 +3876,26 @@ vinyl_iterator_secondary_next(struct iterator *base, struct tuple **ret)
 	 * Note, there's no need in vy_tx_track() as the
 	 * tuple is already tracked in the secondary index.
 	 */
+	struct tuple *full_tuple;
 	if (vy_point_lookup(it->lsm->pk, it->tx, vy_tx_read_view(it->tx),
-			    tuple, &tuple) != 0)
+			    tuple, &full_tuple) != 0)
 		goto fail;
-	*ret = tuple_bless(tuple);
-	tuple_unref(tuple);
+	if (full_tuple == NULL) {
+		/*
+		 * All indexes of a space must be consistent, i.e.
+		 * if a tuple is present in one index, it must be
+		 * present in all other indexes as well, so we can
+		 * get here only if there's a bug somewhere in vinyl.
+		 * Don't abort as core dump won't really help us in
+		 * this case. Just warn the user and proceed to the
+		 * next tuple.
+		 */
+		say_warn("%s: key %s missing in primary index",
+			 vy_lsm_name(it->lsm), vy_stmt_str(tuple));
+		goto next;
+	}
+	*ret = tuple_bless(full_tuple);
+	tuple_unref(full_tuple);
 	if (*ret != NULL)
 		return 0;
 fail:
-- 
2.11.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 4/4] test: improve vinyl/select_consistency
  2018-05-15 14:08 [PATCH 0/4] vinyl: fix crash in vinyl_iterator_secondary_next() Vladimir Davydov
                   ` (2 preceding siblings ...)
  2018-05-15 14:08 ` [PATCH 3/4] vinyl: do not panic if secondary index is inconsistent with primary Vladimir Davydov
@ 2018-05-15 14:08 ` Vladimir Davydov
  3 siblings, 0 replies; 9+ messages in thread
From: Vladimir Davydov @ 2018-05-15 14:08 UTC (permalink / raw)
  To: kostja; +Cc: tarantool-patches

Improve the test by decreasing range_size so that it creates a lot of
ranges for test indexes, not just one. This helped find bugs causing
the crash described in #3393.

Follow-up #3393
---
 test/vinyl/select_consistency.result   | 11 +++++++----
 test/vinyl/select_consistency.test.lua |  9 +++++----
 2 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/test/vinyl/select_consistency.result b/test/vinyl/select_consistency.result
index 537f0613..c8f19cac 100644
--- a/test/vinyl/select_consistency.result
+++ b/test/vinyl/select_consistency.result
@@ -10,13 +10,13 @@ math.randomseed(os.time())
 s = box.schema.space.create('test', {engine = 'vinyl'})
 ---
 ...
-_ = s:create_index('pk', {parts = {1, 'unsigned'}})
+_ = s:create_index('pk', {parts = {1, 'unsigned'}, page_size = 64, range_size = 256})
 ---
 ...
-_ = s:create_index('i1', {unique = true, parts = {2, 'unsigned', 3, 'unsigned'}})
+_ = s:create_index('i1', {unique = true, parts = {2, 'unsigned', 3, 'unsigned'}, page_size = 64, range_size = 256})
 ---
 ...
-_ = s:create_index('i2', {unique = true, parts = {2, 'unsigned', 4, 'unsigned'}})
+_ = s:create_index('i2', {unique = true, parts = {2, 'unsigned', 4, 'unsigned'}, page_size = 64, range_size = 256})
 ---
 ...
 --
@@ -29,13 +29,16 @@ MAX_KEY = 100
 MAX_VAL = 10
 ---
 ...
+PADDING = string.rep('x', 100)
+---
+...
 test_run:cmd("setopt delimiter ';'")
 ---
 - true
 ...
 function gen_insert()
     pcall(s.insert, s, {math.random(MAX_KEY), math.random(MAX_VAL),
-                        math.random(MAX_VAL), math.random(MAX_VAL), 1})
+                        math.random(MAX_VAL), math.random(MAX_VAL), PADDING})
 end;
 ---
 ...
diff --git a/test/vinyl/select_consistency.test.lua b/test/vinyl/select_consistency.test.lua
index c29cb8ac..90fcf67e 100644
--- a/test/vinyl/select_consistency.test.lua
+++ b/test/vinyl/select_consistency.test.lua
@@ -5,9 +5,9 @@ fiber = require 'fiber'
 math.randomseed(os.time())
 
 s = box.schema.space.create('test', {engine = 'vinyl'})
-_ = s:create_index('pk', {parts = {1, 'unsigned'}})
-_ = s:create_index('i1', {unique = true, parts = {2, 'unsigned', 3, 'unsigned'}})
-_ = s:create_index('i2', {unique = true, parts = {2, 'unsigned', 4, 'unsigned'}})
+_ = s:create_index('pk', {parts = {1, 'unsigned'}, page_size = 64, range_size = 256})
+_ = s:create_index('i1', {unique = true, parts = {2, 'unsigned', 3, 'unsigned'}, page_size = 64, range_size = 256})
+_ = s:create_index('i2', {unique = true, parts = {2, 'unsigned', 4, 'unsigned'}, page_size = 64, range_size = 256})
 
 --
 -- If called from a transaction, i1:select({k}) and i2:select({k})
@@ -16,12 +16,13 @@ _ = s:create_index('i2', {unique = true, parts = {2, 'unsigned', 4, 'unsigned'}}
 
 MAX_KEY = 100
 MAX_VAL = 10
+PADDING = string.rep('x', 100)
 
 test_run:cmd("setopt delimiter ';'")
 
 function gen_insert()
     pcall(s.insert, s, {math.random(MAX_KEY), math.random(MAX_VAL),
-                        math.random(MAX_VAL), math.random(MAX_VAL), 1})
+                        math.random(MAX_VAL), math.random(MAX_VAL), PADDING})
 end;
 
 function gen_delete()
-- 
2.11.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/4] vinyl: fix EQ check in run iterator
  2018-05-15 14:08 ` [PATCH 1/4] vinyl: fix EQ check in run iterator Vladimir Davydov
@ 2018-05-15 19:05   ` Konstantin Osipov
  2018-05-15 19:23     ` Vladimir Davydov
  0 siblings, 1 reply; 9+ messages in thread
From: Konstantin Osipov @ 2018-05-15 19:05 UTC (permalink / raw)
  To: Vladimir Davydov; +Cc: tarantool-patches

* Vladimir Davydov <vdavydov.dev@gmail.com> [18/05/15 17:10]:

I am pushing this as is now, please a couple of comments below.

> vy_run_iterator_seek() is supposed to check that the resulting statement
> matches the search key in case of ITER_EQ, but if the search key lies at
> the beginning of the slice, it doesn't. As a result, vy_point_lookup()
> may fail to find an existing tuple as demonstrated below.
> 
> Suppose we are looking for key {10} in the primary index which consists
> of an empty mem and two runs:
> 
>     run 1: DELETE{15}
>     run 2: INSERT{10}
> 
> vy_run_iterator_next() returns DELETE{15} for run 1 because of the
> missing EQ check and vy_point_lookup() stops at run 1 (since the
> terminal statement is found) and mistakenly returns NULL.
> 
> The issue manifests itself as crash in vinyl_iterator_secondary_next(),
> when we fail to find the tuple in the primary index corresponding to a
> statement found in a secondary index.

I believe this explanation belongs to the code, not only to the
changeset comment.

Ideally, this special case should be covered in a unit test, not
just in the code or in CS comment.

> Part of #3393
> ---
>  src/box/vy_run.c | 13 ++++++++++++-
>  1 file changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/src/box/vy_run.c b/src/box/vy_run.c
> index 587cb002..8c922895 100644
> --- a/src/box/vy_run.c
> +++ b/src/box/vy_run.c
> @@ -1316,6 +1316,7 @@ vy_run_iterator_seek(struct vy_run_iterator *itr,
>  {
>  	const struct key_def *cmp_def = itr->cmp_def;
>  	struct vy_slice *slice = itr->slice;
> +	const struct tuple *check_eq_key = NULL;
>  	int cmp;
>  
>  	if (slice->begin != NULL &&
> @@ -1340,6 +1341,8 @@ vy_run_iterator_seek(struct vy_run_iterator *itr,
>  			return 0;
>  		}
>  		if (cmp < 0 || (cmp == 0 && iterator_type != ITER_GT)) {
> +			if (iterator_type == ITER_EQ)
> +				check_eq_key = key;
>  			iterator_type = ITER_GE;
>  			key = slice->begin;
>  		}
> @@ -1365,7 +1368,15 @@ vy_run_iterator_seek(struct vy_run_iterator *itr,
>  		}
>  	}
>  
> -	return vy_run_iterator_do_seek(itr, iterator_type, key, ret);
> +	if (vy_run_iterator_do_seek(itr, iterator_type, key, ret) != 0)
> +		return -1;
> +
> +	if (check_eq_key != NULL && *ret != NULL &&
> +	    vy_stmt_compare(check_eq_key, *ret, cmp_def) != 0) {
> +		vy_run_iterator_stop(itr);
> +		*ret = NULL;
> +	}

As far as I understand the code flow, this adds an extra check for
cases when key != slice->begin. This is 99.9% of cases. Can we
avoid an extra check if it is not needed?

> +	return 0;
>  }

-- 
Konstantin Osipov, Moscow, Russia, +7 903 626 22 32
http://tarantool.io - www.twitter.com/kostja_osipov

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/4] vinyl: fix lost key on dump completion
  2018-05-15 14:08 ` [PATCH 2/4] vinyl: fix lost key on dump completion Vladimir Davydov
@ 2018-05-15 19:20   ` Konstantin Osipov
  2018-05-15 19:27     ` Vladimir Davydov
  0 siblings, 1 reply; 9+ messages in thread
From: Konstantin Osipov @ 2018-05-15 19:20 UTC (permalink / raw)
  To: Vladimir Davydov; +Cc: tarantool-patches

* Vladimir Davydov <vdavydov.dev@gmail.com> [18/05/15 17:10]:

I rebased the patch to 1.9, added a comment and pushed the patch.

Once again, a separate unit test for this edge case would be
greatly appreciated.

> vy_task_dump_complete() creates a slice per each range overlapping with
> the newly written run. It uses vy_range_tree_psearch(min_key) to find
> the first overlapping range and nsearch(max_key) to find the range
> immediately following the last overlapping range. This is incorrect as
> nsearch rb tree method returns the element matching the search key if it
> is present in the tree. That is, if the max key written to a run turns
> out to be equal the beginning of a range, the slice won't be created for
> it and it will be silently and persistently lost.
> 
> The issue manifests itself as crash in vinyl_iterator_secondary_next(),
> when we fail to find the tuple in the primary index corresponding to a
> statement found in a secondary index.
> 
> Part of #3393
> ---
>  src/box/vy_scheduler.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/src/box/vy_scheduler.c b/src/box/vy_scheduler.c
> index 912d9028..b76db587 100644
> --- a/src/box/vy_scheduler.c
> +++ b/src/box/vy_scheduler.c
> @@ -741,7 +741,8 @@ vy_task_dump_complete(struct vy_scheduler *scheduler, struct vy_task *task)
>  		goto fail;
>  	}
>  	begin_range = vy_range_tree_psearch(lsm->tree, min_key);
> -	end_range = vy_range_tree_nsearch(lsm->tree, max_key);
> +	end_range = vy_range_tree_psearch(lsm->tree, max_key);
> +	end_range = vy_range_tree_next(lsm->tree, end_range);
>  	tuple_unref(min_key);
>  	tuple_unref(max_key);
>  
> -- 
> 2.11.0

-- 
Konstantin Osipov, Moscow, Russia, +7 903 626 22 32
http://tarantool.io - www.twitter.com/kostja_osipov

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/4] vinyl: fix EQ check in run iterator
  2018-05-15 19:05   ` Konstantin Osipov
@ 2018-05-15 19:23     ` Vladimir Davydov
  0 siblings, 0 replies; 9+ messages in thread
From: Vladimir Davydov @ 2018-05-15 19:23 UTC (permalink / raw)
  To: Konstantin Osipov; +Cc: tarantool-patches

On Tue, May 15, 2018 at 10:05:12PM +0300, Konstantin Osipov wrote:
> * Vladimir Davydov <vdavydov.dev@gmail.com> [18/05/15 17:10]:
> 
> I am pushing this as is now, please a couple of comments below.
> 
> > vy_run_iterator_seek() is supposed to check that the resulting statement
> > matches the search key in case of ITER_EQ, but if the search key lies at
> > the beginning of the slice, it doesn't. As a result, vy_point_lookup()
> > may fail to find an existing tuple as demonstrated below.
> > 
> > Suppose we are looking for key {10} in the primary index which consists
> > of an empty mem and two runs:
> > 
> >     run 1: DELETE{15}
> >     run 2: INSERT{10}
> > 
> > vy_run_iterator_next() returns DELETE{15} for run 1 because of the
> > missing EQ check and vy_point_lookup() stops at run 1 (since the
> > terminal statement is found) and mistakenly returns NULL.
> > 
> > The issue manifests itself as crash in vinyl_iterator_secondary_next(),
> > when we fail to find the tuple in the primary index corresponding to a
> > statement found in a secondary index.
> 
> I believe this explanation belongs to the code, not only to the
> changeset comment.

Well, all those ITER_EQ checks are scattered throughout iterator code
and none of them has a comment as they all are pretty self-explaining.
Adding a comment to just one of them looks pointless IMO.

Actually, I was thinking about extracting all the EQ checks out of
source iterators and moving them to vy_read_iterator as this would allow
to reduce the number of EQ comparisons, but I didn't get my hands on it
as there were some problems with the cache iterator. May be, later.

> 
> Ideally, this special case should be covered in a unit test, not
> just in the code or in CS comment.

After the last patch in the series is applied, vinyl/select_consistency
functional test triggers this bug in 100% cases. Anyway, I'll think
about a unit test.

> 
> > Part of #3393
> > ---
> >  src/box/vy_run.c | 13 ++++++++++++-
> >  1 file changed, 12 insertions(+), 1 deletion(-)
> > 
> > diff --git a/src/box/vy_run.c b/src/box/vy_run.c
> > index 587cb002..8c922895 100644
> > --- a/src/box/vy_run.c
> > +++ b/src/box/vy_run.c
> > @@ -1316,6 +1316,7 @@ vy_run_iterator_seek(struct vy_run_iterator *itr,
> >  {
> >  	const struct key_def *cmp_def = itr->cmp_def;
> >  	struct vy_slice *slice = itr->slice;
> > +	const struct tuple *check_eq_key = NULL;
> >  	int cmp;
> >  
> >  	if (slice->begin != NULL &&
> > @@ -1340,6 +1341,8 @@ vy_run_iterator_seek(struct vy_run_iterator *itr,
> >  			return 0;
> >  		}
> >  		if (cmp < 0 || (cmp == 0 && iterator_type != ITER_GT)) {
> > +			if (iterator_type == ITER_EQ)
> > +				check_eq_key = key;
> >  			iterator_type = ITER_GE;
> >  			key = slice->begin;
> >  		}
> > @@ -1365,7 +1368,15 @@ vy_run_iterator_seek(struct vy_run_iterator *itr,
> >  		}
> >  	}
> >  
> > -	return vy_run_iterator_do_seek(itr, iterator_type, key, ret);
> > +	if (vy_run_iterator_do_seek(itr, iterator_type, key, ret) != 0)
> > +		return -1;
> > +
> > +	if (check_eq_key != NULL && *ret != NULL &&
> > +	    vy_stmt_compare(check_eq_key, *ret, cmp_def) != 0) {
> > +		vy_run_iterator_stop(itr);
> > +		*ret = NULL;
> > +	}
> 
> As far as I understand the code flow, this adds an extra check for
> cases when key != slice->begin. This is 99.9% of cases. Can we
> avoid an extra check if it is not needed?

We do this extra tuple comparison only if cmp == 0 and the original
iterator_type is ITER_EQ. The (cmp < 0) case is excluded, because we
stop the iteration in this case for ITER_EQ - see several lines above:

> 		cmp = vy_stmt_compare_with_key(key, slice->begin, cmp_def);
> 		if (cmp < 0 && iterator_type == ITER_EQ) {
> 			vy_run_iterator_stop(itr);
> 			return 0;
> 		}
> 		if (cmp < 0 || (cmp == 0 && iterator_type != ITER_GT)) {
> 			if (iterator_type == ITER_EQ)
> 				check_eq_key = key;

				^^^^^^^^^^^^^^^^^^
cmp can't be < 0 if this assignment takes place

> 			iterator_type = ITER_GE;
> 			key = slice->begin;
> 		}

Looks rather messy, but then again I think we should try to clean up
this mess by extracting ITER_EQ check out of source iterators.

Thanks.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/4] vinyl: fix lost key on dump completion
  2018-05-15 19:20   ` Konstantin Osipov
@ 2018-05-15 19:27     ` Vladimir Davydov
  0 siblings, 0 replies; 9+ messages in thread
From: Vladimir Davydov @ 2018-05-15 19:27 UTC (permalink / raw)
  To: Konstantin Osipov; +Cc: tarantool-patches

On Tue, May 15, 2018 at 10:20:43PM +0300, Konstantin Osipov wrote:
> * Vladimir Davydov <vdavydov.dev@gmail.com> [18/05/15 17:10]:
> 
> I rebased the patch to 1.9, added a comment and pushed the patch.
> 
> Once again, a separate unit test for this edge case would be
> greatly appreciated.

It's rather tricky to write a unit test for this as vy_scheduler depends
on a lot of things. However, this bug is triggered in ~90% cases by
vinyl/select_consistency functional test after the last patch in the
series is applied (and this one is reverted, apparently).

Thanks.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2018-05-15 19:27 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-15 14:08 [PATCH 0/4] vinyl: fix crash in vinyl_iterator_secondary_next() Vladimir Davydov
2018-05-15 14:08 ` [PATCH 1/4] vinyl: fix EQ check in run iterator Vladimir Davydov
2018-05-15 19:05   ` Konstantin Osipov
2018-05-15 19:23     ` Vladimir Davydov
2018-05-15 14:08 ` [PATCH 2/4] vinyl: fix lost key on dump completion Vladimir Davydov
2018-05-15 19:20   ` Konstantin Osipov
2018-05-15 19:27     ` Vladimir Davydov
2018-05-15 14:08 ` [PATCH 3/4] vinyl: do not panic if secondary index is inconsistent with primary Vladimir Davydov
2018-05-15 14:08 ` [PATCH 4/4] test: improve vinyl/select_consistency Vladimir Davydov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox