diff --git a/src/box/lua/ctl.c b/src/box/lua/ctl.c index 7010be1387d0b4707d9a0afd643041113628a164..85ed30c505ff59424c76870abe97ecbf463782a3 100644 --- a/src/box/lua/ctl.c +++ b/src/box/lua/ctl.c @@ -40,6 +40,7 @@ #include "lua/trigger.h" #include "box/box.h" +#include "box/schema.h" static int lbox_ctl_wait_ro(struct lua_State *L) @@ -71,10 +72,17 @@ lbox_ctl_on_shutdown(struct lua_State *L) return lbox_trigger_reset(L, 2, &box_on_shutdown, NULL, NULL); } +static int +lbox_ctl_on_schema_init(struct lua_State *L) +{ + return lbox_trigger_reset(L, 2, &on_schema_init, NULL, NULL); +} + static const struct luaL_Reg lbox_ctl_lib[] = { {"wait_ro", lbox_ctl_wait_ro}, {"wait_rw", lbox_ctl_wait_rw}, {"on_shutdown", lbox_ctl_on_shutdown}, + {"on_schema_init", lbox_ctl_on_schema_init}, {NULL, NULL} }; diff --git a/src/box/schema.cc b/src/box/schema.cc index 8625d92eac82f7778700e814c438810eba3c601b..74d70d8d607550cce9aa8facab5da8465071a7d1 100644 --- a/src/box/schema.cc +++ b/src/box/schema.cc @@ -69,6 +69,7 @@ uint32_t schema_version = 0; */ uint32_t space_cache_version = 0; +struct rlist on_schema_init = RLIST_HEAD_INITIALIZER(on_schema_init); struct rlist on_alter_space = RLIST_HEAD_INITIALIZER(on_alter_space); struct rlist on_alter_sequence = RLIST_HEAD_INITIALIZER(on_alter_sequence); @@ -500,6 +501,12 @@ schema_init() init_system_space(space); trigger_run_xc(&on_alter_space, space); } + + /* + * Run the triggers right after creating all the system + * space stubs. + */ + trigger_run(&on_schema_init, NULL); } void diff --git a/src/box/schema.h b/src/box/schema.h index f3df08b48bc2fee9529497c8f483cc79e0fb44da..6f9a96117e1baf31dd2a5c70f76e08e017c48bba 100644 --- a/src/box/schema.h +++ b/src/box/schema.h @@ -44,6 +44,9 @@ extern "C" { extern uint32_t schema_version; extern uint32_t space_cache_version; +/** Triggers invoked after schema initialization. */ +extern struct rlist on_schema_init; + /** * Lock of schema modification */ diff --git a/test/box-tap/on_schema_init.test.lua b/test/box-tap/on_schema_init.test.lua new file mode 100755 index 0000000000000000000000000000000000000000..51b28ea083bb2c759d6dba51402d1501fad76fde --- /dev/null +++ b/test/box-tap/on_schema_init.test.lua @@ -0,0 +1,31 @@ +#!/usr/bin/env tarantool + +-- +-- gh-3159: test on_schema_init trigger +-- +local tap = require('tap') +local test = tap.test('on_schema_init') +local str = '' +test:plan(7) + +function testing_trig() + test:istable(box.space._space, 'system spaces are accessible') + test:is(type(box.space._space.before_replace), 'function', 'before_replace triggers') + test:is(type(box.space._space.on_replace), 'function', 'on_replace triggers') + test:is(type(box.space._space:on_replace(function() str = str.."_space:on_replace" end)), + 'function', 'set on_replace trigger') + str = str..'on_schema_init' +end + +trig = box.ctl.on_schema_init(testing_trig) +test:is(type(trig), 'function', 'on_schema_init trigger set') + +box.cfg{log = 'tarantool.log'} +test:like(str, 'on_schema_init', 'on_schema_init trigger works') +str = '' +box.schema.space.create("test") +-- test that _space.on_replace trigger may be set in on_schema_init +test:like(str, '_space:on_replace', 'can set on_replace') +test:check() +box.space.test:drop() +os.exit(0) diff --git a/test/replication/on_schema_init.result b/test/replication/on_schema_init.result new file mode 100644 index 0000000000000000000000000000000000000000..3f7ee0bd0de77ee94ab91cb42d72fe7ece52ff38 --- /dev/null +++ b/test/replication/on_schema_init.result @@ -0,0 +1,119 @@ +env = require('test_run') +--- +... +test_run = env.new() +--- +... +-- gh-3159: on_schema_init triggers +-- the replica has set an on_schema_init trigger, which will set +-- _space:before_replace triggers to change 'test_engine' space engine +-- and 'test_local' space is_local flag when replication starts. +test_run:cmd('create server replica with rpl_master=default, script="replication/replica_on_schema_init.lua"') +--- +- true +... +test_engine = box.schema.space.create('test_engine', {engine='memtx'}) +--- +... +test_local = box.schema.space.create('test_local', {is_local=false}) +--- +... +test_engine.engine +--- +- memtx +... +test_local.is_local +--- +- false +... +_ = test_engine:create_index("pk") +--- +... +_ = test_local:create_index("pk") +--- +... +test_engine:insert{1} +--- +- [1] +... +test_local:insert{2} +--- +- [2] +... +box.schema.user.grant('guest', 'replication') +--- +... +test_run:cmd('start server replica') +--- +- true +... +test_run:cmd('switch replica') +--- +- true +... +box.space.test_engine.engine +--- +- vinyl +... +box.space.test_local.is_local +--- +- true +... +box.space.test_engine:insert{3} +--- +- [3] +... +box.space.test_local:insert{4} +--- +- [4] +... +box.space.test_engine:select{} +--- +- - [1] + - [3] +... +box.space.test_local:select{} +--- +- - [2] + - [4] +... +test_run:cmd('switch default') +--- +- true +... +test_run:cmd('set variable replica_port to "replica.listen"') +--- +- true +... +box.cfg{replication=replica_port} +--- +... +test_engine:select{} +--- +- - [1] + - [3] +... +-- the space truly became local on replica +test_local:select{} +--- +- - [2] +... +box.cfg{replication=nil} +--- +... +test_run:cmd('stop server replica with cleanup=1') +--- +- true +... +test_run:cleanup_cluster() +--- +... +box.schema.user.revoke('guest', 'replication') +--- +... +test_engine:drop() +--- +... +test_local:drop() +--- +... diff --git a/test/replication/on_schema_init.test.lua b/test/replication/on_schema_init.test.lua new file mode 100644 index 0000000000000000000000000000000000000000..9bb9e477539efeaafa9826a43dc0243169a55579 --- /dev/null +++ b/test/replication/on_schema_init.test.lua @@ -0,0 +1,49 @@ +env = require('test_run') +test_run = env.new() + +-- gh-3159: on_schema_init triggers + +-- the replica has set an on_schema_init trigger, which will set +-- _space:before_replace triggers to change 'test_engine' space engine +-- and 'test_local' space is_local flag when replication starts. +test_run:cmd('create server replica with rpl_master=default, script="replication/replica_on_schema_init.lua"') + +test_engine = box.schema.space.create('test_engine', {engine='memtx'}) +test_local = box.schema.space.create('test_local', {is_local=false}) +test_engine.engine +test_local.is_local + +_ = test_engine:create_index("pk") +_ = test_local:create_index("pk") + +test_engine:insert{1} +test_local:insert{2} + +box.schema.user.grant('guest', 'replication') + +test_run:cmd('start server replica') +test_run:cmd('switch replica') + +box.space.test_engine.engine +box.space.test_local.is_local + +box.space.test_engine:insert{3} +box.space.test_local:insert{4} + +box.space.test_engine:select{} +box.space.test_local:select{} + +test_run:cmd('switch default') + +test_run:cmd('set variable replica_port to "replica.listen"') +box.cfg{replication=replica_port} +test_engine:select{} +-- the space truly became local on replica +test_local:select{} + +box.cfg{replication=nil} +test_run:cmd('stop server replica with cleanup=1') +test_run:cleanup_cluster() +box.schema.user.revoke('guest', 'replication') +test_engine:drop() +test_local:drop() diff --git a/test/replication/replica_on_schema_init.lua b/test/replication/replica_on_schema_init.lua new file mode 100644 index 0000000000000000000000000000000000000000..8a221681bda4ae58e11211e81d7ca7c4cfdac761 --- /dev/null +++ b/test/replication/replica_on_schema_init.lua @@ -0,0 +1,25 @@ +#!/usr/bin/env tarantool + +function trig_local(old, new) + if new and new[3] == 'test_local' and new[6]['group_id'] ~= 1 then + return new:update{{'=', 6, {group_id = 1}}} + end +end + +function trig_engine(old, new) + if new and new[3] == 'test_engine' and new[4] ~= 'vinyl' then + return new:update{{'=', 4, 'vinyl'}} + end +end + +box.ctl.on_schema_init(function() + box.space._space:before_replace(trig_local) + box.space._space:before_replace(trig_engine) +end) + +box.cfg({ + listen = os.getenv("LISTEN"), + replication = os.getenv("MASTER"), +}) + +require('console').listen(os.getenv('ADMIN')) diff --git a/test/replication/suite.cfg b/test/replication/suite.cfg index fc7c0c4646fdbcac71e8b1d7c4f3d882f604b8e4..5e880973111a35b27bf5c87804539f1c9fdeec5c 100644 --- a/test/replication/suite.cfg +++ b/test/replication/suite.cfg @@ -8,6 +8,7 @@ "rebootstrap.test.lua": {}, "wal_rw_stress.test.lua": {}, "force_recovery.test.lua": {}, + "on_schema_init.test.lua": {}, "*": { "memtx": {"engine": "memtx"}, "vinyl": {"engine": "vinyl"}