故障表现
在Debian 12和Ubuntu 22.04及以上版本中,如果使用ibus-libpinyin,会有概率性出现输入卡死无响应,等待一段时间才会有文字输出。
ibus-libpinyin上面也有人提了这个issue:https://github.com/libpinyin/ibus-libpinyin/issues/429
解决方法
用如下命令,删除当前登录用户下ibus-libpinyin产生的所有.tmp缓存文件:
rm -rf ~/.cache/ibus/libpinyin/*.tmp
如果有兴趣知道问题根源的话,可以继续阅读。
排查过程
从strace ibus-engine-libpinyin进程发现,似乎是一些__db.*.tmp文件导致的:
unlink("/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp") = -1 ENOENT (No such file or directory)
unlink("/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp") = -1 ENOENT (No such file or directory)
getpid() = 29864
openat(AT_FDCWD, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 18
read(18, "0-15\n", 1024) = 5
close(18) = 0
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
newfstatat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/user_pinyin_index.bin.tmp", 0xxxxxxxxxxxxx, 0) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/devreporter/.cache/ibus/libpinyin/__db.user_pinyin_index.bin.tmp", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EEXIST (File exists)
pselect6(0, NULL, NULL, NULL, {tv_sec=1, tv_nsec=1000}, NULL) = 0 (Timeout)
//......()
write(2, "BDB0002 __fop_file_setup: Retry"..., 53) = 53
write(2, "\n", 1) = 1
找到gnu出处,是这么说的:
If both O_CREAT and O_EXCL are set, then open fails if the specified file already exists. This is guaranteed to never clobber an existing file.
再细看~/.cache/ibus/libpinyin目录,这里面的文件貌似是Berkeley DB,那么这些__db*.tmp文件怎样来的呢?
阅读libpinyin库源代码后,发现“.tmp”后缀是这么来的,先看pinyin.cpp:
struct _pinyin_context_t{
//忽略
/* default tables. */
FacadeChewingTable2 * m_pinyin_table;
//忽略
};
bool pinyin_save(pinyin_context_t * context){
//忽略
bool retval = _write_files(context) && _rename_files(context);
//忽略
}
static bool _write_files(pinyin_context_t * context){
//忽略
/* save user pinyin table */
gchar * tmpfilename = g_build_filename
(context->m_user_dir, USER_PINYIN_INDEX ".tmp", NULL);
unlink(tmpfilename);
context->m_pinyin_table->store(tmpfilename);
g_free(tmpfilename);
//忽略
}
“context->m_pinyin_table->store(tmpfilename)”调用的是FacadeChewingTable2::store方法,在文件storage/facade_chewing_table2.h:
class FacadeChewingTable2{
private:
//忽略
ChewingLargeTable2 * m_user_chewing_table;
//忽略
bool store(const char * new_user_filename) {
if (NULL == m_user_chewing_table)
return false;
return m_user_chewing_table->store_db(new_user_filename);
}
//忽略
}
属性m_user_chewing_table的ChewingLargeTable2是在storage/chewing_large_table2.h中定义的:
#ifdef HAVE_BERKELEY_DB
#include "chewing_large_table2_bdb.h"
#endif
#ifdef HAVE_KYOTO_CABINET
#include "chewing_large_table2_kyotodb.h"
#endif
因为确定是Berkeley DB,那么直接看storage/chewing_large_table2_bdb.cpp中的store_db方法即可:
bool ChewingLargeTable2::store_db(const char * new_filename) {
DB * tmp_db = NULL;
int ret = unlink(new_filename);
if (ret != 0 && errno != ENOENT)
return false;
ret = db_create(&tmp_db, NULL, 0);
assert(0 == ret);
if (NULL == tmp_db)
return false;
ret = tmp_db->open(tmp_db, NULL, new_filename, NULL,
DB_BTREE, DB_CREATE, 0600);
if (ret != 0)
return false;
if (!copy_bdb(m_db, tmp_db))
return false;
if (tmp_db != NULL) {
tmp_db->sync(m_db, 0);
tmp_db->close(tmp_db, 0);
}
return true;
}
从strace情况来看,应该是“tmp_db->open”出故障了,那“__db.”又是哪里来的呢?Oracle论坛里面有人问类似问题【2】,有人给了个答案:“Shared memory regions”【3】,但文档里面说的是DB_ENV,感觉和这个问题无关:
Shared memory regions:…… Any files created in the filesystem to back the regions are created in the environment home directory specified to the DB_ENV->open() call. These files are named __db.### (for example, __db.001, __db.002 and so on).
但无论如何,问题确定了,用户缓存目录“【用户home目录,比如/home/xxxxx】/.cache/ibus/libpinyin”下面意外存在了各种.tmp文件,然后阻塞了后续读写流程。
参考文档
【1】https://www.gnu.org/software/libc/manual/html_node/Open_002dtime-Flags.html
【2】https://forums.oracle.com/ords/apexds/post/what-is-db-file-7859
【3】https://docs.oracle.com/cd/E17275_01/html/programmer_reference/env_region.html
本页永久链接:https://www.orztip.com/?p=887&article_title=ibus-libpinyin-unresponsive