Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

[Bug]: `couch_bt_engine:init/2` can crash with `noproc` when `couch_file` idle-closes before `set_db_pid`

已关闭
#6,178 3 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

@nickva 已经在做这个了。

开始于 2026年10月28日。

  • #6184 来自 @nickva —— 未关闭

评估

难度
4/5
预计耗时
3-5 天
新手友好度
55/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
erlang
领域
backend, databases

调研方向

Read couch_bt_engine.erl around line 893 and trace the open-to-set_db_pid sequence alongside couch_file’s idle-close checks and the ioq wait described here. The reproduction blocks ioq and waits past the 60-second idle timer; use it to confirm the failure and verify the engine keeps the file alive until it claims it, including when initialization or compaction I/O is delayed.

由索引模型根据 Issue 内容生成。

描述

bug needs-triage
Version

No response

Describe the problem you're encountering

After couch_file:open/2, the file process is linked to the caller, but nothing holds a lasting monitor on it until init_state/4 calls:

couch_file:set_db_pid(Fd, self())

at couch_bt_engine.erl:893.

couch_file closes itself when it looks idle. init/1 arms:

erlang:send_after(?INITIAL_WAIT, self(), maybe_close)

where ?INITIAL_WAIT is 60 seconds.

When the message arrives, is_idle/1 checks monitored_by. If the only monitor is couch_stats_process_tracker, the process stops with reason normal. If it is busy, it re-checks every 10 seconds using ?MONITOR_CHECK.

So, if the time between open and set_db_pid exceeds 60 seconds and one of those checks lands while nothing monitors the file, couch_file stops.

Callers hold a monitor only for the duration of each direct gen_server:call. A request waiting in the ioq queue monitors the ioq server, not the file, so a backed-up ioq is enough to expose the gap. Compaction I/O is not bypassed by default.

Because the exit reason is normal, the link does not take the caller down. The next direct call fails with noproc.

Expected Behaviour

A file opened by couch_bt_engine:init/2 stays open until the engine has claimed it, however long the init takes. Opening a database or finishing a compaction should not fail because IO was slow.

Steps to Reproduce
  1. Start a dev node: ./dev/run -n 1 --admin=adm:pass
  2. Attach a shell: ./dev/remsh
  3. Paste:
%% Create a db file with a header.
Path = filename:join(config:get("couchdb", "database_dir"), "idle_close_repro.couch"),
file:delete(Path),
{ok, Fd0} = couch_file:open(Path, [create]),
ok = couch_file:write_header(Fd0, couch_bt_engine_header:new(), [sync]),
ok = couch_file:close(Fd0),

%% Block ioq.
Ioq = whereis(ioq),
true = erlang:suspend_process(Ioq),

%% Open the db. read_header/1 waits on ioq; the 60s timer starts.
{Pid, Ref} = spawn_monitor(fun() ->
    ioq:set_io_priority({db_compact, <<"repro">>}),
    exit({result, catch couch_bt_engine:init(Path, [])})
end),
timer:sleep(1000),

%% Freeze init and let ioq reply. Now nothing monitors the file.
true = erlang:suspend_process(Pid),
true = erlang:resume_process(Ioq),

%% couch_file idle-closes after 60s.
timer:sleep(61000),

%% Resume init. sync/1 hits the dead file.
true = erlang:resume_process(Pid),
receive {'DOWN', Ref, process, Pid, Reason} -> Reason end.
  1. The result is:
{result,{'EXIT',{noproc,{gen_server,call,
                                  [<0.12353.0>,sync,infinity]}}}}
Your Environment

No response

Additional Context

No response

主要语言
Erlang
星标
7k
派生
1.1k
平均合并
11 小时 29 分钟
30 天内合并 PR
37

环境准备

在 Codespaces 中打开

在浏览器里用你自己的 GitHub 账号启动这个项目的开发容器。

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

apache/couchdb 的其他 Issue

查看 apache/couchdb 的全部 Issue

相似的 Issue

更多 Backend & API Design Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。