Skip to content

Commit 00ebe5f

Browse files
schema: support cached schema
1 parent 149407b commit 00ebe5f

File tree

4 files changed

+167
-85
lines changed

4 files changed

+167
-85
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,6 +1728,8 @@ where:
17281728
* `vshard_router` (`?string|table`) - Cartridge vshard group name or
17291729
vshard router instance. Set this parameter if your space is not
17301730
a part of the default vshard cluster
1731+
* `cached` (`?boolean`) - if `false`, reloads storages schema on call;
1732+
if `true`, return last known schema; default value is `false`
17311733

17321734
Returns space schema (or spaces schema map), error.
17331735

crud/schema.lua

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ local utils = require('crud.common.utils')
88

99
local schema = {}
1010

11-
local system_spaces = {
11+
schema.system_spaces = {
1212
-- https://github.com/tarantool/tarantool/blob/3240201a2f5bac3bddf8a74015db9b351954e0b5/src/box/schema_def.h#L77-L127
1313
['_vinyl_deferred_delete'] = true,
1414
['_schema'] = true,
@@ -69,6 +69,7 @@ schema.call = function(space_name, opts)
6969
checks('?string', {
7070
vshard_router = '?string|table',
7171
timeout = '?number',
72+
cached = '?boolean',
7273
})
7374

7475
opts = opts or {}
@@ -78,9 +79,11 @@ schema.call = function(space_name, opts)
7879
return nil, SchemaError:new(err)
7980
end
8081

81-
local _, err = schema_module.reload_schema(vshard_router)
82-
if err ~= nil then
83-
return nil, SchemaError:new(err)
82+
if opts.cached ~= true then
83+
local _, err = schema_module.reload_schema(vshard_router)
84+
if err ~= nil then
85+
return nil, SchemaError:new(err)
86+
end
8487
end
8588

8689
local spaces, err = utils.get_spaces(vshard_router, opts.timeout)
@@ -100,7 +103,7 @@ schema.call = function(space_name, opts)
100103
for name, space in pairs(spaces) do
101104
-- Can be indexed by space id and space name,
102105
-- so we need to be careful with duplicates.
103-
if type(name) == 'string' and system_spaces[name] == nil then
106+
if type(name) == 'string' and schema.system_spaces[name] == nil then
104107
resp[name] = get_crud_schema(space)
105108
end
106109
end
Lines changed: 71 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,84 @@
1+
local schema = require('crud.schema')
2+
13
return function()
24
if box.info.ro == true then
35
return
46
end
57

68
local engine = os.getenv('ENGINE') or 'memtx'
79

8-
local customers_space = box.schema.space.create('customers', {
9-
format = {
10-
{name = 'id', type = 'unsigned'},
11-
{name = 'bucket_id', type = 'unsigned'},
12-
{name = 'name', type = 'string'},
13-
{name = 'age', type = 'number'},
14-
},
15-
if_not_exists = true,
16-
engine = engine,
17-
})
18-
customers_space:create_index('id', {
19-
parts = { {field = 'id'} },
20-
if_not_exists = true,
21-
})
22-
customers_space:create_index('bucket_id', {
23-
parts = { {field = 'bucket_id'} },
24-
unique = false,
25-
if_not_exists = true,
26-
})
27-
28-
local shops_space = box.schema.space.create('shops', {
29-
format = {
10+
rawset(_G, 'reload_schema', function()
11+
for name, space in pairs(box.space) do
12+
-- Can be indexed by space id and space name,
13+
-- so we need to be careful with duplicates.
14+
if type(name) == 'string' and schema.system_spaces[name] == nil then
15+
space:drop()
16+
end
17+
end
18+
19+
local customers_space = box.schema.space.create('customers', {
20+
format = {
21+
{name = 'id', type = 'unsigned'},
22+
{name = 'bucket_id', type = 'unsigned'},
23+
{name = 'name', type = 'string'},
24+
{name = 'age', type = 'number'},
25+
},
26+
if_not_exists = true,
27+
engine = engine,
28+
})
29+
customers_space:create_index('id', {
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+
39+
local shops_space = box.schema.space.create('shops', {
40+
format = {
41+
{name = 'registry_id', type = 'unsigned'},
42+
{name = 'bucket_id', type = 'unsigned'},
43+
{name = 'name', type = 'string'},
44+
{name = 'address', type = 'string'},
45+
{name = 'owner', type = 'string', is_nullable = true},
46+
},
47+
if_not_exists = true,
48+
engine = engine,
49+
})
50+
shops_space:create_index('registry', {
51+
parts = { {field = 'registry_id'} },
52+
if_not_exists = true,
53+
})
54+
shops_space:create_index('bucket_id', {
55+
parts = { {field = 'bucket_id'} },
56+
unique = false,
57+
if_not_exists = true,
58+
})
59+
shops_space:create_index('address', {
60+
parts = { {field = 'address'} },
61+
unique = true,
62+
if_not_exists = true,
63+
})
64+
end)
65+
66+
rawset(_G, 'alter_schema', function()
67+
box.space['customers']:create_index('age', {
68+
parts = { {field = 'age'} },
69+
unique = false,
70+
if_not_exists = true,
71+
})
72+
73+
box.space['shops']:format({
3074
{name = 'registry_id', type = 'unsigned'},
3175
{name = 'bucket_id', type = 'unsigned'},
3276
{name = 'name', type = 'string'},
3377
{name = 'address', type = 'string'},
3478
{name = 'owner', type = 'string', is_nullable = true},
35-
},
36-
if_not_exists = true,
37-
engine = engine,
38-
})
39-
shops_space:create_index('registry', {
40-
parts = { {field = 'registry_id'} },
41-
if_not_exists = true,
42-
})
43-
shops_space:create_index('bucket_id', {
44-
parts = { {field = 'bucket_id'} },
45-
unique = false,
46-
if_not_exists = true,
47-
})
48-
shops_space:create_index('address', {
49-
parts = { {field = 'address'} },
50-
unique = true,
51-
if_not_exists = true,
52-
})
79+
{name = 'salary', type = 'unsigned', is_nullable = true},
80+
})
81+
end)
82+
83+
rawget(_G, 'reload_schema')()
5384
end

test/integration/schema_test.lua

Lines changed: 86 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,53 +17,79 @@ pgroup.after_all(function(g)
1717
helpers.stop_cluster(g.cluster, g.params.backend)
1818
end)
1919

20-
local function expected_schema()
21-
local schema = {
22-
customers = {
23-
format = {
24-
{name = "id", type = "unsigned"},
25-
{name = "bucket_id", type = "unsigned", is_nullable = true},
26-
{name = "name", type = "string"},
27-
{name = "age", type = "number"},
28-
},
29-
indexes = {
30-
[0] = {
31-
id = 0,
32-
name = "id",
33-
parts = {{exclude_null = false, fieldno = 1, is_nullable = false, type = "unsigned"}},
34-
type = "TREE",
35-
unique = true,
36-
},
20+
pgroup.after_each(function(g)
21+
helpers.call_on_servers(g.cluster, {'s1-master', 's2-master'}, function(server)
22+
server:call('reload_schema')
23+
end)
24+
25+
local _, err = g.router:call('crud.schema')
26+
assert(err == nil)
27+
end)
28+
29+
local schema = {
30+
customers = {
31+
format = {
32+
{name = "id", type = "unsigned"},
33+
{name = "bucket_id", type = "unsigned", is_nullable = true},
34+
{name = "name", type = "string"},
35+
{name = "age", type = "number"},
36+
},
37+
indexes = {
38+
[0] = {
39+
id = 0,
40+
name = "id",
41+
parts = {{exclude_null = false, fieldno = 1, is_nullable = false, type = "unsigned"}},
42+
type = "TREE",
43+
unique = true,
3744
},
3845
},
39-
shops = {
40-
format = {
41-
{name = 'registry_id', type = 'unsigned'},
42-
{name = 'bucket_id', type = 'unsigned', is_nullable = true},
43-
{name = 'name', type = 'string'},
44-
{name = 'address', type = 'string'},
45-
{name = 'owner', type = 'string', is_nullable = true},
46+
},
47+
shops = {
48+
format = {
49+
{name = 'registry_id', type = 'unsigned'},
50+
{name = 'bucket_id', type = 'unsigned', is_nullable = true},
51+
{name = 'name', type = 'string'},
52+
{name = 'address', type = 'string'},
53+
{name = 'owner', type = 'string', is_nullable = true},
54+
},
55+
indexes = {
56+
[0] = {
57+
id = 0,
58+
name = "registry",
59+
parts = {{exclude_null = false, fieldno = 1, is_nullable = false, type = "unsigned"}},
60+
type = "TREE",
61+
unique = true,
4662
},
47-
indexes = {
48-
[0] = {
49-
id = 0,
50-
name = "registry",
51-
parts = {{exclude_null = false, fieldno = 1, is_nullable = false, type = "unsigned"}},
52-
type = "TREE",
53-
unique = true,
54-
},
55-
[2] = {
56-
id = 2,
57-
name = "address",
58-
parts = {{exclude_null = false, fieldno = 4, is_nullable = false, type = "string"}},
59-
type = "TREE",
60-
unique = true,
61-
},
63+
[2] = {
64+
id = 2,
65+
name = "address",
66+
parts = {{exclude_null = false, fieldno = 4, is_nullable = false, type = "string"}},
67+
type = "TREE",
68+
unique = true,
6269
},
6370
},
71+
},
72+
}
73+
74+
local function expected_schema()
75+
local sch = table.deepcopy(schema)
76+
return helpers.schema_compatibility(sch)
77+
end
78+
79+
local function altered_schema()
80+
local sch = table.deepcopy(schema)
81+
82+
sch['customers'].indexes[2] = {
83+
id = 2,
84+
name = "age",
85+
parts = {{exclude_null = false, fieldno = 4, is_nullable = false, type = "number"}},
86+
type = "TREE",
87+
unique = false,
6488
}
6589

66-
return helpers.schema_compatibility(schema)
90+
sch['shops'].format[6] = {name = 'salary', type = 'unsigned', is_nullable = true}
91+
92+
return helpers.schema_compatibility(sch)
6793
end
6894

6995
pgroup.test_get_all = function(g)
@@ -92,3 +118,23 @@ pgroup.test_timeout_option = function(g)
92118

93119
t.assert_equals(err, nil)
94120
end
121+
122+
pgroup.test_schema_cached = function(g)
123+
helpers.call_on_servers(g.cluster, {'s1-master', 's2-master'}, function(server)
124+
server:call('alter_schema')
125+
end)
126+
127+
local result_after, err = g.router:call('crud.schema', {nil, {cached = true}})
128+
t.assert_equals(err, nil)
129+
t.assert_equals(result_after, expected_schema())
130+
end
131+
132+
pgroup.test_schema_reloaded = function(g)
133+
helpers.call_on_servers(g.cluster, {'s1-master', 's2-master'}, function(server)
134+
server:call('alter_schema')
135+
end)
136+
137+
local result_after, err = g.router:call('crud.schema', {nil, {cached = false}})
138+
t.assert_equals(err, nil)
139+
t.assert_equals(result_after, altered_schema())
140+
end

0 commit comments

Comments
 (0)