Skip to content

Commit 428744d

Browse files
ddl: store sharding info hashes on storage
Compute and store sharding key and sharding func hashes on storages. Hashes are updated with on_replace triggers. Part of #212
1 parent c8f0146 commit 428744d

File tree

7 files changed

+540
-26
lines changed

7 files changed

+540
-26
lines changed

crud/common/sharding/sharding_metadata.lua

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ local call = require('crud.common.call')
55
local const = require('crud.common.const')
66
local dev_checks = require('crud.common.dev_checks')
77
local cache = require('crud.common.sharding.sharding_metadata_cache')
8+
local storage_cache = require('crud.common.sharding.storage_metadata_cache')
89
local sharding_func = require('crud.common.sharding.sharding_func')
910
local sharding_key = require('crud.common.sharding.sharding_key')
11+
local sharding_utils = require('crud.common.sharding.utils')
1012

1113
local FetchShardingMetadataError = errors.new_class('FetchShardingMetadataError', {capture_stack = false})
1214

@@ -39,25 +41,6 @@ local function locked(f)
3941
end
4042
end
4143

42-
local function extract_sharding_func_def(tuple)
43-
if not tuple then
44-
return nil
45-
end
46-
47-
local SPACE_SHARDING_FUNC_NAME_FIELDNO = 2
48-
local SPACE_SHARDING_FUNC_BODY_FIELDNO = 3
49-
50-
if tuple[SPACE_SHARDING_FUNC_BODY_FIELDNO] ~= nil then
51-
return {body = tuple[SPACE_SHARDING_FUNC_BODY_FIELDNO]}
52-
end
53-
54-
if tuple[SPACE_SHARDING_FUNC_NAME_FIELDNO] ~= nil then
55-
return tuple[SPACE_SHARDING_FUNC_NAME_FIELDNO]
56-
end
57-
58-
return nil
59-
end
60-
6144
-- Return a map with metadata or nil when spaces box.space._ddl_sharding_key and
6245
-- box.space._ddl_sharding_func are not available on storage.
6346
function sharding_metadata_module.fetch_on_storage()
@@ -68,14 +51,12 @@ function sharding_metadata_module.fetch_on_storage()
6851
return nil
6952
end
7053

71-
local SPACE_NAME_FIELDNO = 1
72-
local SPACE_SHARDING_KEY_FIELDNO = 2
7354
local metadata_map = {}
7455

7556
if sharding_key_space ~= nil then
7657
for _, tuple in sharding_key_space:pairs() do
77-
local space_name = tuple[SPACE_NAME_FIELDNO]
78-
local sharding_key_def = tuple[SPACE_SHARDING_KEY_FIELDNO]
58+
local space_name = tuple[sharding_utils.SPACE_NAME_FIELDNO]
59+
local sharding_key_def = tuple[sharding_utils.SPACE_SHARDING_KEY_FIELDNO]
7960
local space_format = box.space[space_name]:format()
8061
metadata_map[space_name] = {
8162
sharding_key_def = sharding_key_def,
@@ -86,8 +67,8 @@ function sharding_metadata_module.fetch_on_storage()
8667

8768
if sharding_func_space ~= nil then
8869
for _, tuple in sharding_func_space:pairs() do
89-
local space_name = tuple[SPACE_NAME_FIELDNO]
90-
local sharding_func_def = extract_sharding_func_def(tuple)
70+
local space_name = tuple[sharding_utils.SPACE_NAME_FIELDNO]
71+
local sharding_func_def = sharding_utils.extract_sharding_func_def(tuple)
9172
metadata_map[space_name] = metadata_map[space_name] or {}
9273
metadata_map[space_name].sharding_func_def = sharding_func_def
9374
end
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
local stash = require('crud.common.stash')
2+
local utils = require('crud.common.sharding.utils')
3+
4+
local storage_metadata_cache = {}
5+
6+
local FUNC = 1
7+
local KEY = 2
8+
9+
local cache_data = {
10+
[FUNC] = nil,
11+
[KEY] = nil,
12+
}
13+
14+
local ddl_space = {
15+
[FUNC] = '_ddl_sharding_func',
16+
[KEY] = '_ddl_sharding_key',
17+
}
18+
19+
local trigger_stash = stash.get(stash.name.ddl_triggers)
20+
21+
local function update_sharding_func_hash(tuple)
22+
local space_name = tuple[utils.SPACE_NAME_FIELDNO]
23+
local sharding_func_def = utils.extract_sharding_func_def(tuple)
24+
cache_data[FUNC][space_name] = utils.compute_hash(sharding_func_def)
25+
end
26+
27+
local function update_sharding_key_hash(tuple)
28+
local space_name = tuple[utils.SPACE_NAME_FIELDNO]
29+
local sharding_key_def = tuple[utils.SPACE_SHARDING_KEY_FIELDNO]
30+
cache_data[KEY][space_name] = utils.compute_hash(sharding_key_def)
31+
end
32+
33+
local update_hash = {
34+
[FUNC] = update_sharding_func_hash,
35+
[KEY] = update_sharding_key_hash,
36+
}
37+
38+
local function init_cache(section)
39+
cache_data[section] = {}
40+
41+
local space = box.space[ddl_space[section]]
42+
43+
local update_hash_func = update_hash[section]
44+
45+
-- Remove old trigger if there was some code reload.
46+
-- It is possible that ddl space was dropped and created again,
47+
-- so removing non-existing trigger will cause fail;
48+
-- thus we use pcall.
49+
pcall(space.on_replace, space, nil, trigger_stash[section])
50+
51+
trigger_stash[section] = space:on_replace(
52+
function(_, new)
53+
return update_hash_func(new)
54+
end
55+
)
56+
57+
for _, tuple in space:pairs() do
58+
local space_name = tuple[utils.SPACE_NAME_FIELDNO]
59+
-- If the cache record for a space is not nil, it means
60+
-- that it was already set to up-to-date value with trigger.
61+
-- It is more like an overcautiousness since the cycle
62+
-- isn't expected to yield, but let it be here.
63+
if cache_data[section][space_name] == nil then
64+
update_hash_func(tuple)
65+
end
66+
end
67+
end
68+
69+
local function get_sharding_hash(space_name, section)
70+
if box.space[ddl_space[section]] == nil then
71+
return nil
72+
end
73+
74+
-- If one would drop and rebuild ddl spaces fom scratch manually,
75+
-- caching is likely to break.
76+
if cache_data[section] == nil then
77+
init_cache(section)
78+
end
79+
80+
return cache_data[section][space_name]
81+
end
82+
83+
function storage_metadata_cache.get_sharding_func_hash(space_name)
84+
return get_sharding_hash(space_name, FUNC)
85+
end
86+
87+
function storage_metadata_cache.get_sharding_key_hash(space_name)
88+
return get_sharding_hash(space_name, KEY)
89+
end
90+
91+
function storage_metadata_cache.drop_caches()
92+
cache_data = {}
93+
end
94+
95+
return storage_metadata_cache

crud/common/sharding/utils.lua

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
local digest = require('digest')
2+
local msgpack = require('msgpack')
3+
4+
local utils = {}
5+
6+
utils.SPACE_NAME_FIELDNO = 1
7+
utils.SPACE_SHARDING_KEY_FIELDNO = 2
8+
utils.SPACE_SHARDING_FUNC_NAME_FIELDNO = 2
9+
utils.SPACE_SHARDING_FUNC_BODY_FIELDNO = 3
10+
11+
function utils.extract_sharding_func_def(tuple)
12+
if not tuple then
13+
return nil
14+
end
15+
16+
if tuple[utils.SPACE_SHARDING_FUNC_BODY_FIELDNO] ~= nil then
17+
return {body = tuple[utils.SPACE_SHARDING_FUNC_BODY_FIELDNO]}
18+
end
19+
20+
if tuple[utils.SPACE_SHARDING_FUNC_NAME_FIELDNO] ~= nil then
21+
return tuple[utils.SPACE_SHARDING_FUNC_NAME_FIELDNO]
22+
end
23+
24+
return nil
25+
end
26+
27+
function utils.compute_hash(val)
28+
return digest.murmur(msgpack.encode(val))
29+
end
30+
31+
return utils

crud/common/stash.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ stash.name = {
2323
cfg = '__crud_cfg',
2424
stats_internal = '__crud_stats_internal',
2525
stats_local_registry = '__crud_stats_local_registry',
26-
stats_metrics_registry = '__crud_stats_metrics_registry'
26+
stats_metrics_registry = '__crud_stats_metrics_registry',
27+
ddl_triggers = '__crud_ddl_spaces_triggers',
2728
}
2829

2930
--- Setup Tarantool Cartridge reload.

0 commit comments

Comments
 (0)