关于2)我遇到了问题。在我的情况下,启用“在创建空间时”触发会导致 read_only 错误。原因是:触发器在从 WAL 读取时尝试更新到统计表。
local function before_replace(old, new)
-- collision resolving here
if box.session.type() ~= 'applier' then
box.space.stat:upsert(
{ "key", 0 },
{
{"+", stat.COUNT, 1}
})
end
return
end
在那种情况下,我只需要在读取 WAL 时启用触发器。在复制同步开始之前(否则我可能会遇到冲突或统计数据松散)。我发现这是做这件事的正确时机。在 box.info.status 从“正在加载”更改后,我启用了触发器。像这样:
local my_space_name = 'myspace'
local function loading_before_replace(old, new)
if box.info.status == "loading" then
return
end
box.space.my_space_name:before_replace(before_replace, loading_before_replace)
return before_replace(old,new)
end
local function _space_on_replace(old, new)
if not new or not new.name then
return
end
-- skip system spaces
if string.startswith(new.name, "_") then
return
end
if new.name == my_space_name then
box.on_commit(function()
box.space.my_space_name:before_replace(loading_before_replace)
end)
end
end
local function set_triggers()
box.ctl.on_schema_init(function()
box.space._space:on_replace(_space_on_replace)
end)
end
因此before_replace()
触发器将myspace
在初始 WAL 读取后的第一次提交时执行并启用。
也许有可能在 box.info.status 改变时触发?这可以使代码更干净。但我不知道这是否可能。