Skip to content

Commit 6684358

Browse files
committed
fix key_def cache invalidation
When "fields" feature was introduced we change caching strategy and started to keep "string" key for index + fields. This approach led to the cases when nobody could invalidate key_def cache and if user changes index schema and changes e.g. fields order in his/her index it won't reflect sort order. Old value stuck in cache. This patch fixes such behaviour. We don't consider fields in key_def cache - yes we should recreate key_def each time. But at least it's safe.
1 parent 6021b72 commit 6684358

File tree

4 files changed

+79
-6
lines changed

4 files changed

+79
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
2323
by calling `package.search`, built-in `merger` and `keydef` modules are used
2424
if present in `package.loaded`. It allows to avoid ignoring errors on checking
2525
modules existing via `pcall(require, '<module_name>')`.
26+
* Fixed some cases when module ignored schema updates.
2627

2728
### Added
2829

crud/compare/keydef.lua

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
local msgpack = require('msgpack')
2-
31
local comparators = require('crud.compare.comparators')
42
local collations = require('crud.common.collations')
53

@@ -31,10 +29,15 @@ setmetatable(keydef_cache, {__mode = 'k'})
3129
local function new(space, field_names, index_id)
3230
-- Get requested and primary index metainfo.
3331
local index = space.index[index_id]
34-
local key = msgpack.encode({index_id, field_names})
3532

36-
if keydef_cache[key] ~= nil then
37-
return keydef_cache[key]
33+
-- We use "index" as key here (not some string or something else)
34+
-- since cache should be invalidated on schema update.
35+
-- It will be done automatically because fetch_schema
36+
-- rewrites "index" table in space object.
37+
-- Later lua garbage collector will drop old
38+
-- value from "keydef_cache" table. Since it's a weak table with "k" mode.
39+
if field_names == nil and keydef_cache[index] ~= nil then
40+
return keydef_cache[index]
3841
end
3942

4043
-- Create a key def
@@ -52,7 +55,9 @@ local function new(space, field_names, index_id)
5255
keydef = keydef:merge(keydef_lib.new(normalize_parts(updated_parts)))
5356
end
5457

55-
keydef_cache[key] = keydef
58+
if field_names == nil then
59+
keydef_cache[index] = keydef
60+
end
5661

5762
return keydef
5863
end

test/entrypoint/srv_update_schema.lua

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package.preload['customers-storage'] = function()
1818
{name = 'id', type = 'unsigned'},
1919
{name = 'bucket_id', type = 'unsigned'},
2020
{name = 'value', type = 'string'},
21+
{name = 'number', type = 'integer', is_nullable = true},
2122
},
2223
if_not_exists = true,
2324
engine = engine,
@@ -64,6 +65,20 @@ package.preload['customers-storage'] = function()
6465
unique = false,
6566
})
6667
end)
68+
69+
rawset(_G, 'create_number_value_index', function()
70+
box.space.customers:create_index('number_value_index', {
71+
parts = { {field = 'number'}, {field = 'value'} },
72+
if_not_exists = true,
73+
unique = false,
74+
})
75+
end)
76+
77+
rawset(_G, 'alter_number_value_index', function()
78+
box.space.customers.index.number_value_index:alter({
79+
parts = { {field = 'value'}, {field = 'number'} },
80+
})
81+
end)
6782
end,
6883
}
6984
end

test/integration/updated_shema_test.lua

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ local t = require('luatest')
44

55
local helpers = require('test.helper')
66

7+
local fiber = require('fiber')
8+
local crud = require('crud')
79
local crud_utils = require('crud.common.utils')
810

911
local pgroup = helpers.pgroup.new('updated_schema', {
@@ -742,3 +744,53 @@ pgroup:add('test_borders_value_index_added', function(g)
742744
t.assert_equals(err, nil)
743745
end
744746
end)
747+
748+
pgroup:add('test_alter_index_parts', function(g)
749+
-- create space w/ bucket_id index
750+
helpers.call_on_servers(g.cluster, {'s1-master', 's2-master'}, function(server)
751+
server.net_box:call('create_space')
752+
server.net_box:call('create_bucket_id_index')
753+
server.net_box:call('create_number_value_index')
754+
end)
755+
756+
for i = 0, 9 do
757+
-- Insert {0, 9}, {1, 8}, ..., {9, 0} paris in index
758+
local _, err = g.cluster.main_server.net_box:call(
759+
'crud.replace', {'customers', {i, nil, tostring(i), 9 - i}})
760+
t.assert_equals(err, nil)
761+
end
762+
763+
-- Check sort order before alter
764+
local result, err = g.cluster.main_server.net_box:call(
765+
'crud.select', {'customers', {{'>=', 'number_value_index', {0, "0"}}}}
766+
)
767+
t.assert_equals(err, nil)
768+
t.assert_equals(#result.rows, 10)
769+
770+
local objects = crud.unflatten_rows(result.rows, result.metadata)
771+
for i = 0, 9 do
772+
t.assert_equals(objects[i + 1].number, i)
773+
t.assert_equals(objects[i + 1].value, tostring(9 - i))
774+
end
775+
776+
-- Alter index (lead to index rebuild - change parts order)
777+
helpers.call_on_servers(g.cluster, {'s1-master', 's2-master'}, function(server)
778+
server.net_box:call('alter_number_value_index')
779+
end)
780+
781+
-- Wait for index rebuild and schema update
782+
fiber.sleep(1)
783+
784+
-- Sort order should be new
785+
local result, err = g.cluster.main_server.net_box:call(
786+
'crud.select', {'customers', {{'>=', 'number_value_index', {"0", 0}}}}
787+
)
788+
t.assert_equals(err, nil)
789+
t.assert_equals(#result.rows, 10)
790+
791+
local objects = crud.unflatten_rows(result.rows, result.metadata)
792+
for i = 0, 9 do
793+
t.assert_equals(objects[i + 1].number, 9 - i)
794+
t.assert_equals(objects[i + 1].value, tostring(i))
795+
end
796+
end)

0 commit comments

Comments
 (0)