Skip to content

Scan of hash index returns the same tuple twice #11354

@CuriousGeorgiy

Description

@CuriousGeorgiy

Discovered with MVCC fuzzing (#5999).

Steps to reproduce

os.execute('rm -rf *.snap *.xlog *.vylog 512 513')

local json = require('json')
local log = require('log')
local txn_proxy = require('test.box.lua.txn_proxy')

box.cfg{memtx_use_mvcc_engine = true}

local tx9 = txn_proxy:new()
local tx10 = txn_proxy:new()
local tx11 = txn_proxy:new()
local tx15 = txn_proxy:new()
local tx16 = txn_proxy:new()
local tx19 = txn_proxy:new()
local tx22 = txn_proxy:new()
local tx24 = txn_proxy:new()
local tx25 = txn_proxy:new()
local tx26 = txn_proxy:new()
local tx31 = txn_proxy:new()

box.schema.space.create('m', {engine = 'memtx'})
box.space.m:create_index('p', {parts = {
    {1, 'uint'},
    {2, 'uint'}}})
box.space.m:create_index('s1', {parts = {
    {3, 'uint', exclude_null = true},
    {2, 'uint'}}})
box.space.m:create_index('s2', {parts = {
    {1, 'uint'},
    {4, 'uint', exclude_null = true}}})
box.space.m:create_index('s3', {parts = {
    {3, 'uint', exclude_null = true},
    {4, 'uint', exclude_null = true}}})
box.space.m:create_index('s4', {type = 'HASH', parts = {
    {1, 'uint'},
    {2, 'uint'}}})
box.schema.space.create('v', {engine = 'vinyl'})
box.space.v:create_index('p', {parts = {
    {1, 'uint'},
    {2, 'uint'}}})
box.space.v:create_index('s1', {parts = {
    {3, 'uint', exclude_null = true},
    {2, 'uint'}}})
box.space.v:create_index('s2', {parts = {    {1, 'uint'},
    {4, 'uint', exclude_null = true}}})
box.space.v:create_index('s3', {parts = {    {3, 'uint', exclude_null = true},
    {4, 'uint', exclude_null = true}}})

box.space.m:drop()
box.space.v:drop()

box.schema.space.create('m', {engine = 'memtx'})
box.space.m:create_index('p', {parts = {
    {1, 'uint'},
    {2, 'uint'}}})
box.space.m:create_index('s1', {parts = {
    {3, 'uint', exclude_null = true},
    {2, 'uint'}}})
box.space.m:create_index('s2', {parts = {
    {1, 'uint'},
    {4, 'uint', exclude_null = true}}})
box.space.m:create_index('s3', {parts = {
    {3, 'uint', exclude_null = true},
    {4, 'uint', exclude_null = true}}})
box.space.m:create_index('s4', {type = 'HASH', parts = {
    {1, 'uint'},
    {2, 'uint'}}})
box.schema.space.create('v', {engine = 'vinyl'})
box.space.v:create_index('p', {parts = {
    {1, 'uint'},
    {2, 'uint'}}})
box.space.v:create_index('s1', {parts = {
    {3, 'uint', exclude_null = true},
    {2, 'uint'}}})
box.space.v:create_index('s2', {parts = {    {1, 'uint'},
    {4, 'uint', exclude_null = true}}})
box.space.v:create_index('s3', {parts = {    {3, 'uint', exclude_null = true},
    {4, 'uint', exclude_null = true}}})

tx11('box.begin()') -- null
tx22('box.begin()') -- null
tx10('box.begin()') -- null
tx9('box.begin()') -- null
tx9('box.space.m:upsert({2, 4, 5, 3}, {{"=", 3, 8}, {"=", 4, box.NULL}})') -- null
tx19('box.begin()') -- null
tx19('box.space.m:upsert({6, 1, 2, 5}, {{"=", 3, 4}, {"=", 4, box.NULL}})') -- null
tx26('box.begin()') -- null
tx26('box.space.m:insert{8, 6, 6, 7}') -- [8,6,6,7]
tx31('box.begin()') -- null
tx25('box.begin()') -- null
tx26('box.commit()') -- null
tx24('box.begin()') -- null
tx24('box.space.m:replace{7, 7, 4, 1}') -- [7,7,4,1]
tx15('box.begin()') -- null
tx15('box.space.m:replace{5, 5, box.NULL, 6}') -- [5,5,null,6]
tx10('box.space.m:insert{1, 3, 6, 6}') -- [1,3,6,6]
tx16('box.begin()') -- null
tx22('box.space.m:upsert({3, 8, 4, 7}, {{"=", 3, 1}, {"=", 4, 1}})') -- null
tx16('box.space.m:insert{2, 1, 3, 5}') -- [2,1,3,5]
tx24('box.space.m:upsert({7, 8, 7, 4}, {{"=", 3, 8}, {"=", 4, 6}})') -- null
tx24('box.commit()') -- null
tx15('box.space.m:upsert({6, 8, 1, box.NULL}, {{"=", 3, 1}, {"=", 4, 5}})') -- null
tx25('box.space.m:upsert({8, 5, 6, 4}, {{"=", 3, box.NULL}, {"=", 4, 3}})') -- null
tx31('box.space.m:upsert({6, 7, 3, box.NULL}, {{"=", 3, 5}, {"=", 4, 4}})') -- null
tx31('box.commit()') -- null
tx25('box.commit()') -- null
tx10('box.rollback()') -- null
tx22('box.space.m:upsert({1, 8, 5, 2}, {{"=", 3, 6}, {"=", 4, 1}})') -- null
tx22('box.commit()') -- null
tx15('box.rollback()') -- null
tx19('box.rollback()') -- null
tx16('box.rollback()') -- null
tx9('box.rollback()') -- null
log.info(json.encode(tx11('box.space.m.index[4]:select({}, {fullscan = true})'))) -- [[6,7,3,null],[8,6,6,7],[2,6,1,2],[1,8,5,2],[8,3,7,1],[7,7,4,1],[3,8,4,7],[8,5,6,4],[7,8,7,4],[6,7,3,null]]

os.exit()

Actual behavior

I> [[[1,8,5,2],[8,6,6,7],[7,7,4,1],[3,8,4,7],[6,7,3,null],[7,8,7,4],[6,7,3,null],[8,5,6,4]]]

I.e., tuple [6,7,3,null] is returned twice.

Expected behavior

No tuples are returned twice.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions