Skip to content

Commit 52eea03

Browse files
committed
Use merger module to fetch and sort tuples on router
Before this patch we used hand-crafted heap to sort tuples on router. This patch removes it and changes to "merger" module written in C. "Merger" is available since Tarantool 2.2. Later "tuple-merger" was introduced it's a version that is compatible with some Tarantool 1.10 versions. In fact support several Tarantool versions is quite complex task. Some msgpack helpers is not avaliable in Tarantool 1.10 to solve this problem small compatibility lawer is implemented. Also "tuple-keydef" doesn't support collation_id options and it's not so for built-in "key_def" module. We need to normalize index parts and change "collation_id" to "collation" when create "key_def" instance. Closes #33
1 parent e03a9ad commit 52eea03

File tree

7 files changed

+252
-488
lines changed

7 files changed

+252
-488
lines changed

.github/workflows/test_on_push.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
run: |
2222
curl -L https://tarantool.io/installer.sh | sudo VER=${{ matrix.tarantool-version }} bash
2323
sudo apt install -y tarantool-dev
24+
tarantool --version
2425
./deps.sh
2526
2627
- name: Run linter
@@ -46,6 +47,7 @@ jobs:
4647
rm -f tarantool-enterprise-bundle-${{ matrix.bundle_version }}.tar.gz
4748
sudo cp tarantool-enterprise/tarantool /usr/bin/tarantool
4849
source tarantool-enterprise/env.sh
50+
tarantool --version
4951
./deps.sh
5052
5153
- name: Run linter

CMakeLists.txt

+6
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ install(
2828
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cartridge
2929
DESTINATION ${TARANTOOL_INSTALL_LUADIR}
3030
)
31+
32+
# Don't include to rockspec as some Tarantool versions (e.g. 2.2 and 2.3)
33+
# don't have symbols required by "tuple-merger" and "tuple-keydef" modules.
34+
execute_process(
35+
COMMAND bash "-c" "tarantoolctl rocks install tuple-merger 0.0.1"
36+
)

crud/common/heap.lua

-118
This file was deleted.

crud/select.lua

+63-84
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@ local checks = require('checks')
22
local errors = require('errors')
33
local vshard = require('vshard')
44

5-
local call = require('crud.common.call')
65
local utils = require('crud.common.utils')
76
local sharding = require('crud.common.sharding')
87
local dev_checks = require('crud.common.dev_checks')
98

109
local select_conditions = require('crud.select.conditions')
1110
local select_plan = require('crud.select.plan')
1211
local select_executor = require('crud.select.executor')
13-
local select_comparators = require('crud.select.comparators')
1412
local select_filters = require('crud.select.filters')
1513

1614
local Iterator = require('crud.select.iterator')
@@ -20,10 +18,16 @@ local GetReplicasetsError = errors.new_class('GetReplicasetsError')
2018

2119
local select_module = {}
2220

23-
local SELECT_FUNC_NAME = '_crud.select_on_storage'
24-
2521
local DEFAULT_BATCH_SIZE = 100
2622

23+
local function make_cursor(data)
24+
local last_tuple = data[#data]
25+
26+
return {
27+
after_tuple = last_tuple,
28+
}
29+
end
30+
2731
local function select_on_storage(space_name, index_id, conditions, opts)
2832
dev_checks('string', 'number', '?table', {
2933
scan_value = 'table',
@@ -62,46 +66,20 @@ local function select_on_storage(space_name, index_id, conditions, opts)
6266
return nil, SelectError:new("Failed to execute select: %s", err)
6367
end
6468

65-
return tuples
69+
local cursor
70+
if #tuples < opts.limit or opts.limit == 0 then
71+
cursor = {is_end = true}
72+
else
73+
cursor = make_cursor(tuples)
74+
end
75+
76+
return cursor, tuples
6677
end
6778

6879
function select_module.init()
6980
_G._crud.select_on_storage = select_on_storage
7081
end
7182

72-
local function select_iteration(space_name, plan, opts)
73-
dev_checks('string', '?table', {
74-
after_tuple = '?table',
75-
replicasets = 'table',
76-
timeout = '?number',
77-
limit = 'number',
78-
})
79-
80-
-- call select on storages
81-
local storage_select_opts = {
82-
scan_value = plan.scan_value,
83-
after_tuple = opts.after_tuple,
84-
iter = plan.iter,
85-
limit = opts.limit,
86-
scan_condition_num = plan.scan_condition_num,
87-
}
88-
89-
local storage_select_args = {
90-
space_name, plan.index_id, plan.conditions, storage_select_opts,
91-
}
92-
93-
local results, err = call.ro(SELECT_FUNC_NAME, storage_select_args, {
94-
replicasets = opts.replicasets,
95-
timeout = opts.timeout,
96-
})
97-
98-
if err ~= nil then
99-
return nil, err
100-
end
101-
102-
return results
103-
end
104-
10583
local function get_replicasets_by_sharding_key(bucket_id)
10684
local replicaset, err = vshard.router.route(bucket_id)
10785
if replicaset == nil then
@@ -128,8 +106,6 @@ local function build_select_iterator(space_name, user_conditions, opts)
128106
return nil, SelectError:new("batch_size should be > 0")
129107
end
130108

131-
local batch_size = opts.batch_size or DEFAULT_BATCH_SIZE
132-
133109
-- check conditions
134110
local conditions, err = select_conditions.parse(user_conditions)
135111
if err ~= nil then
@@ -165,33 +141,33 @@ local function build_select_iterator(space_name, user_conditions, opts)
165141
replicasets_to_select = get_replicasets_by_sharding_key(bucket_id)
166142
end
167143

168-
-- generate tuples comparator
169-
local scan_index = space.index[plan.index_id]
170-
local primary_index = space.index[0]
171-
local cmp_key_parts = utils.merge_primary_key_parts(scan_index.parts, primary_index.parts)
172-
local cmp_operator = select_comparators.get_cmp_operator(plan.iter)
173-
local tuples_comparator, err = select_comparators.gen_tuples_comparator(
174-
cmp_operator, cmp_key_parts
175-
)
176-
if err ~= nil then
177-
return nil, SelectError:new("Failed to generate comparator function: %s", err)
144+
-- If opts.batch_size is missed we should specify it to min(first, DEFAULT_BATCH_SIZE)
145+
local batch_size
146+
if opts.batch_size == nil then
147+
if opts.first ~= nil and opts.first < DEFAULT_BATCH_SIZE then
148+
batch_size = opts.first
149+
else
150+
batch_size = DEFAULT_BATCH_SIZE
151+
end
152+
else
153+
batch_size = opts.batch_size
178154
end
179155

180-
local iter = Iterator.new({
181-
space_name = space_name,
182-
space_format = space_format,
183-
iteration_func = select_iteration,
184-
comparator = tuples_comparator,
185-
186-
plan = plan,
187-
188-
batch_size = batch_size,
189-
replicasets = replicasets_to_select,
156+
local select_opts = {
157+
scan_value = plan.scan_value,
158+
after_tuple = plan.after_tuple,
159+
iter = plan.iter,
160+
limit = batch_size,
161+
scan_condition_num = plan.scan_condition_num,
162+
}
190163

191-
timeout = opts.timeout,
192-
})
164+
local iter = Iterator.new(replicasets_to_select,
165+
space_name, plan.index_id, plan.conditions, select_opts)
193166

194-
return iter
167+
return {
168+
iter = iter,
169+
space_format = space_format,
170+
}
195171
end
196172

197173
function select_module.pairs(space_name, user_conditions, opts)
@@ -222,31 +198,32 @@ function select_module.pairs(space_name, user_conditions, opts)
222198
error(string.format("Failed to generate iterator: %s", err))
223199
end
224200

225-
local gen = function(_, iter)
226-
if not iter:has_next() then
201+
local tuple, _
202+
203+
if opts.use_tomap ~= true then
204+
return iter.iter:pairs()
205+
end
206+
207+
local merger_gen = iter.iter:pairs()
208+
local gen = function()
209+
_, tuple = merger_gen.gen(nil, merger_gen.state)
210+
if tuple == nil then
227211
return nil
228212
end
229213

230-
local tuple, err = iter:get()
214+
local result
215+
result, err = utils.unflatten(tuple, iter.space_format)
231216
if err ~= nil then
232-
error(string.format("Failed to get next object: %s", err))
233-
end
234-
235-
local result = tuple
236-
if opts.use_tomap == true then
237-
result, err = utils.unflatten(tuple, iter.space_format)
238-
if err ~= nil then
239-
error(string.format("Failed to unflatten next object: %s", err))
240-
end
217+
error(string.format("Failed to unflatten next object: %s", err))
241218
end
242219

243220
return iter, result
244221
end
245222

246-
return gen, nil, iter
223+
return gen
247224
end
248225

249-
function select_module.call(space_name, user_conditions, opts)
226+
local function select_module_call_xc(space_name, user_conditions, opts)
250227
checks('string', '?table', {
251228
after = '?table',
252229
first = '?number',
@@ -277,17 +254,15 @@ function select_module.call(space_name, user_conditions, opts)
277254

278255
local tuples = {}
279256

280-
while iter:has_next() do
281-
local tuple, err = iter:get()
282-
if err ~= nil then
283-
return nil, SelectError:new("Failed to get next object: %s", err)
284-
end
285-
286-
if tuple == nil then
257+
local count = 0
258+
local first = opts.first and math.abs(opts.first)
259+
for _, tuple in iter.iter:pairs() do
260+
if first ~= nil and count >= first then
287261
break
288262
end
289263

290264
table.insert(tuples, tuple)
265+
count = count + 1
291266
end
292267

293268
if opts.first ~= nil and opts.first < 0 then
@@ -300,4 +275,8 @@ function select_module.call(space_name, user_conditions, opts)
300275
}
301276
end
302277

278+
function select_module.call(space_name, user_conditions, opts)
279+
return SelectError:pcall(select_module_call_xc, space_name, user_conditions, opts)
280+
end
281+
303282
return select_module

0 commit comments

Comments
 (0)