Skip to content

fix: Add classes to clean-up Spider's internal Data, Driver, and Job objects from the database when clients destroy the corresponding client objects (fixes #135). - #136

Merged
sitaowang1998 merged 27 commits into
y-scope:mainfrom
sitaowang1998:driver_gc
May 29, 2025

Conversation

@sitaowang1998

@sitaowang1998 sitaowang1998 commented May 11, 2025

Copy link
Copy Markdown
Collaborator

Description

Problem

In the current implementation, Spider clients do not clean up Data, Job, or Driver objects from storage when the corresponding client-side objects are destructed. As a result, in long-running clients, stale data and jobs persist in storage because their associated drivers still hold valid references, preventing automatic cleanup. This issue is tracked in #135.

Solution

This PR addresses the problem by introducing specialized cleaner classes: DataCleaner, JobCleaner, and DriverCleaner. These classes ensure that associated Data, Job, and Driver entries are properly removed from storage when the client-side objects are destructed.

Exception Safety

To avoid unintended cleanup during exception handling, the destructors of the cleaner classes use std::uncaught_exceptions to determine if the program is currently unwinding the stack due to an exception. If so, the cleanup is skipped.

This ensures that cleanup is performed only during normal object destruction, and not during exception handling, preserving exception safety and system stability.

Move Safety with std::unique_ptr

To prevent cleanup from being executed on moved-from objects (which could lead to double-deletion), the cleaner objects are owned via std::unique_ptr. This ensures:

  • Ownership is clear and exclusive.
  • When an object is moved, the original unique_ptr becomes nullptr, so the cleaner's desctructor is not called.
  • Cleanup logic is only executed by the final, owning instance of the cleaner.

By relying on std::unique_ptr, we ensure that the cleaner's destructor is only called once per resource, and only by the last owner. This avoids accidental cleanup of moved objects.

Checklist

  • The PR satisfies the contribution guidelines.
  • This is a breaking change and that has been indicated in the PR title, OR this isn't a
    breaking change.
  • Necessary docs have been updated, OR no docs need to be updated.

Validation performed

  • GitHub workflows pass.
  • Unit tests pass.
  • Integration tests pass.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Introduced automatic cleanup for drivers, jobs, and data, ensuring resources are properly removed when no longer needed.
    • Added a unified context mechanism to simplify and standardize how source information is managed for drivers, jobs, and data.
  • Bug Fixes

    • Improved test reliability by ensuring drivers and schedulers are cleaned up after tests, preventing resource leaks.
  • Chores

    • Enhanced internal resource management for safer and more predictable cleanup during shutdown or object destruction.
    • Added explicit cleanup of scheduler drivers on normal program exit to maintain storage consistency.
    • Updated storage interfaces and implementations to mark cleanup-related methods as noexcept for robustness.

@sitaowang1998
sitaowang1998 requested a review from a team as a code owner May 11, 2025 00:44
@coderabbitai

coderabbitai Bot commented May 11, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This change set introduces new "Cleaner" classes—DataCleaner, DriverCleaner, and JobCleaner—to manage resource cleanup for data, driver, and job entities. A new Context abstraction is added to unify source identification. The client and core logic are refactored to use Context and these cleaner classes. Storage interfaces and implementations are extended to support driver removal, and test cases and scheduler logic are updated for explicit resource cleanup.

Changes

File(s) Change Summary
src/spider/CMakeLists.txt Added new source and header files for Context, DataCleaner, DriverCleaner, and JobCleaner to the build configuration.
src/spider/core/Context.hpp Introduced Context class and associated Source enum to encapsulate execution context (Driver or Task) and unique ID.
src/spider/core/DataCleaner.cpp, src/spider/core/DataCleaner.hpp Added DataCleaner class for data reference cleanup, with destructor logic to remove data references based on context.
src/spider/core/DriverCleaner.cpp, src/spider/core/DriverCleaner.hpp Added DriverCleaner class for driver metadata cleanup, with destructor logic to remove driver records safely.
src/spider/core/JobCleaner.cpp, src/spider/core/JobCleaner.hpp Added JobCleaner class for job metadata cleanup, with destructor logic to remove job records safely.
src/spider/client/Data.hpp Refactored to use core::Context instead of separate source ID and enums; added DataCleaner member for cleanup.
src/spider/client/Driver.cpp, src/spider/client/Driver.hpp Integrated DriverCleaner for driver cleanup; updated data and job builder logic to use core::Context.
src/spider/client/Job.hpp Refactored to use core::Context for job source and ID; added JobCleaner member for cleanup.
src/spider/client/TaskContext.hpp Updated to construct data and job builders using core::Context instead of separate IDs/enums.
src/spider/core/DataImpl.hpp Updated create_data to accept and propagate Context parameter.
src/spider/scheduler/scheduler.cpp Added explicit call to remove driver from metadata storage before program exit.
src/spider/storage/MetadataStorage.hpp Added pure virtual method remove_driver to the MetadataStorage interface; marked remove_job as noexcept.
src/spider/storage/mysql/MySqlStorage.cpp, src/spider/storage/mysql/MySqlStorage.hpp Implemented remove_driver method in MySQL metadata storage class; marked several methods noexcept.
src/spider/worker/FunctionManager.hpp Passed explicit Context (with source type and task ID) when creating DataImpl in function invocation logic.
tests/storage/test-MetadataStorage.cpp Added explicit driver/scheduler removal in test cases for resource cleanup.
tests/scheduler/test-SchedulerPolicy.cpp Added cleanup calls to remove drivers and data after job removal in tests.
tests/scheduler/test-SchedulerServer.cpp Added explicit driver removal cleanup after server shutdown.
tests/storage/test-DataStorage.cpp Added cleanup steps to remove drivers and data after tests.
tests/worker/test-FunctionManager.cpp Added driver removal cleanup after test completion.
tests/worker/test-TaskExecutor.cpp Added driver removal cleanup after test completion.
src/spider/storage/DataStorage.hpp Added noexcept specifier to remove_task_reference and remove_driver_reference methods.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client/Driver/TaskContext
    participant Core as core::{Context, DataCleaner, DriverCleaner, JobCleaner}
    participant Storage as MetadataStorage/DataStorage
    participant Factory as StorageFactory
    participant Conn as StorageConnection

    Note over Client,Core: Resource Creation (Data, Driver, Job)
    Client->>Core: Create Context (Source, UUID)
    Client->>Core: Create Cleaner (DataCleaner/DriverCleaner/JobCleaner) with Context, Storage, Factory, Conn

    Note over Core: On object destruction
    Core->>Core: Check for exception unwinding
    alt Not unwinding
        Core->>Conn: Use existing or acquire from Factory
        alt DataCleaner
            Core->>Storage: Remove driver/task reference to data
        else DriverCleaner
            Core->>Storage: Remove driver metadata
        else JobCleaner
            Core->>Storage: Remove job metadata
        end
    else Unwinding
        Core-->>Core: Skip cleanup
    end
Loading
sequenceDiagram
    participant Client as Client
    participant Core as core::Context
    participant Storage as MetadataStorage

    Client->>Core: Create Context (Source, UUID)
    Client->>Storage: Remove driver/job/scheduler using Context info
Loading

Possibly related PRs

  • build: Split core into spearate library #15: The main PR adds new source and header files to the spider_core library in src/spider/CMakeLists.txt, while the retrieved PR restructures the build by initially splitting core components into a separate library and adjusting linking accordingly; thus, both PRs modify the src/spider/CMakeLists.txt to manage the spider_core library sources but do not overlap on the same files or functions beyond build configuration.

  • fix(storage): Always create a reference when getting data from storage (fixes #132). #119: The main PR introduces new cleaner classes and a unified Context abstraction for source identification and resource cleanup, while the retrieved PR adds source and source_id parameters to Job and Driver classes and modifies data retrieval to register references; both PRs modify constructors and cleanup logic for these classes, showing a strong code-level relationship.

Possibly related issues

Suggested reviewers

  • davidlion

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8838d38 and 0fb0506.

📒 Files selected for processing (6)
  • src/spider/core/DataCleaner.cpp (1 hunks)
  • src/spider/core/DataCleaner.hpp (1 hunks)
  • src/spider/core/DriverCleaner.cpp (1 hunks)
  • src/spider/core/DriverCleaner.hpp (1 hunks)
  • src/spider/core/JobCleaner.cpp (1 hunks)
  • src/spider/core/JobCleaner.hpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/spider/core/DataCleaner.cpp
  • src/spider/core/DataCleaner.hpp
  • src/spider/core/DriverCleaner.hpp
  • src/spider/core/DriverCleaner.cpp
  • src/spider/core/JobCleaner.hpp
  • src/spider/core/JobCleaner.cpp
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: non-storage-unit-tests (ubuntu-24.04)
  • GitHub Check: non-storage-unit-tests (ubuntu-22.04)
  • GitHub Check: lint
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🔭 Outside diff range comments (1)
src/spider/client/Data.hpp (1)

116-147: ⚠️ Potential issue

User-supplied cleanup function is collected but never wired – cleanup silently lost

Builder::set_cleanup_func stores m_cleanup_func, yet build() never transfers it to the newly created core::Data or DataCleaner. As a result, the caller’s cleanup logic is never executed, defeating the purpose of the API.

 msgpack::sbuffer buffer;
 msgpack::pack(buffer, t);
 auto data = std::make_unique<core::Data>(std::string{buffer.data(), buffer.size()});
 data->set_locality(m_nodes);
 data->set_hard_locality(m_hard_locality);
+if (m_cleanup_func) {
+    data->set_cleanup_func(m_cleanup_func);   // <-- preserve user intent
+}

If core::Data no longer supports arbitrary cleanup, deprecate set_cleanup_func completely to avoid a misleading interface.

Either wire the function as above or remove the builder method; otherwise clients will assume their resources are freed while they are not.

🧹 Nitpick comments (8)
src/spider/scheduler/scheduler.cpp (1)

276-278: Consider adding cleanup to error paths.

While the current implementation handles cleanup on normal termination, consider also adding similar cleanup calls in error paths (e.g., in the catch blocks or before early returns due to errors) to ensure consistent cleanup regardless of how the program exits.

src/spider/core/DriverCleaner.cpp (1)

15-45: Consider deduplicating the three almost-identical Cleaner classes

DataCleaner, JobCleaner, and DriverCleaner share ~90 % of their code. A small CRTP/base-class abstraction (e.g., BaseCleaner) parameterised with the removal lambda would eliminate duplication, reduce maintenance overhead, and ensure bug-fixes (like the two above) propagate automatically.

src/spider/core/DriverCleaner.hpp (1)

48-50: Minor: comment in include-guard footer is inconsistent

The opening guard is SPIDER_CORE_DRIVERCLEANER_HPP, but the footer says // DRIVERCLEANER_HPP.
Aligning them improves readability:

-#endif  // DRIVERCLEANER_HPP
+#endif  // SPIDER_CORE_DRIVERCLEANER_HPP
src/spider/core/JobCleaner.hpp (1)

48-50: Synchronise include-guard footer comment

-#endif
+#endif  // SPIDER_CORE_JOB_CLEANER_HPP
src/spider/client/Job.hpp (2)

263-288: Consider extracting repeated context–based data-fetch logic into a helper

The conditional branches that decide between get_driver_data vs get_task_data (lines 263-288 and again at 339-364) are identical. Duplicating this block:

if (m_context.get_source() == core::Context::Source::Driver) {
    err = m_data_storage->get_driver_data(conn, m_context.get_id(), data_id, &data);
} else {
    err = m_data_storage->get_task_data(conn, m_context.get_id(), data_id, &data);
}

means any future change (e.g., adding a new Source enum) must be done in two places and increases cognitive load.

A tiny, private helper keeps the intent clear and shrinks the hot path:

+auto fetch_data(core::StorageConnection& conn,
+                boost::uuids::uuid const& data_id,
+                core::Data* out) -> core::StorageErr {
+    if (m_context.get_source() == core::Context::Source::Driver) {
+        return m_data_storage->get_driver_data(conn, m_context.get_id(), data_id, out);
+    }
+    return m_data_storage->get_task_data(conn, m_context.get_id(), data_id, out);
+}

...
- if (m_context.get_source() == core::Context::Source::Driver) {
-     err = m_data_storage->get_driver_data(conn, m_context.get_id(), data_id, &data);
- } else {
-     err = m_data_storage->get_task_data(conn, m_context.get_id(), data_id, &data);
- }
+ err = fetch_data(conn, data_id, &data);

This will keep the method length under control and prevent subtle divergences later.

Also applies to: 339-364


388-391: m_job_cleaner has sole ownership – ensure its lifetime is necessary

Job now stores a std::unique_ptr<core::JobCleaner>. Because the pointer is never accessed inside Job, its only purpose is RAII-side-effects in the destructor. That is correct, but:

  1. Document this with a short comment so future readers don’t assume it is dead code.
  2. Consider [[maybe_unused]] std::unique_ptr… or naming it m_cleanup_guard to make the intent self-evident.

Tiny clarity tweak, no functional change.

src/spider/client/Data.hpp (2)

132-146: Add a default branch to future-proof the switch on Context::Source

Currently only Driver and Task are handled. Adding a default that throws makes the code robust against enum extension and silences some compiler warnings with -Wswitch-enum.

 switch (m_context.get_source()) {
     case core::Context::Source::Driver: …
     case core::Context::Source::Task:  …
+    default:
+        throw ConnectionException{"Unhandled Context::Source value"};
 }

Minor defensive hardening.


174-176: Rename and/or annotate the hidden guard members for clarity

m_context & m_data_cleaner exist only for side-effects and are not referenced elsewhere. A brief comment or a more explicit name (e.g., m_context_guard, m_data_cleanup_guard) will prevent future “unused-member?” confusion.

Also applies to: 217-218

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a29306 and c05aa6b.

📒 Files selected for processing (20)
  • src/spider/CMakeLists.txt (2 hunks)
  • src/spider/client/Data.hpp (4 hunks)
  • src/spider/client/Driver.cpp (2 hunks)
  • src/spider/client/Driver.hpp (5 hunks)
  • src/spider/client/Job.hpp (7 hunks)
  • src/spider/client/TaskContext.hpp (4 hunks)
  • src/spider/core/Context.hpp (1 hunks)
  • src/spider/core/DataCleaner.cpp (1 hunks)
  • src/spider/core/DataCleaner.hpp (1 hunks)
  • src/spider/core/DataImpl.hpp (2 hunks)
  • src/spider/core/DriverCleaner.cpp (1 hunks)
  • src/spider/core/DriverCleaner.hpp (1 hunks)
  • src/spider/core/JobCleaner.cpp (1 hunks)
  • src/spider/core/JobCleaner.hpp (1 hunks)
  • src/spider/scheduler/scheduler.cpp (1 hunks)
  • src/spider/storage/MetadataStorage.hpp (1 hunks)
  • src/spider/storage/mysql/MySqlStorage.cpp (1 hunks)
  • src/spider/storage/mysql/MySqlStorage.hpp (1 hunks)
  • src/spider/worker/FunctionManager.hpp (1 hunks)
  • tests/storage/test-MetadataStorage.cpp (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (7)
src/spider/scheduler/scheduler.cpp (1)
src/spider/storage/MetadataStorage.hpp (16)
  • conn (27-27)
  • conn (29-29)
  • conn (30-30)
  • conn (32-33)
  • conn (41-41)
  • conn (44-47)
  • conn (49-55)
  • conn (57-58)
  • conn (60-61)
  • conn (63-64)
  • conn (66-70)
  • conn (73-74)
  • conn (76-80)
  • conn (82-82)
  • conn (83-83)
  • conn (84-85)
tests/storage/test-MetadataStorage.cpp (2)
tests/integration/client.py (1)
  • storage (79-82)
src/spider/storage/MetadataStorage.hpp (16)
  • conn (27-27)
  • conn (29-29)
  • conn (30-30)
  • conn (32-33)
  • conn (41-41)
  • conn (44-47)
  • conn (49-55)
  • conn (57-58)
  • conn (60-61)
  • conn (63-64)
  • conn (66-70)
  • conn (73-74)
  • conn (76-80)
  • conn (82-82)
  • conn (83-83)
  • conn (84-85)
src/spider/storage/mysql/MySqlStorage.hpp (1)
src/spider/storage/MetadataStorage.hpp (16)
  • conn (27-27)
  • conn (29-29)
  • conn (30-30)
  • conn (32-33)
  • conn (41-41)
  • conn (44-47)
  • conn (49-55)
  • conn (57-58)
  • conn (60-61)
  • conn (63-64)
  • conn (66-70)
  • conn (73-74)
  • conn (76-80)
  • conn (82-82)
  • conn (83-83)
  • conn (84-85)
src/spider/client/Driver.hpp (2)
src/spider/client/Driver.cpp (2)
  • Driver (24-72)
  • Driver (74-120)
src/spider/core/Driver.hpp (2)
  • Driver (12-12)
  • Driver (12-12)
src/spider/core/JobCleaner.hpp (1)
src/spider/core/JobCleaner.cpp (2)
  • JobCleaner (16-25)
  • JobCleaner (27-45)
src/spider/core/DataCleaner.hpp (1)
src/spider/core/DataCleaner.cpp (2)
  • DataCleaner (17-28)
  • DataCleaner (30-52)
src/spider/core/DriverCleaner.hpp (1)
src/spider/core/DriverCleaner.cpp (2)
  • DriverCleaner (16-25)
  • DriverCleaner (27-45)
🪛 Cppcheck (2.10-2)
src/spider/client/Driver.cpp

[performance] 101-101: Variable 'id' is assigned in constructor body. Consider performing initialization in initialization list.

(useInitializationList)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: non-storage-unit-tests (ubuntu-22.04)
  • GitHub Check: non-storage-unit-tests (ubuntu-24.04)
  • GitHub Check: lint
🔇 Additional comments (26)
src/spider/scheduler/scheduler.cpp (1)

276-278: Good addition for proper driver cleanup.

This cleanup call ensures that the driver data associated with the scheduler is properly removed from storage when the scheduler terminates normally, preventing resource leaks for long-running clients.

src/spider/worker/FunctionManager.hpp (1)

317-317: Good use of Context for proper resource tracking.

The addition of the Context parameter with the Task source type ensures that data objects created during function invocation are properly associated with their origin task. This enables the new cleaner classes to perform appropriate cleanup when these objects are destructed.

src/spider/storage/mysql/MySqlStorage.hpp (1)

43-43: Good implementation of the new interface method.

The addition of the remove_driver method declaration in the MySQL storage implementation aligns with the interface changes and enables proper cleanup of driver metadata from the database.

src/spider/storage/MetadataStorage.hpp (1)

35-41: Well-documented interface addition for driver cleanup.

The new remove_driver method with clear documentation is a good addition to the storage interface. This method enables the cleaner classes to properly remove driver metadata from storage when objects are destructed, addressing the issue mentioned in the PR objectives.

tests/storage/test-MetadataStorage.cpp (3)

72-74: Good addition of cleanup step.

Adding explicit driver removal after the test is completed ensures resources are properly managed and prevents potential side effects on other tests.


107-108: Proper resource cleanup after test completion.

Adding explicit driver removal for the scheduler instance ensures proper cleanup after testing scheduler address functionality.


602-602: Consistent resource cleanup implementation.

This adds the final missing driver cleanup step for the scheduler lease timeout test, ensuring consistent resource management across all test cases.

src/spider/client/Driver.cpp (2)

47-52: Well-placed resource cleanup initialization.

The DriverCleaner is constructed after successfully adding the driver to storage but before starting the heartbeat thread, which is the appropriate sequence to ensure proper lifecycle management.


95-100: Good implementation of consistent cleanup across constructors.

Both constructors now initialize the driver cleaner in the same way, ensuring consistent resource management regardless of how the Driver object is created.

src/spider/core/DataImpl.hpp (3)

9-9: Appropriate addition of Context header.

Including the Context header enables the new context-aware creation functionality.


18-18: Good integration of Context parameter.

Adding the Context parameter to create_data() aligns with the broader architectural shift towards unified source identification across the codebase.


22-22: Correct usage of context in Data constructor.

The context parameter is properly passed to the Data constructor, maintaining the ownership semantics with the other moved and shared parameters.

src/spider/CMakeLists.txt (2)

3-5: Complete addition of new cleaner source files.

All three cleaner source files (DataCleaner, DriverCleaner, JobCleaner) are properly included in the build system, ensuring the implementation is available to the core library.


19-25: Comprehensive header file inclusion.

All required headers for the new context and cleaner functionality are properly added to the core headers list, making them accessible to dependent components.

src/spider/client/Driver.hpp (5)

17-17: Good addition of the DriverCleaner include.

This include is necessary for the newly added member variable that manages driver cleanup.


87-87: Appropriate use of the new Context abstraction.

The refactoring to use core::Context for source identification is a good pattern that unifies how source information is represented throughout the codebase.


231-231: Consistent use of Context for Job initialization.

The change maintains consistency with the other places where Context is used for source identification.


295-295: Consistent Context usage in TaskGraph start method.

Good to see the consistent application of the Context pattern across all methods that create Jobs.


323-323: Good implementation of resource cleanup with DriverCleaner.

This addresses the issue described in PR #135 where driver objects weren't being removed from storage. The unique_ptr ensures the cleaner's destructor is called when the Driver is destroyed, properly cleaning up driver metadata.

src/spider/storage/mysql/MySqlStorage.cpp (1)

221-241: Well-implemented driver removal method.

The implementation follows the established patterns in the codebase with proper transaction handling and error classification. This method appropriately enables the removal of driver entries from the database, which is essential for the cleanup solution described in the PR.

Points of strength:

  • Follows consistent error handling pattern with rollback on failure
  • Correctly differentiates KeyNotFoundErr from generic errors
  • Properly commits transaction on success
src/spider/client/TaskContext.hpp (4)

18-18: Appropriate addition of Context include.

This include is necessary for using the new Context class that unifies source identification.


65-65: Good use of Context for DataBuilder initialization.

Consistent with the pattern established in Driver.hpp, using Context to encapsulate the source type and ID.


177-177: Proper Context usage for Job creation.

This change maintains consistency with other Job creation code in the system.


235-235: Consistent Context usage in TaskGraph start method.

Good to see the Context pattern applied consistently across all methods that create Jobs.

src/spider/core/Context.hpp (1)

1-33: Well-designed Context abstraction.

This new class is a clean and focused abstraction for execution context information. It encapsulates both the source type (Driver or Task) and a UUID identifier, which simplifies interfaces throughout the system.

Strengths:

  • Uses enum class for type safety
  • Good encapsulation with private members and accessor methods
  • Appropriate use of [[nodiscard]] attribute
  • Simple and focused design that serves its purpose well

This abstraction helps unify how source context is represented across the codebase, making interfaces more consistent and supporting the cleaner classes introduced in this PR.

src/spider/core/DataCleaner.cpp (1)

30-35:

Details

✅ Verification successful

Verify m_num_exceptions is initialised at construction time

The comparison against m_num_exceptions assumes this member captured the value returned by std::uncaught_exceptions() in the constructor. If m_num_exceptions is default-initialised to 0, the destructor will always believe it is running during stack-unwinding, and the cleanup will never execute.
Please confirm it is initialised and, if not, add the initialisation.


🏁 Script executed:

#!/bin/bash
# Ensure m_num_exceptions is assigned in the header / constructor
rg -n "m_num_exceptions" -g "*DataCleaner*.[ch]pp"

Length of output: 220


No action needed: m_num_exceptions is already initialised
The default member initialiser in DataCleaner.hpp sets

int m_num_exceptions = std::uncaught_exceptions();

so the destructor’s comparison is valid and no further initialisation is required.

Comment thread src/spider/core/DataCleaner.cpp
Comment thread src/spider/core/DataCleaner.cpp
Comment thread src/spider/core/JobCleaner.cpp
Comment thread src/spider/core/JobCleaner.cpp
Comment thread src/spider/core/DriverCleaner.cpp
Comment thread src/spider/core/DataCleaner.hpp
Comment thread src/spider/core/DriverCleaner.hpp Outdated
Comment thread src/spider/core/DriverCleaner.hpp Outdated
Comment thread src/spider/core/JobCleaner.hpp Outdated
Comment thread src/spider/core/JobCleaner.hpp Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (4)
src/spider/core/JobCleaner.cpp (2)

33-42: ⚠️ Potential issue

Missing null check for storage factory

The code doesn't check if m_storage_factory is null before attempting to use it, which could cause a crash.

Add a null check before attempting to use the storage factory:

if (nullptr == conn) {
+    if (!m_storage_factory) {
+        return; // cannot obtain connection
+    }
    std::variant<std::unique_ptr<StorageConnection>, StorageErr> conn_result
            = m_storage_factory->provide_storage_connection();

43-44: ⚠️ Potential issue

Add exception handling for remove_job

The call to remove_job may throw exceptions, which would be problematic in a destructor. If an exception escapes a destructor during stack unwinding, std::terminate will be called.

Protect the call with a try/catch block:

-    m_metadata_store->remove_job(*conn, m_job_id);
+    try {
+        m_metadata_store->remove_job(*conn, m_job_id);
+    } catch (...) {
+        // Log error or handle silently to prevent std::terminate
+    }
src/spider/core/DataCleaner.hpp (1)

32-32: 🛠️ Refactor suggestion

Destructor should be marked noexcept

The destructor can call methods that interact with storage, potentially leading to exceptions. If an exception escapes the destructor during stack unwinding, std::terminate will be called.

-    ~DataCleaner();
+    ~DataCleaner() noexcept;
src/spider/core/DriverCleaner.hpp (1)

31-31: 🛠️ Refactor suggestion

Destructor should be marked noexcept

The destructor can call methods that interact with storage and performs I/O operations (std::cout in the implementation), which could potentially lead to exceptions. If an exception escapes the destructor during stack unwinding, std::terminate will be called.

-    ~DriverCleaner();
+    ~DriverCleaner() noexcept;
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb5b41a and d3700d7.

📒 Files selected for processing (9)
  • src/spider/core/DataCleaner.hpp (1 hunks)
  • src/spider/core/DriverCleaner.cpp (1 hunks)
  • src/spider/core/DriverCleaner.hpp (1 hunks)
  • src/spider/core/JobCleaner.cpp (1 hunks)
  • src/spider/core/JobCleaner.hpp (1 hunks)
  • src/spider/storage/DataStorage.hpp (2 hunks)
  • src/spider/storage/MetadataStorage.hpp (2 hunks)
  • src/spider/storage/mysql/MySqlStorage.cpp (4 hunks)
  • src/spider/storage/mysql/MySqlStorage.hpp (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/spider/storage/MetadataStorage.hpp
  • src/spider/core/DriverCleaner.cpp
  • src/spider/core/JobCleaner.hpp
  • src/spider/storage/mysql/MySqlStorage.hpp
  • src/spider/storage/mysql/MySqlStorage.cpp
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/spider/core/DataCleaner.hpp (1)
src/spider/core/DataCleaner.cpp (2)
  • DataCleaner (17-28)
  • DataCleaner (30-52)
src/spider/core/DriverCleaner.hpp (1)
src/spider/core/DriverCleaner.cpp (2)
  • DriverCleaner (16-25)
  • DriverCleaner (27-46)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: non-storage-unit-tests (ubuntu-24.04)
  • GitHub Check: non-storage-unit-tests (ubuntu-22.04)
  • GitHub Check: lint
🔇 Additional comments (12)
src/spider/storage/DataStorage.hpp (2)

73-77: Good addition of noexcept specifier for remove_task_reference

Adding the noexcept specifier to this method is appropriate since it will be called during cleanup operations in destructors. This ensures the method won't throw exceptions during resource cleanup, preventing potential std::terminate calls if exceptions occur during stack unwinding.


85-89: Good addition of noexcept specifier for remove_driver_reference

Adding the noexcept specifier to the remove_driver_reference method is appropriate for the same reason as with remove_task_reference. This will ensure safe cleanup operations during destruction of objects.

src/spider/core/JobCleaner.cpp (2)

16-25: Constructor looks good with appropriate resource management

The constructor properly initializes member variables using move semantics for the shared pointers, which is efficient and maintains correct ownership semantics.


27-32: Good stack unwinding detection in destructor

The destructor correctly checks if it's being called during stack unwinding by comparing the current exception count with the count at construction time. This prevents cleanup operations during exception propagation, which is a good practice.

src/spider/core/DataCleaner.hpp (4)

14-22: Good documentation explaining the class purpose and design

The class documentation clearly explains the reason for this cleaner class and why it can't be directly integrated into the Data class. The explanation about moved objects is particularly useful.


25-31: Constructor appropriately captures all required references

The constructor parameters include all necessary components for safely managing data cleanup: the data ID, context, and various storage-related shared pointers.


34-39: Good ownership semantics with deleted copy operations

Correctly deleting copy operations while allowing move operations prevents unintended duplication of cleaners that could lead to double-deletion of resources.


41-48: Member variables appropriately capture required state

The member variables properly capture all the state needed for cleanup operations, including the exception count at construction. The default nullptr for the connection is appropriate as it will be obtained only when needed.

src/spider/core/DriverCleaner.hpp (4)

14-21: Good documentation explaining the class purpose and design

The class documentation clearly explains the rationale behind this cleaner class and why it can't be directly integrated into the Driver class, particularly regarding moved objects.


24-29: Constructor appropriately captures all required references

The constructor parameters include all necessary components for safely managing driver cleanup: the driver ID and various storage-related shared pointers.


33-38: Good ownership semantics with deleted copy operations

Correctly deleting copy operations while allowing move operations prevents unintended duplication of cleaners that could lead to double-deletion of driver resources.


40-46: Member variables appropriately capture required state

The member variables properly capture all the state needed for cleanup operations, including the exception count at construction. The default nullptr for the connection is appropriate as it will be obtained only when needed.

Comment thread src/spider/core/JobCleaner.cpp Outdated
@sitaowang1998
sitaowang1998 requested a review from davidlion May 12, 2025 14:02
Comment thread src/spider/client/Data.hpp Outdated
Comment thread src/spider/storage/MetadataStorage.hpp Outdated
Comment thread src/spider/scheduler/scheduler.cpp Outdated
Comment thread src/spider/core/Context.hpp Outdated
Comment thread src/spider/client/Data.hpp Outdated
Comment thread src/spider/core/JobCleaner.hpp Outdated
Comment thread src/spider/client/Job.hpp

@davidlion davidlion left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

  1. We should mention why exceptions pose an issue in the Cleaner doc strings (and the PR description).
  2. Update the title.
  3. Update the description.

@sitaowang1998 sitaowang1998 changed the title fix: Add data, job and driver removal in descturctor (fixes #135). fix: Add data, job and driver removal in cleaner destructor (fixes #135). May 28, 2025
@sitaowang1998
sitaowang1998 requested a review from davidlion May 28, 2025 17:05
Comment thread src/spider/core/DataCleaner.cpp Outdated
Comment thread src/spider/core/JobCleaner.cpp Outdated
Comment thread src/spider/core/JobCleaner.hpp Outdated
@sitaowang1998
sitaowang1998 requested a review from davidlion May 28, 2025 19:26
@kirkrodrigues

Copy link
Copy Markdown
Member

@coderabbitai, based on the code and PR description, what's a good title for this pull request?

@coderabbitai

coderabbitai Bot commented May 28, 2025

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@kirkrodrigues Based on the code changes and PR description, here are some improved title suggestions that better capture the scope and purpose of this PR:

Top recommendations:

  1. fix: Implement RAII cleanup to prevent resource leaks in long-running sessions (fixes #135)
  2. Add cleaner classes to automatically remove stale Data/Job/Driver objects (fixes #135)
  3. Implement automatic resource cleanup with RAII cleaner classes (fixes #135)

Alternative options:

  1. Fix stale data persistence by adding RAII-based object cleanup (fixes #135)
  2. Add Context abstraction and cleaner classes for proper resource management (fixes #135)

The current title is functional, but these suggestions better emphasize:

  • The problem being solved (resource leaks, stale data persistence)
  • The solution approach (RAII, cleaner classes)
  • The broader impact (long-running sessions, automatic cleanup)

I'd recommend option 1 as it clearly states both the problem (resource leaks in long-running sessions) and the solution approach (RAII cleanup), which captures the essence of this substantial architectural improvement.

@sitaowang1998 sitaowang1998 changed the title fix: Add data, job and driver removal in cleaner destructor (fixes #135). fix: Add classes to clean-up Spider's internal Data, Driver, and Job objects from the database when clients destroy the corresponding client objects (fixes #135). May 29, 2025
@sitaowang1998
sitaowang1998 merged commit 6b7e5ff into y-scope:main May 29, 2025
@sitaowang1998
sitaowang1998 deleted the driver_gc branch May 29, 2025 15:27
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