-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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
Comments
我在 Weasel 不久之前也碰到过这个 error。在某个时间点后突然消失了。你提到了 issue: 我可以确定,这个问题在 15.0 的某个版本还是有的。 另外,补充,我遇到的问题是:即使 Memory 对象没有调用对应的方案,error log 里面也会提示被锁定,并且程序还会尝试重建用户词典。所以,这个问题我当时并不确定是 Memory 引发的。 但几个月某个改动「修复」(?)了。因为我的配置里面存在用到 Memory 的地方,有的还是不同的 lua 打开同一个方案。同步的时候没有报错。 另外提供一个可能的解决方案(未验证):将在 translator 里面设置 db_class: tabledb。 |
lua 中的 LevelDb 不支援 db_pool ( 可以多個翻譯器 同時參考己開啓的 userdb) 如果 usredb 先被 LevelDb 開啓 將造成 Translator 無法開啓 userdb 如果一定編輯LevelDb 操作 翻譯器的userdb ,最好是在 rime.lua local db = LevelDb('luna_pinyin')
db:open()
....
db:close() |
你好 @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 用不了嗎? |
感谢指正,不过这个是 typo,复制,脱敏,到这里来的时候不小心打错了。 我本想问本 issue 提到的问题,因为 issue 提到的 error log 我曾经碰到过,但现在没有碰到过了。而本 issue 提到说其他平台仍然会有这个错误。 所以想问你提到的代码,是否能解决这个问题,如果能的话,应该加在脚本的哪里,是新建 Memory 对象前还是后,在 disconnect 前还是后? local db = LevelDb('luna_pinyin')
db:open()
....
db:close() |
如果沒用 LevelDb 就不用在意 |
这个脚本我记得是为了将 echo_translator 和特定编码的 sentence 候选写入用户词典的,本身候选不属于任何方案内,所以要手动写入。是正常工作且没有 error log 的。 但有一段时间每次同步,发现过本 issue 提到的
当时并没有找到问题所在,因为 erro log 中出现了没有在 lua 中调用的方案名,比如 Memory 所用的方案是 en,但 error log 提示 stroke db 无法打开的错误。 过一段时间,突然好了。 现在看到这个 issue,又想起来了。 |
感谢热情的 shewer 回复,您以往 issue 里的回复对我的帮助很大。 参考我的 1st comment,并没有使用 LevelDb。
如果是这样的话,我抽空用您的 LevelDb 试一下, 可以显性释放 db,感觉应该不会占用 LOCK。整个操作可以放在 |
那我不太清楚了,我的
我这里试过了,把 Memory 关掉后,其他全部不动,不会出现上述报错,可以正常 sync 了 (否则 LOCK 相关用户词典无法 sync)。您的情况我不是太清楚,可能和我的有点区别。
您提到 stroke,看到您写的
嗯,感谢您的建议。目前我也是这样处理的(见 imfuxiao/Hamster#593) |
LevelDb 主要是提供 librime-lua 大量的 key value db 應用 |
看文档里写到 '不可用於 已開啓 的userdb, 專用於 librime-lua key-value db' 当输入 'foobarfoo*' 其用特定字符如'*' 结尾时,将其标记为 自造英文词汇 并写入词典,最好可以像用户词典那样,不需要重新部署就可以记忆(即 下一次输入时,会列入候选项)。 |
替換 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 |
使用 但是,此时 暂时可以切换方案来同步 (即只使用一个 schema 来自造英文词汇),因为 请问有办法做
|
Error opening db '...': IO error: lock .../...userdb/LOCK: already held by process
when using Memory
Error opening db '...': IO error: lock .../...userdb/LOCK: already held by process
when both Memory
and table_translator@...
use the same dict
Weasel 在同步的时候,会进入【维护模式】,释放占用的文件资源。或许因此不会出现 LOCK 的情况。 不清楚这种维护模式是否是所有前端都有的逻辑,也不清楚在这种维护模式下,lua 是否会按设计释放资源。 |
这个结论怎么来的 |
刚刚试了下 leveldb,改了下 repo 的 sample,可以作为用户词典用,比如你的需求:
演示:shei* -> shei -- 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 |
如果方案中有 該字典的 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'
新版本 librime-lua 已在 CommitEntryReg 加入 update_entry methods , 所以不須要引用 upvalue --old
env.mem:memorize( function(commits) callback(env.mem,commits) end) -- callback(mem,commits)
--new
env.mem:memorize( callback1) -- callback1(commits) 剛剛 測試 ,在mem 中開啓的 userdb , 無法再用 leveldb 操作
我在 fini 中 加入 env.mem = nil 提前清除 期望提前 gc , 你可試試, |
请教一个问题,这个 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) |
@mokapsing 实际效果是这样 您可以自己试一下。不过这个不是重点,因为这个参数可以自己配置。 |
我用的是旧版本,要对您的代码做点小修改用在自己电脑上。
@shewer 加了 log 进行查看,确实会提前 我 Fcitx5 用的是 Arch Linux 编译好的 1.10.0 |
沒深入了解,可以看 librime/tools/ 中code ,說不定 librime-lua userdb api 可以完成 ,前提是在 engine/translators 導入前 完成 userdb 處理井 close() ,避免 translator 無法開啓 userdict 同步時不會把user_dict 導出嗎? |
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 |
玩了一会 leveldb,用做临时的词典的话,刚刚能用。 导入导出不成问题,但权重可能有点麻烦,让 GitHub Copilot 根据样例写了个大概: 但还是想搞清楚这个 issue 提到的问题如何解决 |
感谢您提供的方案。试了一下,这样即使多个 schema 共用这个 db 也没有问题。因为 这样规避了 感觉和原本 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() 然后和上面一样,不用 这样的话相当于两种方案, |
@shewer 可以再问一个和本 issue 相关的小问题么? 我想着用 rime 默认删词按键 ^K 来删除上述手动管理的 tabledb 某一个词汇,可以通过 lua_processor 删除 (返回2方便后续lua_translator更新),但是无法像 rime 删除词汇那样及时更新 现象是通过 log 查看,后续的 lua_translator 和 lua_filter 都不调用 (在仅按下 ^K 情况下)。 librime 里应该是通过 |
SegmentReg select_index │ 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();
│ }
│ } |
感谢。之前弄错了,由于 lua_translator 直接用 lua 里直接调用 |
發現 user_dict 是leveldb 時 在 callback 外部操作 update_entry 會少了 StartSession() 操作 Memory::OnCommit() TableTranslaion ScriptTranslation 開始時 call FinishSession() class LevelDb |
这个 bug 打算如何处理呢? 是禁止在 memory callback 外使用 update_entry,抛出明确的错误或者警告,还是如何? |
Based on
rime-fast-xhup
and this issue, I use the following to write one custom word to the userdb.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 usefile
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?
The text was updated successfully, but these errors were encountered: