vinyl: fix handling of duplicate multikey entries in transaction write set#10871
Merged
sergos merged 1 commit intotarantool:masterfrom Dec 3, 2024
Merged
Conversation
…e set
A multikey index stores a tuple once per each entry of the indexed
array field, excluding duplicates. For example, if the array field
equals {1, 3, 2, 3}, the tuple will be stored three times. Currently,
when a tuple with duplicate multikey entries is inserted into a
transaction write set, duplicates are overwritten as if they belonged
to different statements. Actually, this is pointless: we could just as
well skip them without trying to add to the write set. Besides, this
may break the assumptions taken by various optimizations, resulting in
anomalies. Consider the following example:
```lua
local s = box.schema.space.create('test', {engine = 'vinyl'})
s:create_index('primary')
s:create_index('secondary', {parts = {{'[2][*]', 'unsigned'}}})
s:replace({1, {10, 10}})
s:update({1}, {{'=', 2, {10}}})
```
It will insert the following entries to the transaction write set
of the secondary index:
1. REPLACE {10, 1} [overwritten by no.2]
2. REPLACE {10, 1} [overwritten by no.3]
3. DELETE {10, 1} [turned into no-op as REPLACE + DELETE]
4. DELETE {10, 1} [overwritten by no.5]
5. REPLACE {10, 1} [turned into no-op as DELETE + REPLACE]
(1-2 correspond to `replace()` and 3-5 to `delete()`)
As a result, tuple {1, {10}} will be lost forever.
Let's fix this issue by silently skipping duplicate multikey entries
added to a transaction write set. After the fix, the example above
will produce the following write set entries:
1. REPLACE{10, 1} [overwritten by no.2]
2. DELETE{10, 1} [turned into no-op as REPLACE + DELETE]
3. REPLACE{10, 1} [committed]
(1 corresponds to `replace()` and 2-3 to `delete()`)
Closes tarantool#10869
Closes tarantool#10870
NO_DOC=bug fix
p7nov
approved these changes
Dec 3, 2024
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A multikey index stores a tuple once per each entry of the indexed array field, excluding duplicates. For example, if the array field equals {1, 3, 2, 3}, the tuple will be stored three times. Currently, when a tuple with duplicate multikey entries is inserted into a transaction write set, duplicates are overwritten as if they belonged to different statements. Actually, this is pointless: we could just as well skip them without trying to add to the write set. Besides, this may break the assumptions taken by various optimizations, resulting in anomalies. Consider the following example:
It will insert the following entries to the transaction write set of the secondary index:
(1-2 correspond to
replace()and 3-5 todelete())As a result, tuple {1, {10}} will be lost forever.
Let's fix this issue by silently skipping duplicate multikey entries added to a transaction write set. After the fix, the example above will produce the following write set entries:
(1 corresponds to
replace()and 2-3 todelete())Closes #10869
Closes #10870