Skip to content

Commit 72dd358

Browse files
Preserve stats config and values between reloads
After this patch, statistics module state (enabled/disabled, driver) preserved between package reloads and Tarantool Cartridge role reloads [1]. Since `metrics` package do not fully support preserving registry between role reloads [2] now, this feature doesn't work for `metrics` driver. Corresponding tests are marked with xfail until issue is resolved for metrics. 1. https://www.tarantool.io/en/doc/latest/book/cartridge/cartridge_api/modules/cartridge.roles/#reload 2. tarantool/metrics#334 Follows up #224
1 parent 91db274 commit 72dd358

12 files changed

+292
-47
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,13 @@ registry they are stored as `tnt_crud_map_reduces`,
722722
`tnt_crud_tuples_fetched` and `tnt_crud_tuples_lookup` metrics
723723
with `{ operation = 'select', name = space_name }` labels.
724724

725+
Statistics are preserved between package reloads or [Tarantool Cartridge
726+
role reloads](https://www.tarantool.io/en/doc/latest/book/cartridge/cartridge_api/modules/cartridge.roles/#reload).
727+
Beware that metrics 0.12.0 and below do not support
728+
preverving stats between role reload
729+
(see [tarantool/metrics#334](https://github.com/tarantool/metrics/issues/334)),
730+
thus this feature will be unsupported for `metrics` driver.
731+
725732
## Cartridge roles
726733

727734
`cartridge.roles.crud-storage` is a Tarantool Cartridge role that depends on the

crud/stats/local_registry.lua

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
local dev_checks = require('crud.common.dev_checks')
22
local op_module = require('crud.stats.operation')
33
local registry_common = require('crud.stats.registry_common')
4+
local stash = require('crud.stats.stash')
45

56
local registry = {}
6-
local internal_registry = {}
7+
local internal_registry = stash.get('local_registry')
78

89
--- Initialize local metrics registry
910
--
@@ -31,7 +32,7 @@ end
3132
-- @treturn boolean Returns true.
3233
--
3334
function registry.destroy()
34-
internal_registry = {}
35+
internal_registry = stash.reset('local_registry')
3536

3637
return true
3738
end

crud/stats/metrics_registry.lua

+28-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ local is_package, metrics = pcall(require, 'metrics')
33
local dev_checks = require('crud.common.dev_checks')
44
local op_module = require('crud.stats.operation')
55
local registry_common = require('crud.stats.registry_common')
6+
local stash = require('crud.stats.stash')
67

78
local registry = {}
8-
local internal_registry = {}
9+
-- Used to cache collectors.
10+
local internal_registry = stash.get('metrics_registry')
911

1012
local metric_name = {
1113
-- Summary collector for all operations.
@@ -114,7 +116,7 @@ function registry.destroy()
114116
metrics.registry:unregister(c)
115117
end
116118

117-
internal_registry = {}
119+
internal_registry = stash.reset('metrics_registry')
118120
return true
119121
end
120122

@@ -321,4 +323,28 @@ function registry.observe_map_reduces(count, space_name)
321323
return true
322324
end
323325

326+
-- Workaround for https://github.com/tarantool/metrics/issues/334 .
327+
-- This workaround does not prevent observations reset between role reloads,
328+
-- but it fixes collector unlink from registry. Without this workaround,
329+
-- we will continue to use cached collectors that are already cleaned up
330+
-- from registry and changes will not appear in metrics export output.
331+
local function workaround_role_reload()
332+
if not registry.is_supported() then
333+
return
334+
end
335+
336+
-- Check if this registry was enabled before reload.
337+
if next(internal_registry) == nil then
338+
return
339+
end
340+
341+
-- Check if base collector is in metrics package registry.
342+
-- If it's not, then registry has beed cleaned up on role reload.
343+
if metrics.registry:find('summary', metric_name.stats) == nil then
344+
registry.init()
345+
end
346+
end
347+
348+
workaround_role_reload()
349+
324350
return registry

crud/stats/module.lua

+8-5
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,12 @@ local vshard = require('vshard')
66
local dev_checks = require('crud.common.dev_checks')
77
local utils = require('crud.common.utils')
88
local op_module = require('crud.stats.operation')
9+
local stash = require('crud.stats.stash')
910

1011
local StatsError = errors.new_class('StatsError', {capture_stack = false})
1112

1213
local stats = {}
13-
local internal = {
14-
registry = nil,
15-
driver = nil,
16-
}
17-
stats.internal = internal
14+
local internal = stash.get('internal')
1815

1916
local local_registry = require('crud.stats.local_registry')
2017
local metrics_registry = require('crud.stats.metrics_registry')
@@ -337,4 +334,10 @@ end
337334
--
338335
stats.op = op_module
339336

337+
--- Stats module internal state (for debug/test)
338+
--
339+
-- @table internal
340+
--
341+
stats.internal = internal
342+
340343
return stats

crud/stats/stash.lua

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
local dev_checks = require('crud.common.dev_checks')
2+
3+
local stash = {}
4+
5+
local function get_G_name(name)
6+
return ('__crud_stats_%s'):format(name)
7+
end
8+
9+
--- Get a stash instance, initialize if needed
10+
-- Stashes are persistent to package reload and cartridge roles reload.
11+
--
12+
-- @function get
13+
--
14+
-- @tparam string name
15+
-- Stash identifier.
16+
--
17+
-- @treturn table A stash instance.
18+
--
19+
function stash.get(name)
20+
dev_checks('string')
21+
22+
local _G_name = get_G_name(name)
23+
local instance = rawget(_G, _G_name) or {}
24+
rawset(_G, _G_name, instance)
25+
26+
local hotreload = package.loaded['cartridge.hotreload']
27+
if hotreload ~= nil then
28+
hotreload.whitelist_globals({_G_name})
29+
end
30+
31+
return instance
32+
end
33+
34+
--- Reset stash instance
35+
-- Stashes are persistent to package reload and cartridge roles reload.
36+
--
37+
-- @function get
38+
--
39+
-- @tparam string name
40+
-- Stash identifier.
41+
--
42+
-- @treturn table A stash instance.
43+
--
44+
function stash.reset(name)
45+
dev_checks('string')
46+
47+
local _G_name = get_G_name(name)
48+
local instance = {}
49+
rawset(_G, _G_name, instance)
50+
51+
return instance
52+
end
53+
54+
return stash

deps.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
set -e
55

66
# Test dependencies:
7-
tarantoolctl rocks install luatest 0.5.5
7+
tarantoolctl rocks install luatest 0.5.6
88
tarantoolctl rocks install luacheck 0.25.0
99
tarantoolctl rocks install luacov 0.13.0
1010

test/entrypoint/srv_select.lua

-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ package.preload['customers-storage'] = function()
2424
},
2525
if_not_exists = true,
2626
engine = engine,
27-
id = 542,
2827
})
2928
-- primary index
3029
customers_space:create_index('id_index', {

test/entrypoint/srv_stats.lua

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env tarantool
2+
3+
require('strict').on()
4+
_G.is_initialized = function() return false end
5+
6+
local log = require('log')
7+
local errors = require('errors')
8+
local cartridge = require('cartridge')
9+
10+
package.preload['customers-storage'] = function()
11+
local engine = os.getenv('ENGINE') or 'memtx'
12+
return {
13+
role_name = 'customers-storage',
14+
init = function()
15+
local customers_space = box.schema.space.create('customers', {
16+
format = {
17+
{name = 'id', type = 'unsigned'},
18+
{name = 'bucket_id', type = 'unsigned'},
19+
{name = 'name', type = 'string'},
20+
{name = 'last_name', type = 'string'},
21+
{name = 'age', type = 'number'},
22+
{name = 'city', type = 'string'},
23+
},
24+
if_not_exists = true,
25+
engine = engine,
26+
id = 542,
27+
})
28+
-- primary index
29+
customers_space:create_index('id_index', {
30+
parts = { {field = 'id'} },
31+
if_not_exists = true,
32+
})
33+
customers_space:create_index('bucket_id', {
34+
parts = { {field = 'bucket_id'} },
35+
unique = false,
36+
if_not_exists = true,
37+
})
38+
customers_space:create_index('age_index', {
39+
parts = { {field = 'age'} },
40+
unique = false,
41+
if_not_exists = true,
42+
})
43+
end,
44+
}
45+
end
46+
47+
local ok, err = errors.pcall('CartridgeCfgError', cartridge.cfg, {
48+
advertise_uri = 'localhost:3301',
49+
http_port = 8081,
50+
bucket_count = 3000,
51+
roles = {
52+
'cartridge.roles.crud-router',
53+
'cartridge.roles.crud-storage',
54+
'customers-storage',
55+
},
56+
roles_reload_allowed = true,
57+
})
58+
59+
if not ok then
60+
log.error('%s', err)
61+
os.exit(1)
62+
end
63+
64+
_G.is_initialized = cartridge.is_healthy

test/helper.lua

+8
Original file line numberDiff line numberDiff line change
@@ -411,4 +411,12 @@ function helpers.get_map_reduces_stat(router, space_name)
411411
]], { space_name })
412412
end
413413

414+
function helpers.reload_roles(srv)
415+
local ok, err = srv.net_box:eval([[
416+
return require("cartridge.roles").reload()
417+
]])
418+
419+
t.assert_equals({ok, err}, {true, nil})
420+
end
421+
414422
return helpers

test/integration/reload_test.lua

+2-10
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@ local g = t.group()
88

99
local helpers = require('test.helper')
1010

11-
local function reload(srv)
12-
local ok, err = srv.net_box:eval([[
13-
return require("cartridge.roles").reload()
14-
]])
15-
16-
t.assert_equals({ok, err}, {true, nil})
17-
end
18-
1911
g.before_all(function()
2012
g.cluster = helpers.Cluster:new({
2113
datadir = fio.tempdir(),
@@ -92,7 +84,7 @@ function g.test_router()
9284
t.assert_equals(last_insert[3], 'A', 'No workload for label A')
9385
end)
9486

95-
reload(g.router)
87+
helpers.reload_roles(g.router)
9688

9789
local cnt = #g.insertions_passed
9890
g.cluster:retrying({}, function()
@@ -117,7 +109,7 @@ function g.test_storage()
117109
-- snapshot with a signal
118110
g.s1_master.process:kill('USR1')
119111

120-
reload(g.s1_master)
112+
helpers.reload_roles(g.s1_master)
121113

122114
g.cluster:retrying({}, function()
123115
g.s1_master.net_box:call('box.snapshot')

0 commit comments

Comments
 (0)