Skip to content

Conversation

@wangrong1069
Copy link
Contributor

@wangrong1069 wangrong1069 commented Nov 28, 2025

  • Adjust deepin-anything-daemon service unit to limit memory usage and prevent excessive restarts.
    • Reduced MemoryHigh from 4G to 2G and MemoryMax from 5G to 3G.
    • Added StartLimitIntervalSec and StartLimitBurst to control restart frequency.
  • Enhance error handling for filesystem operations in base_event_handler and file_index_manager.
    • Wrapped directory scanning in scan_directory with a try-catch block for std::filesystem::filesystem_error.
    • Added error code parameter to std::filesystem::remove_all calls to prevent crashes on non-existent directories or permission issues.
    • Ensured jobs_ are cleared after termination processing.

Summary by Sourcery

Improve daemon robustness by tightening systemd resource limits and hardening filesystem-related error handling in the daemon core.

Bug Fixes:

  • Prevent crashes during directory scanning by catching std::filesystem::filesystem_error and handling failures gracefully when iterating directories.
  • Avoid exceptions when removing volatile index directories by using std::filesystem::remove_all with an error_code parameter instead of throwing on failure.
  • Ensure pending jobs are fully cleared after termination processing to avoid leftover work items.

Enhancements:

  • Add logging for failed path handling and directory scan failures to aid in diagnosing filesystem issues.
  • Adjust deepin-anything-daemon systemd unit memory and restart policies to reduce resource usage and avoid excessive restart loops.

@sourcery-ai
Copy link

sourcery-ai bot commented Nov 28, 2025

Reviewer's Guide

This PR tightens systemd resource and restart limits for deepin-anything-daemon and hardens the daemon’s filesystem-related code paths to avoid crashes and leaks by improving error handling and cleanup behavior.

Sequence diagram for enhanced scan_directory error handling

sequenceDiagram
    participant beh as base_event_handler
    participant fs as filesystem
    participant handler as PathHandler
    participant log as spdlog

    beh->>fs: construct recursive_directory_iterator(dir_path, skip_permission_denied)
    loop for each entry
        beh->>fs: exists(entry.path, ec)
        fs-->>beh: exists result
        alt path in blacklist or not exists
            beh->>fs: iterator.disable_recursion_pending()
        else path allowed
            beh->>handler: handler(path)
            alt handler returns false
                beh->>log: error Failed to handle path
                beh-->>beh: return false
            else handler returns true
                alt stop_scan_directory_ is true
                    beh->>log: info Scanning interrupted
                    beh-->>beh: return true
                end
            end
        end
    end
    beh-->>log: info Scanning directory completed

    rect rgb(240,200,200)
        beh->>fs: recursive iteration may throw filesystem_error
        fs-->>beh: throw filesystem_error
        beh->>log: error Failed to scan directory with details
    end
Loading

Sequence diagram for file_index_manager index cleanup with error_code

sequenceDiagram
    participant fim as file_index_manager
    participant fs as filesystem
    participant log as spdlog
    participant writer as IndexWriter
    participant reader as IndexReader

    rect rgb(230,230,255)
        fim->>log: warn The index is corrupted or invalid
        opt writer_ not null
            fim->>writer: close()
        end
        opt reader_ not null
            fim->>reader: close()
        end
        fim->>fs: remove_all(volatile_index_directory_, ec)
        fs-->>fim: error_code ec (no exception)
    end

    rect rgb(230,255,230)
        fim->>fs: exists(volatile_index_directory_ + /invalid_index, ec)
        alt invalid_index exists
            fim->>log: warn The index is invalid, remove it
            fim->>fs: remove_all(volatile_index_directory_, ec)
        else
            fim->>log: warn Index corrupted or version mismatch
            fim->>fs: remove_all(volatile_index_directory_, ec)
        end
    end
Loading

Class diagram for updated base_event_handler and file_index_manager

classDiagram
    class base_event_handler {
        - thread_pool pool_
        - vector~Job~ jobs_
        - bool stop_scan_directory_
        - config_ptr config_
        + void terminate_processing()
        + bool scan_directory(string dir_path, function<bool(string)> handler)
    }

    class file_index_manager {
        - IndexWriterPtr writer_
        - IndexReaderPtr reader_
        - string volatile_index_directory_
        + file_index_manager(string persistent_index_dir, string volatile_index_dir)
        + void check_index_version()
    }

    class config {
        + vector~string~ blacklist_paths
    }

    class spdlog {
        + static void info(string message, string arg1)
        + static void info(string message)
        + static void warn(string message, string arg1)
        + static void error(string message, string arg1)
        + static void error(string message, string arg1, string arg2, string arg3, int arg4)
    }

    class filesystem {
        + static bool exists(path p, error_code ec)
        + static uintmax_t remove_all(path p, error_code ec)
        + class filesystem_error
    }

    base_event_handler --> config : uses
    base_event_handler ..> spdlog : logging
    base_event_handler ..> filesystem : recursive_directory_iterator
    file_index_manager ..> filesystem : exists, remove_all
    file_index_manager ..> spdlog : logging
Loading

File-Level Changes

Change Details Files
Ensure all queued jobs are released after termination processing completes.
  • After draining jobs_ via eat_job, explicitly clear the jobs_ container to release any remaining resources and avoid stale jobs lingering across lifecycles.
  • Keep existing behavior of waiting for the thread pool and consuming all jobs, only adding the explicit container clear step.
src/daemon/src/core/base_event_handler.cpp
Harden directory scanning against filesystem errors and better log handler failures.
  • Wrap recursive directory iteration in scan_directory in a try-catch for std::filesystem::filesystem_error to prevent crashes when encountering problematic paths.
  • On handler(path) failure, log an error with the failing path before aborting the scan, instead of silently returning false.
  • Preserve existing blacklist checks, existence checks, and early-exit behavior when stop_scan_directory_ is set, but move them inside the protected try block.
  • Log an error with filesystem exception details (what(), path1, path2, and error code) when directory iteration throws.
src/daemon/src/core/base_event_handler.cpp
Avoid crashes when deleting volatile index directories by using non-throwing filesystem removal.
  • Change std::filesystem::remove_all calls for volatile_index_directory_ to the overload accepting a std::error_code so failures (e.g., non-existent directory, permission issues) are reported but do not throw.
  • Introduce and reuse a std::error_code variable in file_index_manager contexts where index directories may be removed due to corruption, invalid markers, or version mismatch.
src/daemon/src/core/file_index_manager.cpp
Tighten systemd memory limits and restart throttling for the daemon service.
  • Lower MemoryHigh from 4G to 2G and MemoryMax from 5G to 3G to constrain the daemon’s memory usage.
  • Add StartLimitIntervalSec and StartLimitBurst to cap how often systemd will restart the daemon in a given time window, reducing restart storms.
src/daemon/deepin-anything-daemon.service

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • In scan_directory, catching std::filesystem::filesystem_error and then falling through to log "Scanning directory ... completed" and returning true will mask real failures; consider returning false (or otherwise signaling failure) from the catch block and adjusting the completion log message accordingly.
  • Now that std::filesystem::remove_all calls use an std::error_code, the error is effectively ignored; if a failure to remove the index directory is meaningful in these code paths, consider logging ec (e.g., ec.value()/ec.message()) when it indicates an error.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `scan_directory`, catching `std::filesystem::filesystem_error` and then falling through to log "Scanning directory ... completed" and returning `true` will mask real failures; consider returning `false` (or otherwise signaling failure) from the catch block and adjusting the completion log message accordingly.
- Now that `std::filesystem::remove_all` calls use an `std::error_code`, the error is effectively ignored; if a failure to remove the index directory is meaningful in these code paths, consider logging `ec` (e.g., `ec.value()`/`ec.message()`) when it indicates an error.

## Individual Comments

### Comment 1
<location> `src/daemon/src/core/base_event_handler.cpp:364-368` </location>
<code_context>
-            continue;
-        }

-        if (!handler(path)) {
-            return false;
-        }
+    try {
+        // By default, symlinks are not followed
+        std::filesystem::recursive_directory_iterator dirpos{ dir_path, std::filesystem::directory_options::skip_permission_denied };
+        for (auto it = begin(dirpos); it != end(dirpos); ++it) {
+            path = std::move(it->path().string());
+            if (is_path_in_blacklist(path, config_->blacklist_paths) ||
+                !std::filesystem::exists(it->path(), ec)) {
+                    it.disable_recursion_pending();
+                continue;
+            }

-        if (stop_scan_directory_) {
-            spdlog::info("Scanning interrupted");
-            return true;
+            if (!handler(path)) {
+                spdlog::error("Failed to handle path: {}", path);
+                return false;
+            }
</code_context>

<issue_to_address>
**issue (bug_risk):** Handler returning false is now treated as an error, which may change existing semantics.

Previously, `handler(path)` returning `false` just stopped the scan without logging an error. Callers may legitimately use `false` for a normal early stop (e.g., “found what I needed”), so this change could both alter behavior and flood logs with errors. Consider either keeping `false` as a non-error early exit (no error log), clearly documenting that `false` now means failure, or introducing a distinct way to signal “stop” vs “error” (e.g., a richer return type).
</issue_to_address>

### Comment 2
<location> `src/daemon/src/core/base_event_handler.cpp:377-380` </location>
<code_context>
+                return true;
+            }
         }
+    } catch (std::filesystem::filesystem_error const& e) {
+        spdlog::error("Failed to scan directory: {}, {}, {}, {}",
+            e.what(), e.path1().string(), e.path2().string(), e.code().value());
     }

</code_context>

<issue_to_address>
**suggestion:** Filesystem error logging omits the human-readable error message from `std::error_code`.

Right now the log only prints `e.code().value()`, which is just a numeric code. Please also log `e.code().message()` so operators can see the OS-level error text (e.g., "permission denied"). For example:

```cpp
spdlog::error(
    "Failed to scan directory: {}, {}, {}, {} ({})",
    e.what(),
    e.path1().string(),
    e.path2().string(),
    e.code().value(),
    e.code().message());
```

```suggestion
    } catch (std::filesystem::filesystem_error const& e) {
        spdlog::error(
            "Failed to scan directory: {}, {}, {}, {} ({})",
            e.what(),
            e.path1().string(),
            e.path2().string(),
            e.code().value(),
            e.code().message());
    }
```
</issue_to_address>

### Comment 3
<location> `src/daemon/src/core/base_event_handler.cpp:382` </location>
<code_context>
+            e.what(), e.path1().string(), e.path2().string(), e.code().value());
     }

     spdlog::info("Scanning directory {} completed", dir_path);
</code_context>

<issue_to_address>
**issue (bug_risk):** The "completed" log may be misleading when the scan exits via exception.

Because the `catch` for `std::filesystem::filesystem_error` logs the error and then falls through, we still emit `"Scanning directory {} completed"` even when the scan failed. Please either exit early from the `catch` or gate the final log on a success flag so it only indicates completion on success.
</issue_to_address>

### Comment 4
<location> `src/daemon/src/core/file_index_manager.cpp:187-190` </location>
<code_context>

     std::error_code ec;
     std::string path;
-    // By default, symlinks are not followed
</code_context>

<issue_to_address>
**issue (bug_risk):** Swallowing errors from `remove_all` can leave a corrupted index without any signal.

Switching from the throwing `remove_all` to the `std::error_code` overload makes failures silent. Right now `ec` is ignored, so callers proceed as if the directory was removed even when it wasn’t, which can leave a bad index in place and cause confusing follow‑on behavior.

At minimum, check and log failures, e.g.:

```cpp
std::filesystem::remove_all(volatile_index_directory_, ec);
if (ec) {
    spdlog::error("Failed to remove corrupted index {}: {} ({})",
                  volatile_index_directory_, ec.message(), ec.value());
}
```

The same pattern should be applied to the other `remove_all(..., ec)` calls in `check_index_version()` so cleanup issues are visible during diagnosis.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +187 to +190
std::error_code ec;
if (writer_) writer_->close();
if (reader_) reader_->close();
std::filesystem::remove_all(volatile_index_directory_);
std::filesystem::remove_all(volatile_index_directory_, ec);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Swallowing errors from remove_all can leave a corrupted index without any signal.

Switching from the throwing remove_all to the std::error_code overload makes failures silent. Right now ec is ignored, so callers proceed as if the directory was removed even when it wasn’t, which can leave a bad index in place and cause confusing follow‑on behavior.

At minimum, check and log failures, e.g.:

std::filesystem::remove_all(volatile_index_directory_, ec);
if (ec) {
    spdlog::error("Failed to remove corrupted index {}: {} ({})",
                  volatile_index_directory_, ec.message(), ec.value());
}

The same pattern should be applied to the other remove_all(..., ec) calls in check_index_version() so cleanup issues are visible during diagnosis.

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: lzwind, wangrong1069

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

- Adjust deepin-anything-daemon service unit to limit memory usage and prevent excessive restarts.
    - Reduced MemoryHigh from 4G to 2G and MemoryMax from 5G to 3G.
    - Added StartLimitIntervalSec and StartLimitBurst to control restart frequency.
- Enhance error handling for filesystem operations in base_event_handler and file_index_manager.
    - Wrapped directory scanning in scan_directory with a try-catch block for std::filesystem::filesystem_error.
    - Added error code parameter to std::filesystem::remove_all calls to prevent crashes on non-existent directories or permission issues.
    - Ensured jobs_ are cleared after termination processing.
@github-actions
Copy link

TAG Bot

TAG: 7.0.33
EXISTED: no
DISTRIBUTION: unstable

@deepin-ci-robot
Copy link

deepin pr auto review

我来对这段代码进行详细的审查分析:

  1. 系统服务配置修改 (deepin-anything-daemon.service)
    优点:
  • 降低了内存限制(从4G/5G降低到2G/3G),更合理地使用系统资源
  • 添加了启动频率限制(StartLimitIntervalSec和StartLimitBurst),防止服务频繁重启
  • 配置项都有清晰的注释说明

建议:

  • 可以考虑添加OOMScoreAdjust参数,在系统内存不足时优先被终止
  1. 事件处理器改进 (base_event_handler.cpp)
    优点:
  • 在terminate_processing中添加了jobs_.clear(),确保资源被正确释放
  • 改进了目录扫描的错误处理,使用try-catch捕获文件系统异常
  • 添加了更详细的错误日志记录

建议:

  • 可以考虑在catch块中添加对特定异常类型的处理,比如权限拒绝、磁盘空间不足等
  • path变量的重复使用可能会导致性能问题,建议在循环内部声明
  1. 索引管理器改进 (file_index_manager.cpp)
    优点:
  • 在删除文件系统目录时添加了error_code参数,避免异常抛出
  • 保持了原有的错误处理逻辑,同时提高了安全性

建议:

  • 可以考虑添加对remove_all操作结果的检查
  • 在删除索引前可以添加备份机制,以防数据丢失
  1. 版本更新记录 (changelog)
    优点:
  • 版本号更新规范
  • 变更描述清晰

建议:

  • 可以添加更详细的变更说明,比如具体的性能改进指标

整体安全性评估:

  1. 文件系统操作都添加了错误处理
  2. 内存使用限制更加合理
  3. 服务重启机制得到改进
  4. 异常处理更加完善

性能优化建议:

  1. 考虑使用移动语义减少不必要的拷贝
  2. 在文件系统操作时可以考虑使用缓存
  3. 可以添加性能监控指标,帮助后续优化

代码质量建议:

  1. 统一错误处理风格
  2. 添加更多的单元测试覆盖
  3. 考虑添加代码注释说明关键逻辑
  4. 可以考虑使用RAII管理资源

这些修改整体上提高了系统的稳定性和资源管理效率,是一个良好的改进。建议在后续版本中持续监控这些改进的效果,并根据实际使用情况进行调整。

@wangrong1069
Copy link
Contributor Author

/merge

@deepin-bot deepin-bot bot merged commit 5c6e2fd into linuxdeepin:develop/snipe Nov 28, 2025
18 checks passed
@wangrong1069 wangrong1069 deleted the pr1128 branch November 28, 2025 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants