• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / crud / 20334944897

18 Dec 2025 11:08AM UTC coverage: 88.971% (+0.002%) from 88.969%
20334944897

Pull #469

github

Satbek
perf: drop wrap_box_space_func_result to cut allocations and speed storage calls

- remove the extra wrapper around box.space methods to avoid per-call closures and arg tables
- call wrap_func_result directly so storage paths allocate less and return handling stays centralized
- reduce storage-side overhead on replace/insert/delete/get/update/upsert(+_many) for better call latency
Pull Request #469: perf: drop wrap_box_space_func_result to cut allocations and speed storage calls

35 of 35 new or added lines in 11 files covered. (100.0%)

26 existing lines in 5 files now uncovered.

4945 of 5558 relevant lines covered (88.97%)

6075.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.08
/crud/borders.lua
1
local checks = require('checks')
258✔
2
local errors = require('errors')
258✔
3

4
local const = require('crud.common.const')
258✔
5
local dev_checks = require('crud.common.dev_checks')
258✔
6
local call = require('crud.common.call')
258✔
7
local utils = require('crud.common.utils')
258✔
8
local schema = require('crud.common.schema')
258✔
9
local has_keydef, Keydef = pcall(require, 'crud.compare.keydef')
258✔
10
local select_comparators = require('crud.compare.comparators')
258✔
11

12
local BorderError = errors.new_class('BorderError', {capture_stack = false})
258✔
13

14
local borders = {}
258✔
15

16
local STAT_FUNC_NAME = 'get_border_on_storage'
258✔
17
local CRUD_STAT_FUNC_NAME = utils.get_storage_call(STAT_FUNC_NAME)
258✔
18

19

20
local function get_border_on_storage(border_name, space_name, index_id, field_names, fetch_latest_metadata)
21
    dev_checks('string', 'string', 'number', '?table', '?boolean')
132✔
22

23
    assert(border_name == 'min' or border_name == 'max')
132✔
24

25
    local space = box.space[space_name]
132✔
26
    if space == nil then
132✔
27
        return nil, BorderError:new("Space %q doesn't exist", space_name)
×
28
    end
29

30
    local index = space.index[index_id]
132✔
31
    if index == nil then
132✔
32
        return nil, BorderError:new("Index %q of space doesn't exist", index_id, space_name)
×
33
    end
34

35
    local function get_index_border(_, index)
36
        return index[border_name](index)
132✔
37
    end
38

39
    return schema.wrap_func_result(space, get_index_border, {
132✔
40
        add_space_schema_hash = true,
41
        field_names = field_names,
132✔
42
        fetch_latest_metadata = fetch_latest_metadata,
132✔
43
    }, index)
132✔
44
end
45

46
borders.storage_api = {[STAT_FUNC_NAME] = get_border_on_storage}
258✔
47

48
local is_closer
49

50
if has_keydef then
258✔
51
    is_closer = function (compare_sign, keydef, tuple, res_tuple)
52
        if res_tuple == nil then
54✔
53
            return true
28✔
54
        end
55

56
        local cmp = keydef:compare(tuple, res_tuple)
52✔
57

58
        return cmp * compare_sign > 0
26✔
59
    end
60
else
61
    is_closer = function (_, comparator, tuple, res_tuple)
UNCOV
62
        if res_tuple == nil then
×
UNCOV
63
            return true
×
64
        end
UNCOV
65
        return comparator(tuple, res_tuple)
×
66
    end
67
end
68

69
local function call_get_border_on_router(vshard_router, border_name, space_name, index_name, opts)
70
    checks('table', 'string', 'string', '?string|number', {
156✔
71
        timeout = '?number',
72
        request_timeout = '?number',
73
        fields = '?table',
74
        mode = '?string',
75
        vshard_router = '?string|table',
76
        fetch_latest_metadata = '?boolean',
77
    })
78

79
    local space, err, netbox_schema_version = utils.get_space(space_name, vshard_router, opts.timeout)
156✔
80
    if err ~= nil then
156✔
UNCOV
81
        return nil, BorderError:new("An error occurred during the operation: %s", err), const.NEED_SCHEMA_RELOAD
×
82
    end
83
    if space == nil then
156✔
84
        return nil, BorderError:new("Space %q doesn't exist", space_name), const.NEED_SCHEMA_RELOAD
36✔
85
    end
86

87
    local index
88
    if index_name == nil then
138✔
89
        index = space.index[0]
40✔
90
    else
91
        index = space.index[index_name]
98✔
92
    end
93

94
    if index == nil then
138✔
95
        return nil,
72✔
96
               BorderError:new("Index %q of space %q doesn't exist", index_name, space_name),
72✔
97
               const.NEED_SCHEMA_RELOAD
72✔
98
    end
99

100
    local primary_index = space.index[0]
66✔
101

102
    local cmp_key_parts = utils.merge_primary_key_parts(index.parts, primary_index.parts)
66✔
103
    local field_names = utils.enrich_field_names_with_cmp_key(opts.fields, cmp_key_parts, space:format())
132✔
104

105
    local replicasets, err = vshard_router:routeall()
66✔
106
    if err ~= nil then
66✔
UNCOV
107
        return nil, BorderError:new("Failed to get router replicasets: %s", err)
×
108
    end
109
    local mode = opts.mode or 'read'
66✔
110
    local call_opts = {
66✔
111
        mode = mode,
66✔
112
        replicasets = replicasets,
66✔
113
        timeout = opts.timeout,
66✔
114
        request_timeout = mode == 'read' and opts.request_timeout or nil,
66✔
115
    }
116
    local results, err, storages_info = call.map(vshard_router,
132✔
117
        CRUD_STAT_FUNC_NAME,
66✔
118
        {border_name, space_name, index.id, field_names, opts.fetch_latest_metadata},
66✔
119
        call_opts
120
    )
66✔
121

122
    if err ~= nil then
66✔
UNCOV
123
        return nil, BorderError:new("Failed to get %s: %s", border_name, err)
×
124
    end
125

126
    local compare_sign = border_name == 'max' and 1 or -1
66✔
127
    local comparator
128
    if has_keydef then
66✔
129
        comparator = Keydef.new(space, field_names, index.id)
132✔
130
    else
131
        local tarantool_iter
UNCOV
132
        if compare_sign > 0 then
×
133
            tarantool_iter = box.index.GT
×
134
        else
135
            tarantool_iter = box.index.LT
×
136
        end
UNCOV
137
        local key_parts = utils.merge_primary_key_parts(index.parts, primary_index.parts)
×
UNCOV
138
        local cmp_operator = select_comparators.get_cmp_operator(tarantool_iter)
×
UNCOV
139
        comparator = select_comparators.gen_tuples_comparator(cmp_operator, key_parts, field_names, space:format())
×
140
    end
141

142
    local res_tuple = nil
66✔
143
    for _, storage_result in pairs(results) do
264✔
144
        local storage_result = storage_result[1]
132✔
145
        if storage_result.err ~= nil then
132✔
146
            local err_wrapped = BorderError:new("Failed to get %s: %s", border_name, storage_result.err)
×
147

UNCOV
148
            local need_reload = schema.result_needs_reload(space, storage_result)
×
149
            if need_reload then
×
UNCOV
150
                return nil, err_wrapped, const.NEED_SCHEMA_RELOAD
×
151
            end
152

UNCOV
153
            return nil, err_wrapped
×
154
        end
155

156
        local tuple = storage_result.res
132✔
157
        if tuple ~= nil and is_closer(compare_sign, comparator, tuple, res_tuple) then
186✔
158
            res_tuple = tuple
34✔
159
        end
160
    end
161

162
    if opts.fetch_latest_metadata == true then
66✔
163
        -- This option is temporary and is related to [1], [2].
164
        -- [1] https://github.com/tarantool/crud/issues/236
165
        -- [2] https://github.com/tarantool/crud/issues/361
166
        space = utils.fetch_latest_metadata_when_map_storages(space, space_name, vshard_router, opts,
4✔
167
                                                              storages_info, netbox_schema_version)
4✔
168
    end
169

170
    local result = utils.format_result({res_tuple}, space, field_names)
66✔
171

172
    if opts.fields ~= nil then
66✔
173
        result = utils.cut_rows(result.rows, result.metadata, opts.fields)
20✔
174
    end
175

176
    return result
66✔
177
end
178

179
local function get_border(border_name, space_name, index_name, opts)
180
    opts = opts or {}
118✔
181
    local vshard_router, err = utils.get_vshard_router_instance(opts.vshard_router)
118✔
182
    if err ~= nil then
118✔
183
        return nil, BorderError:new(err)
16✔
184
    end
185

186
    return schema.wrap_func_reload(vshard_router, call_get_border_on_router,
110✔
187
        border_name, space_name, index_name, opts
110✔
188
    )
110✔
189
end
190

191
--- Find the minimum value in the specified index
192
--
193
-- @function min
194
--
195
-- @param string space_name
196
--  A space name
197
--
198
-- @param ?string index_name
199
--  An index name (by default, primary index is used)
200
--
201
-- @tparam ?number opts.timeout
202
--  Function call timeout
203
--
204
-- @tparam ?number opts.request_timeout
205
--  vshard call request_timeout
206
--  default is the same as opts.timeout
207
--
208
-- @tparam ?table opts.fields
209
--  Field names for getting only a subset of fields
210
--
211
-- @tparam ?string|table opts.vshard_router
212
--  Cartridge vshard group name or vshard router instance.
213
--  Set this parameter if your space is not a part of the
214
--  default vshard cluster.
215
--
216
-- @return[1] result
217
-- @treturn[2] nil
218
-- @treturn[2] table Error description
219
function borders.min(space_name, index_id, opts)
258✔
220
    return get_border('min', space_name, index_id, opts)
59✔
221
end
222

223
--- Find the maximum value in the specified index
224
--
225
-- @function min
226
--
227
-- @param string space_name
228
--  A space name
229
--
230
-- @param ?string index_name
231
--  An index name (by default, primary index is used)
232
--
233
-- @tparam ?number opts.timeout
234
--  Function call timeout
235
--
236
-- @tparam ?number opts.request_timeout
237
--  vshard call request_timeout
238
--  default is the same as opts.timeout
239
--
240
-- @tparam ?table opts.fields
241
--  Field names for getting only a subset of fields
242
--
243
-- @tparam ?string|table opts.vshard_router
244
--  Cartridge vshard group name or vshard router instance.
245
--  Set this parameter if your space is not a part of the
246
--  default vshard cluster.
247
--
248
-- @return[1] result
249
-- @treturn[2] nil
250
-- @treturn[2] table Error description
251
function borders.max(space_name, index_id, opts)
258✔
252
    return get_border('max', space_name, index_id, opts)
59✔
253
end
254

255
return borders
258✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc