Skip to content

Vinyl read view iterator may skip tuple deleted later #11079

@locker

Description

@locker

Bug description

index:pairs() that was sent to a read view may skip a tuple that was deleted after the read view was created.

Tarantool version:

Tarantool 3.4.0-entrypoint-89-g93cbadc15955
Target: Linux-x86_64-Debug
Build options: cmake . -DCMAKE_INSTALL_PREFIX=/home/vlad/src/tarantool/tarantool/build/debug/install -DENABLE_BACKTRACE=TRUE
Compiler: GNU-13.2.0
C_FLAGS: -fexceptions -funwind-tables -fasynchronous-unwind-tables -fno-common -msse2 -Wformat -Wformat-security -Werror=format-security -fstack-protector-strong -fPIC -fmacro-prefix-map=/home/vlad/src/tarantool/tarantool=. -std=c11 -Wall -Wextra -Wno-gnu-alignof-expression -fno-gnu89-inline -Wno-cast-function-type -Werror -g -ggdb -O0
CXX_FLAGS: -fexceptions -funwind-tables -fasynchronous-unwind-tables -fno-common -msse2 -Wformat -Wformat-security -Werror=format-security -fstack-protector-strong -fPIC -fmacro-prefix-map=/home/vlad/src/tarantool/tarantool=. -std=c++11 -Wall -Wextra -Wno-invalid-offsetof -Wno-gnu-alignof-expression -Wno-cast-function-type -Werror -g -ggdb -O0

Steps to reproduce

Run the following script:

local fiber = require('fiber')

local function printf(...)
    print(string.format(...))
end

local function async(func)
    local f = fiber.new(func)
    f:set_joinable(true)
    f:join()
end

os.execute('rm -rf [0-9]*')
box.cfg{
    log_level = 'warn',
}

local s = box.schema.space.create('test', {engine = 'vinyl'})
s:create_index('pk')

s:insert{10}
s:insert{20}
s:insert{30}
s:insert{40}
s:insert{50}

box.begin()

-- Create an iterator.
local gen, param, state = s:pairs()
local function iterate()
    local tuple
    state, tuple = gen(param, state)
    printf('read %s', tuple)
end

-- Reads {10}.
iterate()

-- Sends the iterator to a read view because it updates {10}.
-- {30} must be visible from the read view.
async(function()
    box.begin()
    s:replace({10, 'x'})
    s:delete({30})
    box.commit()
    s:select()
end)

-- Should read {20}, {30}, {40}, {50}.
iterate()
iterate()
iterate()
iterate()

box.commit()

os.exit(0)

Actual behavior

The script prints:

read [10]
read [20]
read [40]
read [50]
read nil

Expected behavior

The script is expected to print:

read [10]
read [20]
read [30]
read [40]
read [50]

Notes

  • The test is responsible in vinyl-luatest/select_consistency_test.lua failures with a "consistency check failed" error. (The issue was found while tuning vinyl-luatest/select_consistency_test in the scope of vinyl-luatest/select_consistency_test.lua:200: Assertion failed: 4 >= 5 #11046.)
  • The memtx engine isn't affected, i.e. after applying the following patch, the script starts working as expected:
    --- test.lua	2025-02-03 16:54:06.948178078 +0300
    +++ test-memtx.lua	2025-02-03 16:54:46.624927285 +0300
    @@ -13,9 +13,10 @@
     os.execute('rm -rf [0-9]*')
     box.cfg{
         log_level = 'warn',
    +    memtx_use_mvcc_engine = true,
     }
     
    -local s = box.schema.space.create('test', {engine = 'vinyl'})
    +local s = box.schema.space.create('test', {engine = 'memtx'})
     s:create_index('pk')
     
     s:insert{10}
  • Disabling the Vinyl cache eliminates the issue:
    --- test.lua	2025-02-03 16:54:06.948178078 +0300
    +++ test-no-cache.lua	2025-02-03 16:56:26.024803329 +0300
    @@ -13,6 +13,7 @@
     os.execute('rm -rf [0-9]*')
     box.cfg{
         log_level = 'warn',
    +    vinyl_cache = 0,
     }
     
     local s = box.schema.space.create('test', {engine = 'vinyl'})

Metadata

Metadata

Assignees

Labels

2.11Target is 2.11 and all newer release/master branches3.2Target is 3.2 and all newer release/master branches3.3Target is 3.3 and all newer release/master branchesbugSomething isn't workingvinyl

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions