hchunhui / librime-lua

Extending RIME with Lua scripts
BSD 3-Clause "New" or "Revised" License
293 stars 43 forks source link

sync throws `Error opening db '...': IO error: lock .../...userdb/LOCK: already held by process` when both `Memory` and `table_translator@...` use the same dict #330

Closed sci-42ver closed 2 months ago

sci-42ver commented 2 months ago

Based on rime-fast-xhup and this issue, I use the following to write one custom word to the userdb.

dict_ns = 'melt_eng'
-- in init
env.mem = Memory(env.engine, Schema('double_pinyin_flypy'), dict_ns)
...
-- in func
dict.text = inp
dict.custom_code = inp.." "
dict.comment = '(to add)'
local ph = Phrase(env.mem, "en_custom", seg.start, seg._end, dict)
yield(ph:toCandidate())

Although it has the advantage of loading the committed word automatically without re-deploy, but it will throw Error opening db '...': IO error: lock .../...userdb/LOCK: already held by process error when sync in Fcitx5, etc., but not in weasel where the latter probably solves with this situation inherently. Then we can use file module to manually append the entry to the YAML or txt file, but that will need re-deploy.

Is there one way to avoid the above error but also keep the above advantage?

mirtlecn commented 2 months ago

我在 Weasel 不久之前也碰到过这个 error。在某个时间点后突然消失了。你提到了 issue:

https://github.com/rime/weasel/issues/199

我可以确定,这个问题在 15.0 的某个版本还是有的。

另外,补充,我遇到的问题是:即使 Memory 对象没有调用对应的方案,error log 里面也会提示被锁定,并且程序还会尝试重建用户词典。所以,这个问题我当时并不确定是 Memory 引发的。

但几个月某个改动「修复」(?)了。因为我的配置里面存在用到 Memory 的地方,有的还是不同的 lua 打开同一个方案。同步的时候没有报错。

另外提供一个可能的解决方案(未验证):将在 translator 里面设置 db_class: tabledb。

shewer commented 2 months ago

lua 中的 LevelDb 不支援 db_pool ( 可以多個翻譯器 同時參考己開啓的 userdb) MemoryReg 類似 翻譯器 ,可以同時 和其他翻譯器共用同一個userdb

如果 usredb 先被 LevelDb 開啓 將造成 Translator 無法開啓 userdb 檢查 方案中 lua script 是否有使用 LevelDb 開啓 userdb( LevelDb)

如果一定編輯LevelDb 操作 翻譯器的userdb ,最好是在 rime.lua or init() or fini() ,中操作 且完工時 使用 :close() 關閉

local db = LevelDb('luna_pinyin') 
db:open()
....
db:close()
mirtlecn commented 2 months ago

你好 @shewer ,如果在具体的 lua 中,比如:

local F = {}

function F.init( env )
  local config = env.engine.schema.config
  env.name_space = env.name_space:gsub( '^*', '' )
  local schema = config:get_string( env.name_space .. '/en_schema' ) or 'en'
  F.en_dict = Memory( env.engine, Schema( schema ) )

  env.commit_notifier = env.engine.context.commit_notifier:connect(
                                  function( ctx )
                local cand = ctx:get_selected_candidate()
                local commit_text = ctx:get_commit_text()
                local commit_code = ctx.input

                if (cand and cand.text == commit_text) then
                    if (cand.type == 'sentence' or cand.type == 'raw') and
                        ((commit_text:find( '%a' ) and commit_text:find( '%d' )) or (commit_text:find( '^%a+$' ))) then
                        log.info( '- record: ' .. commit_text )
                        F.update_dict_entry( commit_text, commit_code )
                    end
                else
                    return
                end
            end
                               )
    end
end

function F.update_dict_entry( text, code )
    if #text == 0 then return end
    local e = DictEntry()
    e.text = text
    e.custom_code = code .. ' '
    F.en_dict:update_userdict( e, 1, '' )
end

function F.func( input, env )
   for cand in input:iter() do yield( cand ) end
end

function F.fina( env )
  env.commit_notifier:disconnect()
end

return F

因为脚本中并没有显性地新建 db 这个对象,所以想问这两步是加在哪里呢?

在新建 memory 之前?在 disconnect 之后?

shewer commented 2 months ago

你好 @shewer ,如果在具体的 lua 中,比如:

local F = {}

function F.init( env )
  local config = env.engine.schema.config
  env.name_space = env.name_space:gsub( '^*', '' )
  local schema = config:get_string( env.name_space .. '/en_schema' ) or 'en'
  F.en_dict = Memory( env.engine, Schema( schema ) )

  env.commit_notifier = env.engine.context.commit_notifier:connect(
                                  function( ctx )
                local cand = ctx:get_selected_candidate()
                local commit_text = ctx:get_commit_text()
                local commit_code = ctx.input

                if (cand and cand.text == commit_text) then
                    if (cand.type == 'sentence' or cand.type == 'raw') and
                        ((commit_text:find( '%a' ) and commit_text:find( '%d' )) or (commit_text:find( '^%a+$' ))) then
                        log.info( '- record: ' .. commit_text )
                        F.update_dict_entry( commit_text, commit_code )
                    end
                else
                    return
                end
            end
                               )
    end
end

function F.update_dict_entry( text, code )
    if #text == 0 then return end
    local e = DictEntry()
    e.text = text
    e.custom_code = code .. ' '
    F.en_dict:update_userdict( e, 1, '' )
end

function F.func( input, env )
   for cand in input:iter() do yield( cand ) end
end

function F.fina( env )
  env.commit_notifier:disconnect()
end

return F

因为脚本中并没有显性地新建 db 这个对象,所以想问这两步是加在哪里呢?

在新建 memory 之前?在 disconnect 之后?

F.fina 錯了 是 F.fini(env) notifier 無法解構容易出問題

Mmory 內己註冊 commit_notifier 用不了嗎? 每次 commit 時就會 callback Memorize() , 參考 memory 範例腳本

mirtlecn commented 2 months ago

感谢指正,不过这个是 typo,复制,脱敏,到这里来的时候不小心打错了。

我本想问本 issue 提到的问题,因为 issue 提到的 error log 我曾经碰到过,但现在没有碰到过了。而本 issue 提到说其他平台仍然会有这个错误。

所以想问你提到的代码,是否能解决这个问题,如果能的话,应该加在脚本的哪里,是新建 Memory 对象前还是后,在 disconnect 前还是后?

local db = LevelDb('luna_pinyin') 
db:open()
....
db:close()
shewer commented 2 months ago

如果沒用 LevelDb 就不用在意

mirtlecn commented 2 months ago

Mmory 內己註冊 commit_notifier 用不了嗎? 每次 commit 時就會 callback Memorize() , 參考 memory 範例腳本

这个脚本我记得是为了将 echo_translator 和特定编码的 sentence 候选写入用户词典的,本身候选不属于任何方案内,所以要手动写入。是正常工作且没有 error log 的。

但有一段时间每次同步,发现过本 issue 提到的

IO error: lock .../...userdb/LOCK: already held by process

当时并没有找到问题所在,因为 erro log 中出现了没有在 lua 中调用的方案名,比如 Memory 所用的方案是 en,但 error log 提示 stroke db 无法打开的错误。

过一段时间,突然好了。

现在看到这个 issue,又想起来了。

sci-42ver commented 2 months ago

如果沒用 LevelDb 就不用在意

感谢热情的 shewer 回复,您以往 issue 里的回复对我的帮助很大。

参考我的 1st comment,并没有使用 LevelDb。

如果一定編輯LevelDb 操作 翻譯器的userdb ,最好是在 rime.lua or init() or fini() ,中操作 且完工時 使用 :close() 關閉

如果是这样的话,我抽空用您的 LevelDb 试一下, 可以显性释放 db,感觉应该不会占用 LOCK。整个操作可以放在 func 里么?

sci-42ver commented 2 months ago

我可以确定,这个问题在 15.0 的某个版本还是有的。

那我不太清楚了,我的 weasel 0.15.0 没有这个问题,weasel 代码我没怎么看过,具体为啥会(帮助/不)解锁 LOCK 不太清楚。

另外,补充,我遇到的问题是:即使 Memory 对象没有调用对应的方案,error log 里面也会提示被锁定,并且程序还会尝试重建用户词典。所以,这个问题我当时并不确定是 Memory 引发的。

我这里试过了,把 Memory 关掉后,其他全部不动,不会出现上述报错,可以正常 sync 了 (否则 LOCK 相关用户词典无法 sync)。您的情况我不是太清楚,可能和我的有点区别。

当时并没有找到问题所在,因为 erro log 中出现了没有在 lua 中调用的方案名,比如 Memory 所用的方案是 en,但 error log 提示 stroke db 无法打开的错误。

您提到 stroke,看到您写的 search.lua 代码(已 merge 到 rime-ice),可能和 ReverseLookup 有关系,本质上应该都和 db 有关,属于同一类问题 (目前我只在反查里看到有用过 stroke)。 我 Reverse 词典基本上不用,不是太懂。 在这里感谢您给 rime-ice 写的那么多 lua 代码,方便了 lua 新手写 lua 代码。

另外提供一个可能的解决方案(未验证):将在 translator 里面设置 db_class: tabledb。

嗯,感谢您的建议。目前我也是这样处理的(见 imfuxiao/Hamster#593)

shewer commented 2 months ago

LevelDb 主要是提供 librime-lua 大量的 key value db 應用 雖然可以開啓 userdict.userdb 但是要小心 操作 我是不會在librime 工作程序中 開啓 userdict

sci-42ver commented 2 months ago

LevelDb 主要是提供 librime-lua 大量的 key value db 應用 雖然可以開啓 userdb 但是要小心 操作

看文档里写到 '不可用於 已開啓 的userdb, 專用於 librime-lua key-value db' 这样的话,我把我的需求再详细描述一下吧,您帮忙看下有没有什么更好的办法?

当输入 'foobarfoo' 其用特定字符如'' 结尾时,将其标记为 自造英文词汇 并写入词典,最好可以像用户词典那样,不需要重新部署就可以记忆(即 下一次输入时,会列入候选项)。

shewer commented 2 months ago

替換 echo_translator , 檢查 inp 字尾 * 時將inp 製作成 Phras

使用 env.name_space 指定方案

--echo_translator.lua
local function memoryCallback1(commits)
  for i, dictentry in ipairs(commits:get()) do
    commits:update_entry(dictentry, 1, "")
  end
end

local T = {}
function T.init(env)
  env.name_space = env.name_space:match("[^*]*$")
  env.mem = Memory(env.engine,Schema(env.name_space) )  --  ns= "translator"
  env.mem:memorize(memoryCallback1)
end
function T.fini(env)
   env.mem = nil
end

function T.func(inp,seg,env)
  if inp:match("%*$") then
    local entry = DictEntry()
    entry.text = inp:sub(1, -2)
    entry.custom_code = entry.text .. " " -- 必須加上 空白
    local ph = Phrase(env.mem, "userdict", seg._start, seg._end, entry)
    ph.quility = -100
    yield(ph:toCandidate())
  else
    local cand = Candidate('raw', seg._start, seg._end, inp, "RAW")
    cand.quality = -100
    yield(cand)
  end
end

return T
sci-42ver commented 2 months ago

使用 Schema(env.name_space) 配合 lua_translator@en_custom_translator 确实不会 LOCK,因为使用的词典是只属于此 lua 脚本的。

但是,此时 env.name_space=en_custom_translator,应该需要一个对应的 en_custom_translator.schema.yaml。然后,主 schema.yaml 添加 table_translator@en_custom_translator 来导入自造词。这样的话依然会有 "Error opening db 'en_custom_translator': IO error: lock .../en_custom_translator.userdb/LOCK: already held by process" message。"

暂时可以切换方案来同步 (即只使用一个 schema 来自造英文词汇),因为 lua_translator@en_custom_translator只属于一个 schema 的。之前由于几个 schema 都用了 lua_translator@en_custom_translator (名字不一样,不过都调用同一个 lua 脚本。),故切换方案无效。

请问有办法做 db:close() 类似的操作于 userdb,从而不切换方案也可同步?(在 hamster 上,切换方案并不会自动释放 LOCK。见 问题里引用的第2个链接 fcitx/fcitx5-rime#97)


  1. 上述方案可以通过 yield(ph:toCandidate()) 产生 candidate。但是 env.mem:memorize(memoryCallback1) 并不运行 memoryCallback1 (在此函数最开始加了 log.info,但是 log 里并不产生此 info)。

  2. 不清楚上述 commits:update_entry 是不是一个 pseudo code,文档里用的是 memory:update_userdict (memory是一个 Memory instance)。

mirtlebot commented 2 months ago

Weasel 在同步的时候,会进入【维护模式】,释放占用的文件资源。或许因此不会出现 LOCK 的情况。

不清楚这种维护模式是否是所有前端都有的逻辑,也不清楚在这种维护模式下,lua 是否会按设计释放资源。

mokapsing commented 2 months ago

但是,此时 env.name_space=en_custom_translator,应该需要一个对应的 en_custom_translator.schema.yaml

这个结论怎么来的

mirtlecn commented 2 months ago

刚刚试了下 leveldb,改了下 repo 的 sample,可以作为用户词典用,比如你的需求:

结尾是 * 号,写入用户词典,无须重新部署就能使用

演示:shei* -> shei

1713431677

-- leveldb.lua

-- - lua_translator@*leveldb@dict
-- dict:
--   dictionary: lua
--   initial_quality: 1.5

db_pool_ = {}

local function opendb( name )
    local db = db_pool_[name]
    if not db then
        db = LevelDb( name )
        if not db then return nil end
        db_pool_[name] = db
    end
    if not db:loaded() then db:open() end
    return db
end

local function update_entry( text, code, db )
    if #text == 0 then return end
    db:update( code, text )
end

local M = {}

function M.init( env )
    local config = env.engine.schema.config
    local dbname = config:get_string( env.name_space .. '/dictionary' )
    env.quality = tonumber( config:get_string( env.name_space .. '/initial_quality' ) ) or 1
    env.db = assert( opendb( dbname ), 'initleveldb failed' )

    env.commit_notifier = env.engine.context.commit_notifier:connect(
                              function( ctx )
            local commit_text = ctx:get_commit_text()
            local commit_code = ctx.input
            local cand = ctx:get_selected_candidate()
            local cand_text = cand.text
            if (cand and cand_text == commit_text and cand.type == 'new') then
                commit_code = commit_code:gsub( '*$', '' )
                print( '- record: ' .. commit_text .. ' | ' .. commit_code )
                update_entry( commit_text, commit_code, env.db )
            end
        end
                           )
end

function M.fini( env )
    env.db:close()
    env.commit_notifier:disconnect()
end

function M.func( inp, seg, env )
    if inp:find('*$') then
        local cand = Candidate('new', seg.start, seg._end, inp:gsub('*$',''), '+')
        yield(cand)
    end

    for _, v in env.db:query( inp ):iter() do
        local type = 'lua'
        local cand = Candidate( type, seg.start, seg._end, v, '#' )
        cand.quality = env.quality
        yield( cand )
    end
end

return M

不过我用 rime_dict_manager 没办法导出数据,不晓得怎么方便地备份里面的 key value

shewer commented 2 months ago

使用 Schema(env.name_space) 配合 lua_translator@en_custom_translator 确实不会 LOCK,因为使用的词典是_只属于此 lua 脚本_的。

如果方案中有 該字典的 namespace 可以參考 下面 create memory 的參數

Memory( engine, schema[,ns])  
Memory(env.engine, env.engine.schema) -- 使用用本方案ns="translator"
Momory(env.engine, Schema('cangjie5') ) -- 使用外部方案 ns=translator
Memory(env.engine, Schema('cangjie5'), 'cangjie6') ns='cangjie6'

但是,此时 env.name_space=en_custom_translator,应该需要一个对应的 en_custom_translator.schema.yaml。然后,主 schema.yaml 添加 table_translator@en_custom_translator 来导入自造词。这样的话依然会有 "Error opening db 'en_custom_translator': IO error: lock .../en_custom_translator.userdb/LOCK: already held by process" message。"

暂时可以切换方案来同步 (即只使用一个 schema 来自造英文词汇),因为 lua_translator@en_custom_translator只属于一个 schema 的。之前由于几个 schema 都用了 lua_translator@en_custom_translator (名字不一样,不过都调用同一个 lua 脚本。),故切换方案无效。

请问有办法做 db:close() 类似的操作于 userdb,从而不切换方案也可同步?(在 hamster 上,切换方案并不会自动释放 LOCK。见 问题里引用的第2个链接 fcitx/fcitx5-rime#97)

  1. 上述方案可以通过 yield(ph:toCandidate()) 产生 candidate。但是 env.mem:memorize(memoryCallback1) 并不运行 memoryCallback1 (在此函数最开始加了 log.info,但是 log 里并不产生此 info)。

  2. 不清楚上述 commits:update_entry 是不是一个 pseudo code,文档里用的是 memory:update_userdict (memory是一个 Memory instance)。

新版本 librime-lua 已在 CommitEntryReg 加入 update_entry methods , 所以不須要引用 upvalue 舊版本是使用 upvalue 機制取得 mem

--old
env.mem:memorize( function(commits)  callback(env.mem,commits) end) -- callback(mem,commits)
--new
env.mem:memorize( callback1) -- callback1(commits)

剛剛 測試 ,在mem 中開啓的 userdb , 無法再用 leveldb 操作

mem 生成後 userdb 始終開啓,LevelDb 也是無法開啓, 
mem.user_dict.loaded   -- true
leveldb._loaded -- false
leveldb:close() --  false   , close() 程序會先檢查 loaded 狀態再執行 ,所以 close 失敗 
leveldb:open()  -- error  無法開啓

我在 fini 中 加入 env.mem = nil 提前清除 期望提前 gc , 你可試試, rime_api_console 版本 ver : " (id:unknown) Ver: librime 1.11.0 librime-lua 287 lua Lua 5.4"

mirtlecn commented 2 months ago

请教一个问题,这个 leveldb 的数值可以像 librime 的 userdb 借助 librime cli 导出、合并吗?@shewer

似乎 rime_dict manager 导出的是只有文件头的空内容,

倒是发现用

for k,v in env.db:query(''):iter() do
    print (k,v)
end

能获取一份内容。是不是只能在 lua 里面这些合并、导出的操作。

比如说这个根据 sample 做小小改动的脚本 https://github.com/hchunhui/librime-lua/issues/330#issuecomment-2063339939

sci-42ver commented 2 months ago

但是,此时 env.name_space=en_custom_translator,应该需要一个对应的 en_custom_translator.schema.yaml

这个结论怎么来的

@mokapsing 实际效果是这样 您可以自己试一下。不过这个不是重点,因为这个参数可以自己配置。

sci-42ver commented 2 months ago

新版本 librime-lua 已在 CommitEntryReg 加入 update_entry methods , 所以不須要引用 upvalue 舊版本是使用 upvalue 機制取得 mem

我用的是旧版本,要对您的代码做点小修改用在自己电脑上。

我在 fini 中 加入 env.mem = nil 提前清除 期望提前 gc ,

@shewer 加了 log 进行查看,确实会提前 env.mem = nil,然后,进行同步。但是 LOCK 并没有释放。

我 Fcitx5 用的是 Arch Linux 编译好的 1.10.0

shewer commented 2 months ago

请教一个问题,这个 leveldb 的数值可以像 librime 的 userdb 借助 librime cli 导出、合并吗?@shewer

似乎 rime_dict manager 导出的是只有文件头的空内容,

倒是发现用

for k,v in env.db:query(''):iter() do
    print (k,v)
end

能获取一份内容。是不是只能在 lua 里面这些合并、导出的操作。

比如说这个根据 sample 做小小改动的脚本 #330 (comment)

沒深入了解,可以看 librime/tools/ 中code ,說不定 librime-lua userdb api 可以完成 ,前提是在 engine/translators 導入前 完成 userdb 處理井 close() ,避免 translator 無法開啓 userdict

同步時不會把user_dict 導出嗎?

shewer commented 2 months ago

我在 fini 中 加入 env.mem = nil 提前清除 期望提前 gc ,

@shewer 加了 log 进行查看,确实会提前 env.mem = nil,然后,进行同步。但是 LOCK 并没有释放。

我 Fcitx5 用的是 Arch Linux 编译好的 1.10.0

librime-lua git版本 ix: reduce peak memory usage (7f3eca2ce6 )

查查 librime-lua 的版本

 local function find_ver()
    if  KeyEvent(0x41,0):repr() == "A" then
        return 321
    elseif Component and Component.TableTranslator then
       return 287
    elseif UserDb and TableDb then
       return 240
    elseif UserDb then
       return 220
    elseif rime_api.regex_match then
       return 197
    elseif rime_api.get_distribution_name then
       return 185
    elseif LevelDb then
       return 177
    elseif Opencc then
       return 147
    elseif KeySequence and KeySequence().repr then
       return 139
    elseif  ConfigMap and ConfigMap().keys then
       return 127
    elseif Projection then
       return 102
    elseif KeyEvent then
       return 100
    elseif Memory then
       return 80
    elseif rime_api.get_user_data_dir then
       return 9
    elseif log then
       return 9
    else
       return 0
    end
 end
sci-42ver commented 2 months ago

查查 librime-lua 的版本

@shewer https://gitlab.archlinux.org/archlinux/packaging/packages/librime/-/blob/main/PKGBUILD?ref_type=heads#L9 -> https://github.com/hchunhui/librime-lua/tree/7f3eca2ce659fc2401b8acb52bd2182b433e12b1

运行结果为 287。

mirtlecn commented 2 months ago

玩了一会 leveldb,用做临时的词典的话,刚刚能用。

导入导出不成问题,但权重可能有点麻烦,让 GitHub Copilot 根据样例写了个大概:

leveldb.lua.txt


但还是想搞清楚这个 issue 提到的问题如何解决

sci-42ver commented 2 months ago

https://github.com/mirtlecn/rime/blob/master/tools/lua/leveldb.lua

感谢您提供的方案。试了一下,这样即使多个 schema 共用这个 db 也没有问题。因为 db.close() 释放资源,同时 sync 完全分离出来了。(不过 sync 暂时需要全部手写,上述支持导入导出,不同设备 sync 需要检测重复的 entry 然后 merge。)

这样规避了 table_translator,从而不会有两个 translator 抢占一个 LOCK 的情况。


感觉和原本 rime-fast-xhupen_custom.lua 很类似,只不过 rime-fast-xhup 调用 file 添加词条,sync 也是通过 file。由于检索是完全匹配,并不是 prefix,故需要重新部署导入词典的新词。做一点小修改 (问问题之前应该想到这种方法的。感谢大家的热心帮助):

local file = assert(io.open(dict_path, "r")) --打开
for line in file:lines() do
  local cand_text=string.match(line,'^(.*)\t'..input)
  if cand_text then
    yield(Candidate("en_custom", seg.start, seg._end, cand_text,'(manual search)'))
  end
end
file:close()

然后和上面一样,不用 table_translator


这样的话相当于两种方案,LevelDbfile,基本原理是类似的。

sci-42ver commented 2 months ago

@shewer 可以再问一个和本 issue 相关的小问题么?

我想着用 rime 默认删词按键 ^K 来删除上述手动管理的 tabledb 某一个词汇,可以通过 lua_processor 删除 (返回2方便后续lua_translator更新),但是无法像 rime 删除词汇那样及时更新 menu。我是用上一个 comment 方法来手动产生 candidate 的。


现象是通过 log 查看,后续的 lua_translator 和 lua_filter 都不调用 (在仅按下 ^K 情况下)。

librime 里应该是通过 RefreshNonConfirmedComposition 里的 update_notifier_ 刷新的,但是 lua_translator 和 lua_filter 好像并不接受 notifier, 除非输入 alphabet 里的字符。

shewer commented 2 months ago

SegmentReg select_index ContextReg delete_current_selection() 會蜀發 delete notifier 查看 memory.cc OnDeleteEntry() 處理完,會用RefreshNonConfirmedComposition() 刷新 ,重新Compose()

│ void Memory::OnDeleteEntry(Context* ctx) {
│   if (!user_dict_ || user_dict_->readonly() || !ctx || !ctx->HasMenu())
│     return;
│   auto phrase =
│       As<Phrase>(Candidate::GetGenuineCandidate(ctx->GetSelectedCandidate()));
│   if (Language::intelligible(phrase, this)) {
│     const DictEntry& entry(phrase->entry());
│     LOG(INFO) << "deleting entry: '" << entry.text << "'.";
│     user_dict_->UpdateEntry(entry, -1);  // mark as deleted in user dict
│     ctx->RefreshNonConfirmedComposition();
│   }
│ }
sci-42ver commented 2 months ago

感谢。之前弄错了,由于 lua_translator 直接用 Candidate construct 候选项,As<Phrase> 会变成 NULL,所以之前 lua 里用 delete_current_selection 无效。

lua 里直接调用 refresh_non_confirmed_composition 来刷新 kGuess 相关 candidate,可行。

shewer commented 2 months ago

發現 user_dict 是leveldb 時 須要操作 StartSession() FinishSession() DiscardSession() Memory::OnCommit() 時須要 call StartSession() TableTranslation ScriptTranslation 在產生 Translation 前 會 call FiniSession()

在 callback 外部操作 update_entry 會少了 StartSession() 操作

Memory::OnCommit() https://github.com/rime/librime/blob/1f3bf35691a5ad066ef36775e289525f3b092e28/src/rime/gear/memory.cc#L104

TableTranslaion ScriptTranslation 開始時 call FinishSession() https://github.com/rime/librime/blob/1f3bf35691a5ad066ef36775e289525f3b092e28/src/rime/gear/table_translator.cc#L249

https://github.com/rime/librime/blob/1f3bf35691a5ad066ef36775e289525f3b092e28/src/rime/gear/script_translator.cc#L198

class LevelDb https://github.com/rime/librime/blob/1f3bf35691a5ad066ef36775e289525f3b092e28/src/rime/dict/level_db.h#L35

mirtlecn commented 2 months ago

这个 bug 打算如何处理呢?

是禁止在 memory callback 外使用 update_entry,抛出明确的错误或者警告,还是如何?