diff --git a/src/box/index_def.c b/src/box/index_def.c index 756b49fe9c82..be06f7383a85 100644 --- a/src/box/index_def.c +++ b/src/box/index_def.c @@ -52,6 +52,7 @@ const struct index_opts index_opts_default = { /* .lsn = */ 0, /* .func = */ 0, /* .hint = */ INDEX_HINT_DEFAULT, + /* .fast_offset = */ false, }; /** @@ -89,6 +90,7 @@ const struct opt_def index_opts_reg[] = { OPT_DEF("func", OPT_UINT32, struct index_opts, func_id), OPT_DEF_LEGACY("sql"), OPT_DEF_CUSTOM("hint", index_opts_parse_hint), + OPT_DEF("fast_offset", OPT_BOOL, struct index_opts, fast_offset), OPT_END, }; diff --git a/src/box/index_def.h b/src/box/index_def.h index ac436dc91c89..946be6f8a8d6 100644 --- a/src/box/index_def.h +++ b/src/box/index_def.h @@ -108,6 +108,10 @@ struct index_opts { * Use hint optimization for tree index. */ enum index_hint_cfg hint; + /** + * Use logarithmic select with offset. + */ + bool fast_offset; }; extern const struct index_opts index_opts_default; @@ -155,6 +159,8 @@ index_opts_cmp(const struct index_opts *o1, const struct index_opts *o2) return o1->func_id - o2->func_id; if (o1->hint != o2->hint) return o1->hint - o2->hint; + if (o1->fast_offset != o2->fast_offset) + return o1->fast_offset - o2->fast_offset; return 0; } diff --git a/src/box/lua/schema.lua b/src/box/lua/schema.lua index eff8466c9959..1c253eb84314 100644 --- a/src/box/lua/schema.lua +++ b/src/box/lua/schema.lua @@ -1487,6 +1487,7 @@ local index_options = { bloom_fpr = 'number', func = 'number, string', hint = 'boolean', + fast_offset = 'boolean', } local function jsonpaths_from_idx_parts(parts) @@ -1629,6 +1630,7 @@ box.schema.index.create = atomic_wrapper(function(space_id, name, options) bloom_fpr = options.bloom_fpr, func = options.func, hint = options.hint, + fast_offset = options.fast_offset, } local field_type_aliases = { num = 'unsigned'; -- Deprecated since 1.7.2 diff --git a/src/box/lua/space.cc b/src/box/lua/space.cc index 41d8e0ee3d57..498e04e55dda 100644 --- a/src/box/lua/space.cc +++ b/src/box/lua/space.cc @@ -566,6 +566,9 @@ lbox_fillspace(struct lua_State *L, struct space *space, int i) lua_setfield(L, -2, "hint"); } + lua_pushnil(L); + lua_setfield(L, -2, "fast_offset"); + if (index_opts->func_id > 0) { lua_pushstring(L, "func"); lua_newtable(L); diff --git a/src/box/memtx_space.c b/src/box/memtx_space.c index c4cc9a427906..a8bfff113f50 100644 --- a/src/box/memtx_space.c +++ b/src/box/memtx_space.c @@ -761,6 +761,11 @@ memtx_space_check_index_def(struct space *space, struct index_def *index_def) { struct key_def *key_def = index_def->key_def; + if (index_def->opts.fast_offset) { + diag_set(ClientError, ER_UNSUPPORTED, "memtx", + "logarithmic select with offset"); + return -1; + } if (key_def->is_nullable) { if (index_def->iid == 0) { diag_set(ClientError, ER_NULLABLE_PRIMARY, diff --git a/src/box/vinyl.c b/src/box/vinyl.c index 9f12d150dc85..c9fca0466490 100644 --- a/src/box/vinyl.c +++ b/src/box/vinyl.c @@ -678,6 +678,11 @@ vinyl_space_check_index_def(struct space *space, struct index_def *index_def) "hint is only reasonable with memtx tree index"); return -1; } + if (index_def->opts.fast_offset) { + diag_set(ClientError, ER_UNSUPPORTED, "Vinyl", + "logarithmic select with offset"); + return -1; + } struct key_def *key_def = index_def->key_def; diff --git a/test/box-luatest/gh_8204_fast_offset_test.lua b/test/box-luatest/gh_8204_fast_offset_test.lua new file mode 100644 index 000000000000..2d0ced81c53b --- /dev/null +++ b/test/box-luatest/gh_8204_fast_offset_test.lua @@ -0,0 +1,54 @@ +local server = require('luatest.server') +local t = require('luatest') + +local g = t.group() + +g.before_all(function() + g.server = server:new({alias = 'master'}) + g.server:start() +end) + +g.after_all(function() + g.server:drop() +end) + +g.after_each(function() + g.server:exec(function() + if box.space.test then + box.space.test:drop() + end + end) +end) + +g.test_option = function() + g.server:exec(function() + local s = box.schema.space.create('test', {engine = 'memtx'}) + + -- Memtx does not support the fast_offset option. + t.assert_error_msg_content_equals( + "memtx does not support logarithmic select with offset", + s.create_index, s, 'pk', {fast_offset = true}) + + -- Can successfully create all indexes with fast_offset = false. + s:create_index('k0', {type = 'TREE', fast_offset = false}) + s:create_index('k1', {type = 'HASH', fast_offset = false}) + s:create_index('k2', {type = 'RTREE', fast_offset = false, + unique = false, parts = {2, 'array'}}) + s:create_index('k3', {type = 'BITSET', fast_offset = false, + unique = false}) + + s:drop() + + s = box.schema.space.create('test', {engine = 'vinyl'}) + + -- Vinyl does not support the fast_offset option. + t.assert_error_msg_content_equals( + "Vinyl does not support logarithmic select with offset", + s.create_index, s, 'pk', {fast_offset = true}) + + -- Can successfully create vinyl index with fast_offset = false. + s:create_index('pk', {fast_offset = false}) + + s:drop() + end) +end