forked from tarantool/tarantool
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
memtx: fix lost gap and full scan items
By a mistake in 8a56514 a shortcut was added to procedure that handles gap write: it was considered that if the writing transaction is the same as reading - there is no actual conflict that must be stored further. That was a wrong decision: if such a transaction yields and another transaction comes and commits a value with the same key - the first one must go to conflicted state since it has read no more possible state. Another similar mistake was made in e6f5090, where writing after full scan of the same transaction was not tracked as read. Obviously that was wrong: if some other transaction overwrites the key and commits - this transaction must go to read view since it did not see anything by this key which is not so anymore. Fix it, reverting the first commit and an modifying the second and add a test. Closes tarantool#8326 NO_DOC=bugfix
- Loading branch information
Showing
3 changed files
with
80 additions
and
12 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
## bugfix/core | ||
|
||
* Fixed a bug when MVCC sometimes lost gap record (gh-8326). |
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
local server = require('luatest.server') | ||
local t = require('luatest') | ||
|
||
local g = t.group() | ||
|
||
g.before_all(function() | ||
g.server = server:new{ | ||
alias = 'default', | ||
box_cfg = {memtx_use_mvcc_engine = true} | ||
} | ||
g.server:start() | ||
end) | ||
|
||
g.after_all(function() | ||
g.server:drop() | ||
end) | ||
|
||
g.before_each(function() | ||
g.server:exec(function() | ||
local s = box.schema.space.create('s') | ||
s:create_index('pk', {parts = {{1, 'uint'}, {2, 'uint'}}}) | ||
s:create_index('sk', {type = 'hash', parts = {{2, 'uint'}}}) | ||
end) | ||
end) | ||
|
||
g.after_each(function() | ||
g.server:exec(function() | ||
box.space.s:drop() | ||
end) | ||
end) | ||
|
||
g.test_lost_gap_record = function() | ||
g.server:exec(function() | ||
local txn_proxy = require("test.box.lua.txn_proxy") | ||
|
||
local tx1 = txn_proxy.new() | ||
local tx2 = txn_proxy.new() | ||
tx1:begin() | ||
tx2:begin() | ||
|
||
tx1('box.space.s:select{1}') -- select by partial key {1}, empty result | ||
tx1('box.space.s:replace{1, 1, 1}') -- write right to selected | ||
|
||
tx2('box.space.s:replace{1, 1, 2}') -- overwrite by the second TX | ||
tx2:commit() -- ok, now tx1 must become conflicted because of select{1} | ||
|
||
t.assert_equals(tx1:commit(), | ||
{{error = "Transaction has been aborted by conflict"}}) | ||
t.assert_equals(box.space.s:select{1}, {{1, 1, 2}}) | ||
end) | ||
end | ||
|
||
g.test_lost_full_scan_record = function() | ||
g.server:exec(function() | ||
local txn_proxy = require("test.box.lua.txn_proxy") | ||
|
||
local tx1 = txn_proxy.new() | ||
local tx2 = txn_proxy.new() | ||
tx1:begin() | ||
tx2:begin() | ||
|
||
tx1('box.space.s.index.sk:select{}') -- secondary fullscan, empty result | ||
tx1('box.space.s:replace{1, 1, 1}') -- write to selected | ||
|
||
tx2('box.space.s:replace{1, 1, 2}') -- overwrite by the second TX | ||
tx2:commit() -- ok, now tx1 must become conflicted because of select{1} | ||
|
||
t.assert_equals(tx1:commit(), | ||
{{error = "Transaction has been aborted by conflict"}}) | ||
t.assert_equals(box.space.s:select{1}, {{1, 1, 2}}) | ||
end) | ||
end |