Skip to content

Commit 4409775

Browse files
ddl: fix fetching invalid configuration
Before this patch, in case there is a sharding key record in _ddl_sharding_key for a non-existing space (for example, if ddl space wasn't properly dropped) and sharding info needs to be updated, any crud request will fail with "attempt to index a nil value" error. This patch fixes the behavior and adds a log warning if ddl configuration is invalid. Closes #308
1 parent df14f8d commit 4409775

File tree

5 files changed

+128
-6
lines changed

5 files changed

+128
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1212
### Changed
1313

1414
### Fixed
15+
* Fetching invalid ddl confuguration (sharding key for non-existing space)
16+
is no longer breaks CRUD requests (#308, PR #309).
1517

1618
## [0.12.0] - 28-06-22
1719

crud/common/sharding/sharding_metadata.lua

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,20 @@ function sharding_metadata_module.fetch_on_storage()
5858
for _, tuple in sharding_key_space:pairs() do
5959
local space_name = tuple[sharding_utils.SPACE_NAME_FIELDNO]
6060
local sharding_key_def = tuple[sharding_utils.SPACE_SHARDING_KEY_FIELDNO]
61-
local space_format = box.space[space_name]:format()
62-
metadata_map[space_name] = {
63-
sharding_key_def = sharding_key_def,
64-
sharding_key_hash = storage_cache.get_sharding_key_hash(space_name),
65-
space_format = space_format,
66-
}
61+
local space = box.space[space_name]
62+
63+
if space ~= nil then
64+
local space_format = space:format()
65+
metadata_map[space_name] = {
66+
sharding_key_def = sharding_key_def,
67+
sharding_key_hash = storage_cache.get_sharding_key_hash(space_name),
68+
space_format = space_format,
69+
}
70+
else
71+
log.warn('Found sharding info for %q, but space not exists. ' ..
72+
'Ensure that you did a proper cleanup after DDL space drop.',
73+
space_name)
74+
end
6775
end
6876
end
6977

deps.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@ rmdir "${TMPDIR}"
2828

2929
tarantoolctl rocks install cartridge 2.7.4
3030
tarantoolctl rocks install ddl 1.6.0
31+
tarantoolctl rocks install migrations 0.4.2
3132

3233
tarantoolctl rocks make

test/entrypoint/srv_migration.lua

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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+
return {
12+
role_name = 'customers-storage',
13+
init = function(opts)
14+
if opts.is_master then
15+
box.schema.space.create('customers')
16+
17+
box.space['customers']:format{
18+
{name = 'id', is_nullable = false, type = 'unsigned'},
19+
{name = 'bucket_id', is_nullable = false, type = 'unsigned'},
20+
{name = 'sharding_key', is_nullable = false, type = 'unsigned'},
21+
}
22+
23+
box.space['customers']:create_index('pk', {parts = { 'id' }})
24+
box.space['customers']:create_index('bucket_id', {parts = { 'bucket_id' }})
25+
end
26+
end,
27+
}
28+
end
29+
30+
local ok, err = errors.pcall('CartridgeCfgError', cartridge.cfg, {
31+
advertise_uri = 'localhost:3301',
32+
http_port = 8081,
33+
bucket_count = 3000,
34+
roles = {
35+
'customers-storage',
36+
'cartridge.roles.crud-router',
37+
'cartridge.roles.crud-storage',
38+
}}
39+
)
40+
41+
if not ok then
42+
log.error('%s', err)
43+
os.exit(1)
44+
end
45+
46+
_G.is_initialized = cartridge.is_healthy
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
local fio = require('fio')
2+
3+
local t = require('luatest')
4+
5+
local helpers = require('test.helper')
6+
7+
local pgroup = t.group('migration', {
8+
{engine = 'memtx'},
9+
{engine = 'vinyl'},
10+
})
11+
12+
pgroup.before_all(function(g)
13+
g.cluster = helpers.Cluster:new({
14+
datadir = fio.tempdir(),
15+
server_command = helpers.entrypoint('srv_migration'),
16+
use_vshard = true,
17+
replicasets = helpers.get_test_replicasets(),
18+
env = {
19+
['ENGINE'] = g.params.engine,
20+
},
21+
})
22+
g.cluster:start()
23+
end)
24+
25+
pgroup.after_all(function(g) helpers.stop_cluster(g.cluster) end)
26+
27+
pgroup.test_gh_308_select_after_improper_ddl_space_drop = function(g)
28+
-- Create a space sharded by key with ddl tools.
29+
helpers.call_on_storages(g.cluster, function(server)
30+
server.net_box:eval([[
31+
local migrator_utils = require('migrator.utils')
32+
33+
if not box.info.ro then
34+
box.schema.space.create('customers_v2')
35+
36+
box.space['customers_v2']:format{
37+
{name = 'id_v2', is_nullable = false, type = 'unsigned'},
38+
{name = 'bucket_id', is_nullable = false, type = 'unsigned'},
39+
{name = 'sharding_key', is_nullable = false, type = 'unsigned'},
40+
}
41+
42+
box.space['customers_v2']:create_index('pk', {parts = { 'id_v2' }})
43+
box.space['customers_v2']:create_index('bucket_id', {parts = { 'bucket_id' }})
44+
45+
migrator_utils.register_sharding_key('customers_v2', {'sharding_key'})
46+
end
47+
]])
48+
end)
49+
50+
-- Do not do any requests to refresh sharding metadata.
51+
52+
-- Drop space, but do not clean up ddl sharding data.
53+
helpers.call_on_storages(g.cluster, function(server)
54+
server.net_box:eval([[
55+
if not box.info.ro then
56+
box.space['customers_v2']:drop()
57+
end
58+
]])
59+
end)
60+
61+
-- Ensure that crud request for existing space is ok.
62+
local _, err = g.cluster.main_server.net_box:call('crud.select',
63+
{'customers', nil, { first = 1 }})
64+
t.assert_equals(err, nil)
65+
end

0 commit comments

Comments
 (0)