fix: detect abnormal exit via sentinel for filename index - #264
Merged
Johnson-zs merged 1 commit intoSep 29, 2026
Merged
Johnson-zs merged 1 commit into
Johnson-zs merged 1 commit into
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: Johnson-zs The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Reviewer's GuideFileNameIndexDBus now uses a running sentinel file to detect crashes, SIGKILL, or OOM while idle; a leftover sentinel marks the index Dirty and routes startup through the existing full-update recovery path, while normal cleanup removes it. TextIndex and OcrIndex are unchanged. Sequence diagram for filename index abnormal-exit recoverysequenceDiagram
participant Service as FileNameIndexDBus
participant FS as IndexDirectory
participant State as StateStore
participant Recovery as ExistingRecoveryPath
Service->>FS: QFile::exists(sentinelPath)
alt Sentinel remains from previous run
Service->>State: setIndexState(Dirty)
end
Service->>FS: QDir::mkpath(indexDir)
Service->>FS: QFile::open(WriteOnly)
Service->>State: getIndexState()
State-->>Service: Dirty
Service->>Recovery: handleSilentStart()
Recovery->>Recovery: Update()
alt Normal cleanup
Service->>FS: QFile::remove(sentinelPath)
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="src/index/dbus/filenameindexdbus.cpp" line_range="25-28" />
<code_context>
+// when the service starts, the previous run was killed without cleanup.
+inline constexpr char kSentinelFileName[] = ".filename_index_running";
+
+QString sentinelFilePath(const QString &indexDir)
+{
+ return indexDir + QLatin1Char('/') + QLatin1String(kSentinelFileName);
+}
+
QStringList defaultPathsToProcess()
</code_context>
<issue_to_address>
**issue (bug_risk):** When `indexDir` is empty, `sentinelFilePath()` returns `/.filename_index_running`, which is non-empty. Startup therefore probes the filesystem root for the sentinel and cleanup attempts to remove that root-level path instead of skipping sentinel handling.
**Triggers:** When the filename index directory provider returns an empty path.
**Suggested fix:** Return an empty path from `sentinelFilePath()` when `indexDir` is empty, or guard the existence check with `!indexDir.isEmpty()` as is done for creation.
```suggestion
QString sentinelFilePath(const QString &indexDir)
{
return indexDir.isEmpty() ? QString() : indexDir + QLatin1Char('/') + QLatin1String(kSentinelFileName);
}
```
</issue_to_address>
### Comment 2
<location path="src/index/dbus/filenameindexdbus.cpp" line_range="69-74" />
<code_context>
+ runtime->stateStore().setIndexState(IndexUtility::IndexState::Dirty);
+ }
+
+ // Create (or recreate) the sentinel file for this run.
+ if (!indexDir.isEmpty()) {
+ QDir().mkpath(indexDir);
+ QFile sentinel(sentinelPath);
+ if (sentinel.open(QIODevice::WriteOnly)) {
+ sentinel.close();
+ } else {
+ qWarning() << "FileNameIndexDBus: Failed to create sentinel file:" << sentinelPath;
</code_context>
<issue_to_address>
**issue (bug_risk):** Two filename-index service instances sharing the same index directory overwrite and remove one another's sentinel: the later startup truncates the shared file, and either instance's normal cleanup removes it while the other is still running. If the remaining instance is then killed, its abnormal exit leaves no sentinel and recovery is skipped.
**Triggers:** When a second service process starts before the first process has exited, including after DBus service registration fails but object construction continues.
**Suggested fix:** Use an ownership-specific/atomic lease sentinel, or refuse to construct the service when DBus name registration fails; cleanup must only remove a sentinel owned by the current process.
</issue_to_address>
Johnson-zs
force-pushed
the
develop/snipe-20260923
branch
from
September 29, 2026 11:20
9cb34f6 to
df79576
Compare
1. Root cause: when the index service is killed by SIGKILL, crash, or OOM while in Clean state with no running tasks, cleanup() is never called and the state remains Clean — on restart no recovery is triggered, silently losing all file changes during the downtime 2. Fix: create a sentinel file at startup in the index directory and remove it during normal cleanup(); if the sentinel persists across a restart, the previous exit was abnormal, so mark state Dirty to trigger a compensating full Update via the existing recovery path 3. Harden sentinelFilePath() to return empty when indexDir is empty, preventing operations on the filesystem root when indexDir is unset 4. Abort service construction when DBus registerService fails, preventing multi-instance scenarios that could corrupt the sentinel file; unregister already-registered services on partial failure to avoid blocking legitimate instances 5. Check registerIndexServices() return value in main() and exit on failure instead of continuing with unregistered DBus services 6. Use open() with O_NOFOLLOW to create the sentinel file, preventing symlink-following that could truncate an arbitrary file if an attacker pre-placed a symlink in the index directory 7. Guard cleanup() with QFile::exists() before QFile::remove() to avoid false warnings when the sentinel file is already absent 8. Impact: FileNameIndexDBus and serviceentry are affected; TextIndex and OcrIndex are unchanged per the filename-index completeness need Influence: 1. Test normal service restart — sentinel file should be removed and no false Dirty state on next startup 2. Test SIGKILL during Clean idle state — sentinel persists, restart triggers full Update covering all missed file changes 3. Verify no regression on existing Dirty state recovery path 4. Test service startup with empty indexDir — no root-level file ops 5. Test second instance startup — should abort, not corrupt sentinel 6. Test DBus unavailable — main() should exit, not run unregistered 7. Test symlink in indexDir — sentinel creation must not follow it fix: 通过哨兵文件检测文件名索引服务异常退出 1. 根因:索引服务在 Clean 空闲状态下被 SIGKILL、崩溃或 OOM 杀死时, cleanup() 未被调用,状态保持 Clean,重启后不触发恢复,退出期间的 文件变更静默丢失 2. 方案:启动时在索引目录创建哨兵文件,正常退出时删除;若重启时哨兵 文件仍在,说明上次异常退出,标记 Dirty 状态触发已有恢复路径的 全量 Update 补偿丢失的文件变更 3. 加固 sentinelFilePath() 在 indexDir 为空时返回空字符串,避免 indexDir 未设置时操作文件系统根目录 4. DBus registerService 失败时中止服务构造,防止多实例场景下 哨兵文件被互相覆盖或删除;部分注册失败时注销已注册的服务, 避免阻塞合法实例 5. main() 检查 registerIndexServices() 返回值,失败时退出,不再 在 DBus 服务未注册的情况下继续运行 6. 使用 open() 配合 O_NOFOLLOW 标志创建哨兵文件,防止攻击者在 索引目录预置符号链接导致任意文件被截断 7. cleanup() 删除哨兵文件前先检查 QFile::exists(),避免文件 不存在时误报警告 8. 影响:修改 FileNameIndexDBus 和 serviceentry,TextIndex 和 OcrIndex 不变,符合仅文件名索引需要完整性保证的需求 Influence: 1. 测试正常重启场景——哨兵文件应被删除,下次启动不误触发 Dirty 2. 测试 Clean 空闲状态下 SIGKILL——哨兵文件残留,重启触发全量 Update 3. 验证已有 Dirty 状态恢复路径无回归 4. 测试 indexDir 为空时启动——不应操作根目录文件 5. 测试第二个实例启动——应中止退出,不破坏哨兵文件 6. 测试 DBus 不可用时启动——main() 应退出,不继续运行 7. 测试索引目录存在符号链接——哨兵文件创建不应跟随符号链接
Johnson-zs
force-pushed
the
develop/snipe-20260923
branch
from
September 29, 2026 11:38
df79576 to
87fc1b3
Compare
Johnson-zs
merged commit Sep 29, 2026
6595d66
into
linuxdeepin:develop/snipe-20260923
17 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix: detect abnormal exit via sentinel for filename index
or OOM while in Clean state with no running tasks, cleanup() is
never called and the state remains Clean — on restart no recovery
is triggered, silently losing all file changes during the downtime
remove it during normal cleanup(); if the sentinel persists across
a restart, the previous exit was abnormal, so mark state Dirty to
trigger a compensating full Update via the existing recovery path
are unchanged per the requirement that only filename index needs
full completeness guarantees
Influence:
no false Dirty state on next startup
triggers full Update covering all missed file changes
fix: 通过哨兵文件检测文件名索引服务异常退出
cleanup() 未被调用,状态保持 Clean,重启后不触发恢复,退出期间的
文件变更静默丢失
文件仍在,说明上次异常退出,标记 Dirty 状态触发已有恢复路径的
全量 Update 补偿丢失的文件变更
仅文件名索引需要完整性保证的需求
Influence:
Summary by Sourcery
Detect abnormal filename-index shutdowns and trigger full recovery while making D-Bus service registration failures explicit and safe.
New Features:
Bug Fixes:
Enhancements:
Tests: