-
Notifications
You must be signed in to change notification settings - Fork 403
Labels
Description
Bug description
Since the number type had been implemented, the constraint about equality of MsgPack contents of equal tuples has been discontinued, e. g. equal keys may have value of 0 in both MP_UINT8 and MP_DOUBLE format. The same applies to the double field type.
The problem is that the MVCC engine assumes the tuple keys are only equal if they're bitwice identical. Simple solution is to compare keys using key_compare instead of memcmp.
Steps to reproduce
box.cfg{
memtx_use_mvcc_engine = true
}
s = box.schema.create_space('s')
s:create_index('pk', {type = 'HASH', parts = {1, 'double'}})
fiber = require('fiber')
function unsigned(v)
return v
end
function double(v)
return require('ffi').cast('double', v)
end
function conflicting_fiber(cast_lookup_key, prefix, value)
box.begin()
-- This creates point hole items in different positions in the hash table
-- depending on the cast function.
print(prefix..'Check if {1} exists.')
local key_exists = #s:select({cast_lookup_key(1)}) ~= 0
if not key_exists then
print(prefix..'No, {1} does not exist. Let others go.')
fiber.sleep(0.25) -- Enough for WAL write of insert {1}.
print(prefix..'Insert my unique value to abort on conflict.')
s:insert({value})
end
box.commit()
end
print('[0] Create [1].')
f1 = fiber.new(conflicting_fiber, unsigned, '[1] ', 11)
f1:set_joinable(true)
print('[0] Create [2].')
f2 = fiber.new(conflicting_fiber, double, '[2] ', 22)
f2:set_joinable(true)
print('[0] Let [1] and [2] go.')
fiber.yield()
-- This only finds one point hole (one with double or unsigned key), so it only
-- conflicts one of conflicting fibers (must conflict both though).
print('[0] Inserting {1}...')
s:insert({1})
print('[0] Done, now [1] and [2] must be conflicting. The new space contents:')
print(require('yaml').encode(s:select(nil, {limit = 10})))
ok, result = f1:join() -- [0] must abort on commit.
print('[1]', ok, result)
ok, result = f2:join() -- [1] must abort on commit too, but does not.
print('[2]', ok, result)
os.exit()Actual behavior
Only one of transactions is conflicted:
[0] Create [1].
[0] Create [2].
[0] Let [1] and [2] go.
[1] Check if {1} exists.
[1] No, {1} does not exist. Let others go.
[2] Check if {1} exists.
[2] No, {1} does not exist. Let others go.
[0] Inserting {1}...
[0] Done, now [1] and [2] must be conflicting. The new space contents:
---
- [1]
...
[2] Insert my unique value to abort on conflict.
[1] Insert my unique value to abort on conflict.
[1] false Transaction has been aborted by conflict
[2] true nil
Expected behavior
Both transactions are conflicted.
Reactions are currently unavailable