commit - e9691d42306dbf9985d9c610d01c0dc77ff4b896
commit + f8c9d693042c21202dc696f6751805a6b18d3765
blob - bc2e97d1ddce661b5a16d4a8f82faf9bd38643c6
blob + 08022d0bbd5c43ac54059f229368f51e94d173ba
--- tarantool-tools/vinyl.lua
+++ tarantool-tools/vinyl.lua
См. https://github.com/tarantool/tarantool/issues/5076
https://github.com/mkostoevr/tarantool/commit/f3462f6bfb80f93ce2c155bb6444d12e478dd180
https://github.com/tarantool/tarantool/issues/4349
+
+Различие между движками memtx и vinyl,
+https://www.tarantool.io/ru/doc/latest/concepts/engines/memtx_vinyl_diff/
+
+Usage: taskset 0xef ./tarantool vinyl.lua
]]
-local TEST_DURATION = 10*60 -- Seconds.
-local NUM_SP = 5
+local TEST_DURATION = 30*60 -- Seconds.
+local NUM_SP = 70
local NUM_TUPLES = 1000
local SEED = 10000
-local N_OPS_IN_TX = 10
+local N_OPS_IN_TX = 5
local MAX_KEY = 10000
--
local fiber = require('fiber')
local log = require('log')
local math = require('math')
+local json = require('json')
local seed = SEED or os.time()
seed = seed or math.randomseed(seed)
}
-- Forward declaration.
-local function generate_dml() end
-local function generate_ddl() end
+local generate_dml
+local generate_ddl
+local index_create_op
local tx_op = {
['TX_COMMIT'] = function() box.rollback() end,
}
local function generate_tx(space)
- log.info("GENERATE_TX")
+ log.info("TX")
if box.is_in_txn() then
local tx_op_name = random_elem(dict_keys(tx_op))
- local fn = tx_op[tx_op_name]
- assert(type(fn) == 'function')
- pcall(fn)
- else
- box.begin()
- for _ = 1, N_OPS_IN_TX do
- generate_dml(space)
- generate_ddl(space)
- end
- box.commit()
+ local fn = tx_op[tx_op_name]
+ assert(type(fn) == 'function')
+ local ok, err = pcall(fn)
+ if not ok then log.info('ERROR: ' .. err) end
end
+ box.begin()
+ for _ = 1, N_OPS_IN_TX do
+ generate_dml(space)
+ end
+ box.commit()
+ box.begin()
+ for _ = 1, N_OPS_IN_TX do
+ generate_ddl(space)
+ end
+ box.commit()
end
-- Iterator types for TREE indexes.
'REQ',
}
-local function generate_read(space)
- box.snapshot()
-
- space:get(1)
+local function select_op(space)
local select_opts = {
iterator = random_elem(iter_type),
-- The maximum number of tuples.
- limit = math.random(5000),
+ limit = math.random(100, 500),
-- The number of tuples to skip.
offset = math.random(100),
-- A tuple or the position of a tuple (tuple_pos) after
-- the last selected tuple as the second value.
fetch_pos = random_elem({true, false}),
}
- log.info(select_opts)
- space:select(math.random(MAX_KEY), select_opts)
+ -- log.info(select_opts)
+ local key = math.random(MAX_KEY)
+ space:select(key, select_opts)
end
-local function generate_delete(space)
+local function delete_op(space)
local key = math.random(MAX_KEY)
space:delete(key)
end
-local function generate_insert(space)
+local function insert_op(space)
local key = math.random(MAX_KEY)
if space:get(key) ~= nil then
return
end
pcall(space.insert, space, {
key,
- math.random(MAX_KEY),
math.random(MAX_KEY),
math.random(MAX_KEY),
- })
+ math.random(MAX_KEY),
+ })
end
local tuple_op = {
-- ':', for string splice.
}
-local function generate_upsert(space)
- local tuple = { math.random(1000), math.random(1000) }
+local function upsert_op(space)
+ local tuple = { math.random(MAX_KEY), math.random(MAX_KEY) }
space:upsert(tuple, {
{ random_elem(tuple_op), math.random(2), math.random(1000) },
{ random_elem(tuple_op), math.random(2), math.random(1000) }
})
end
-local function generate_update(space)
+local function update_op(space)
local count = space:count()
- space:update(math.random(count), {
+ local key = math.random(count)
+ space:update(key, {
{ random_elem(tuple_op), math.random(2), math.random(1000) },
{ random_elem(tuple_op), math.random(2), math.random(1000) },
})
end
-local function generate_replace(space)
- local k = math.random(0, 1000)
- space:replace({k, math.random(100)})
+local function replace_op(space)
+ local key = math.random(MAX_KEY)
+ space:replace({key, math.random(MAX_KEY)})
end
+local function bsize_op(space)
+ space:bsize()
+end
+
+local function len_op(space)
+ space:len()
+end
+
+local function truncate_op(space)
+ space:truncate()
+end
+
+--[[
+local DEFAULT_FORMAT = {
+ {name = '1', type = 'any'},
+ {name = '2', type = 'unsigned'},
+ {name = '3', type = 'string'},
+ {name = '4', type = 'number'},
+ {name = '5', type = 'double'},
+ {name = '6', type = 'integer'},
+ {name = '7', type = 'boolean'},
+ {name = '8', type = 'decimal'},
+ {name = '9', type = 'uuid'},
+ {name = 'a', type = 'scalar'},
+ {name = 'b', type = 'array'},
+ {name = 'c', type = 'map'}
+}
+]]
+
+local function format_op(space)
+ -- https://www.tarantool.io/ru/doc/latest/reference/reference_lua/box_space/format/
+ -- space:format(DEFAULT_FORMAT)
+end
+
local function init_space(space)
log.info('CREATING TUPLES')
for _ = 1, NUM_TUPLES do
box.begin()
for _ = 1, N_OPS_IN_TX do
- generate_insert(space)
+ insert_op(space)
end
box.commit()
end
local dump_watermark = 70000
while box.stat.vinyl().memory.level0 < dump_watermark do
- generate_insert(space)
+ insert_op(space)
end
end
}
log.info('FINISH BOX.CFG')
- log.info('create a space')
+ log.info('CREATE A SPACE')
local space = box.schema.space.create('test', { engine = 'vinyl' })
- -- TODO: replace with function create_index.
- space:create_index('pk', { type = 'tree', parts = {{1, 'uint'}},
- run_count_per_level = 100,
- page_size = 128,
- range_size = 1024 })
- -- TODO: replace with function create_index.
- space:create_index('secondary', { unique = false, parts = { 2, 'unsigned' }})
+ index_create_op(space)
+ index_create_op(space)
+
init_space(space)
log.info('FINISH SETUP')
return space
end
local dml_ops = {
- ['DELETE_OP'] = generate_delete,
- ['INSERT_OP'] = generate_insert,
- ['READ_OP'] = generate_read,
- ['REPLACE_OP'] = generate_replace,
- ['UPDATE_OP'] = generate_update,
- ['UPSERT_OP'] = generate_upsert,
+ DELETE_OP = delete_op,
+ INSERT_OP = insert_op,
+ SELECT_OP = select_op,
+ REPLACE_OP = replace_op,
+ UPDATE_OP = update_op,
+ UPSERT_OP = upsert_op,
+ BSIZE_OP = bsize_op,
+ LEN_OP = len_op,
+ TRUNCATE_OP = truncate_op,
+ FORMAT_OP = format_op,
}
generate_dml = function(space)
local op_name = random_elem(dict_keys(dml_ops))
- log.info(("GENERATE DML: %s"):format(op_name))
- local fn = dml_ops[op_name]
- assert(type(fn) == 'function')
- local ok, err = pcall(fn, space)
- if ok ~= true then
+ log.info(op_name)
+ local fn = dml_ops[op_name]
+ assert(type(fn) == 'function')
+ local ok, err = pcall(fn, space)
+ if ok ~= true then
log.info('ERROR: ' .. err)
- end
+ end
end
-- https://www.tarantool.io/en/doc/latest/concepts/data_model/indexes/
local function index_opts(space)
assert(space ~= nil)
+ -- TODO: generate random 'parts' by specified space format.
local opts = {
unique = random_elem({true, false}),
if_not_exists = false,
return opts
end
-local function index_create(space)
+function index_create_op(space)
local idx_name = 'idx_' .. math.random(100)
if space.index[idx_name] ~= nil then
space.index[idx_name]:drop()
end
local opts = index_opts(space)
+ -- FIXME
+ opts.type = 'TREE'
local ok, err = pcall(space.create_index, space, idx_name, opts)
if ok ~= true then
- log.info('ERROR: ' .. err)
- log.info(opts)
+ local msg = ('ERROR: %s (%s)'):format(err, json.encode(opts))
+ log.info(msg)
end
end
-local function index_drop(space)
- if space.index.i ~= nil then
- space.index.i:drop()
- end
+local function index_drop_op(space)
+ if not space.enabled then return end
+ local idx = random_elem(space.index)
+ if idx ~= nil then idx:drop() end
end
-local function index_alter(space)
+local function index_alter_op(space)
+ if not space.enabled then return end
local idx = random_elem(space.index)
local opts = index_opts(space)
-- Option is not relevant.
opts.if_not_exists = nil
- idx:alter(opts)
- -- TODO: space.index.sk:alter{parts = {2, 'number'}}
+ if idx ~= nil then idx:alter(opts) end
end
-local function index_compact(space)
- if space.index.pk ~= nil then
- space.index.pk:compact()
- end
- if space.index.sk ~= nil then
- space.index.sk:compact()
- end
+local function index_compact_op(space)
+ if not space.enabled then return end
+ local idx = random_elem(space.index)
+ if idx ~= nil then idx:compact() end
end
-local function index_noop()
- -- Nope.
+local function index_max_op(space)
+ if not space.enabled then return end
+ local idx = random_elem(space.index)
+ if idx ~= nil then idx:max() end
end
+local function index_min_op(space)
+ if not space.enabled then return end
+ local idx = random_elem(space.index)
+ if idx ~= nil then idx:min() end
+end
+
+local function index_random_op(space)
+ if not space.enabled then return end
+ local idx = random_elem(space.index)
+ if idx ~= nil and idx.type ~= 'TREE' then idx:random() end
+end
+
+local function index_rename_op(space)
+ if not space.enabled then return end
+ local idx = random_elem(space.index)
+ -- FIXME: Use random string instead.
+ if idx ~= nil then idx:rename('XXX') end
+end
+
+local function index_stat_op(space)
+ if not space.enabled then return end
+ local idx = random_elem(space.index)
+ if idx ~= nil then idx:stat() end
+end
+
+local function index_get_op(space)
+ if not space.enabled then return end
+ -- TODO
+end
+
+local function index_select_op(space)
+ if not space.enabled then return end
+ -- TODO
+end
+
+local function index_count_op(space)
+ if not space.enabled then return end
+ -- TODO
+end
+
+local function index_update_op(space)
+ if not space.enabled then return end
+ -- TODO
+end
+
+local function index_delete_op(space)
+ if not space.enabled then return end
+ -- TODO
+end
+
local ddl_ops = {
- INDEX_ALTER = index_alter,
- INDEX_COMPACT = index_compact,
- INDEX_CREATE = index_create,
- INDEX_DROP = index_drop,
- INDEX_NO_OP = index_noop,
+ INDEX_ALTER_OP = index_alter_op,
+ INDEX_COMPACT_OP = index_compact_op,
+ INDEX_CREATE_OP = index_create_op,
+ INDEX_DROP_OP = index_drop_op,
+ INDEX_GET_OP = index_get_op,
+ INDEX_SELECT_OP = index_select_op,
+ INDEX_MIN_OP = index_min_op,
+ INDEX_MAX_OP = index_max_op,
+ INDEX_RANDOM_OP = index_random_op,
+ INDEX_COUNT_OP = index_count_op,
+ INDEX_UPDATE_OP = index_update_op,
+ INDEX_DELETE_OP = index_delete_op,
+ INDEX_RENAME_OP = index_rename_op,
+ INDEX_STAT_OP = index_stat_op,
}
generate_ddl = function(space)
local op_name = random_elem(dict_keys(ddl_ops))
- log.info(("GENERATE DDL: %s"):format(op_name))
- local fn = ddl_ops[op_name]
- assert(type(fn) == 'function')
- local ok, err = pcall(fn, space)
- if ok ~= true then
+ log.info(op_name)
+ local fn = ddl_ops[op_name]
+ assert(type(fn) == 'function')
+ local ok, err = pcall(fn, space)
+ if ok ~= true then
log.info('ERROR: ' .. err)
- end
+ end
end
local function set_err_injection()
local errinj_name = random_elem(dict_keys(errinj_set))
- local t = errinj_set[errinj_name]
+ local t = errinj_set[errinj_name]
local errinj_val_enable = true
local errinj_val_disable = false
local ok, err
ok, err = pcall(box.error.injection.set, errinj_name, errinj_val_enable)
if ok ~= true then
- log.info(err)
+ log.info('ERROR: ' .. err)
end
fiber.sleep(pause_time)
log.info(string.format("DISABLE RANDOM ERROR INJECTION: %s -> %s",
errinj_name, tostring(errinj_val_disable)))
ok, err = pcall(box.error.injection.set, errinj_name, errinj_val_disable)
if ok ~= true then
- log.info('ERR: ' .. err)
+ log.info('ERROR: ' .. err)
end
end
cleanup()
local space = setup()
+ fiber.sleep(1)
local f
for i = 1, NUM_SP do
local start = os.clock()
while os.clock() - start < TEST_DURATION do
generate_dml(space)
- fiber.sleep(0.1)
+ fiber.sleep(0.01)
end
end)
f:set_joinable(true)
if ok ~= true then
log.info('TX: ' .. err)
end
- fiber.sleep(0.1)
+ fiber.sleep(0.01)
end
end)
f:set_joinable(true)
local start = os.clock()
while os.clock() - start < TEST_DURATION do
generate_ddl(space)
- fiber.sleep(0.1)
+ fiber.sleep(math.random(15, 30))
end
end)
f:set_joinable(true)
f = fiber.new(function()
local start = os.clock()
while os.clock() - start < TEST_DURATION do
- local ok, err = pcall(box.snapshot)
- if ok ~= true then
- log.info('BOX SNAPSHOT: ' .. err)
+ local in_progress = box.info.gc().checkpoint_is_in_progress
+ if not in_progress then
+ box.snapshot()
end
fiber.sleep(math.random(30, 60))
end
end)
f:set_joinable(true)
- f:name('snapshots')
+ f:name('SNAPSHOTS')
table.insert(fibers, f)
f = fiber.new(function()
local start = os.clock()
while os.clock() - start < TEST_DURATION do
set_err_injection()
- fiber.sleep(math.random(30, 60))
+ fiber.sleep(math.random(10, 30))
end
end)
f:set_joinable(true)
f:name('ERRINJ')
table.insert(fibers, f)
- f = fiber.new(function()
- local start = os.clock()
- while os.clock() - start < TEST_DURATION do
- print_stat(space)
- fiber.sleep(60)
- end
- end)
- f:set_joinable(true)
- f:name('STATS')
- table.insert(fibers, f)
-
for _, fb in ipairs(fibers) do
local ok, errmsg = fiber.join(fb)
- assert(ok == true)
- assert(errmsg == nil)
+ if not ok then
+ log.info('ERROR: ' .. errmsg)
+ end
end
teardown(space)