Skip to content

fix: synchronize plugin data phase initialization#3151

Merged
18202781743 merged 1 commit intolinuxdeepin:dcc-coredumpfrom
18202781743:flow
Apr 3, 2026
Merged

fix: synchronize plugin data phase initialization#3151
18202781743 merged 1 commit intolinuxdeepin:dcc-coredumpfrom
18202781743:flow

Conversation

@18202781743
Copy link
Copy Markdown
Contributor

@18202781743 18202781743 commented Apr 3, 2026

  1. Added m_dataPhaseStarted flag to track when data phase has begun
  2. Implemented modulePhaseFinished() to check if individual plugin completed module phase
  3. Implemented allModulePhaseFinished() to verify all plugins completed module phase
  4. Added tryStartDataPhase() to coordinate transition from module phase to data phase
  5. Modified loadPlugin() to check m_dataPhaseStarted before proceeding to data phase
  6. Updated onUpdatePluginStatus() to trigger tryStartDataPhase() when plugins reach ModuleEnd or PluginEnd
  7. Reset m_dataPhaseStarted to false in loadModules() for each new plugin loading cycle

This change ensures that all plugins complete their module phase before any plugin enters the data phase. Previously, when a single plugin reached ModuleEnd, it would immediately proceed to createData(), potentially causing issues if other plugins were still in their module phase. Now the system waits for all plugins to finish their module phase before starting the data phase for any plugin, ensuring proper synchronization.

Log: Fixed plugin loading synchronization issue

Influence:

  1. Test plugin loading with multiple plugins of different load times
  2. Verify all plugins complete module phase before any starts data phase
  3. Test with hidden plugins that may end before entering module load
  4. Verify reset behavior when loading new modules
  5. Test edge cases with empty plugin list
  6. Verify thread safety in asynchronous plugin loading scenarios

fix: 同步插件数据阶段初始化

  1. 添加 m_dataPhaseStarted 标志来跟踪数据阶段是否已开始
  2. 实现 modulePhaseFinished() 检查单个插件是否完成模块阶段
  3. 实现 allModulePhaseFinished() 验证所有插件是否完成模块阶段
  4. 添加 tryStartDataPhase() 协调从模块阶段到数据阶段的转换
  5. 修改 loadPlugin() 在进入数据阶段前检查 m_dataPhaseStarted
  6. 更新 onUpdatePluginStatus() 在插件达到 ModuleEnd 或 PluginEnd 时触发 tryStartDataPhase()
  7. 在 loadModules() 中为每个新的插件加载周期重置 m_dataPhaseStarted 为 false

此更改确保所有插件完成其模块阶段后,任何插件才能进入数据阶段。之前,当单
个插件达到 ModuleEnd 时,它会立即进入 createData(),如果其他插件仍处于模
块阶段,可能会导致问题。现在系统会等待所有插件完成模块阶段,然后才开始任
何插件的数据阶段,确保适当的同步。

Log: 修复插件加载同步问题

Influence:

  1. 测试具有不同加载时间的多个插件的加载过程
  2. 验证所有插件完成模块阶段后,才开始任何插件的数据阶段
  3. 测试可能在进入模块加载前结束的隐藏插件
  4. 验证加载新模块时的重置行为
  5. 测试空插件列表的边缘情况
  6. 验证异步插件加载场景中的线程安全性

Summary by Sourcery

Synchronize the transition from plugin module phase to data phase so that data loading only begins once all plugins have completed their module phase.

Bug Fixes:

  • Prevent plugins from entering the data phase while others are still in the module phase by coordinating phase transition based on all plugins’ statuses.

Enhancements:

  • Track global data phase state with a new flag and helper methods to determine when all plugins have finished the module phase before triggering data loading for each plugin.
  • Reset data phase state on each new module loading cycle to ensure correct behavior across successive plugin load operations.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Apr 3, 2026

Reviewer's Guide

Synchronizes the plugin lifecycle so that the data phase starts only after all plugins have finished their module phase, using a new manager-level flag and coordination helpers wired into status updates and plugin loading flow.

Sequence diagram for synchronized plugin data phase initialization

sequenceDiagram
    participant PluginManager
    participant PluginDataA
    participant PluginDataB

    Note over PluginManager: Initial module loading for all plugins

    PluginManager->>PluginDataA: start module phase
    PluginManager->>PluginDataB: start module phase

    Note over PluginDataA: PluginDataA finishes module phase first
    PluginDataA-->>PluginManager: onUpdatePluginStatus(ModuleEnd)
    PluginManager->>PluginManager: modulePhaseFinished(PluginDataA)
    PluginManager->>PluginManager: allModulePhaseFinished() returns false
    PluginManager->>PluginManager: tryStartDataPhase()
    PluginManager-->>PluginManager: m_dataPhaseStarted is false and allModulePhaseFinished is false
    PluginManager-->>PluginManager: return without starting data phase

    Note over PluginDataB: PluginDataB finishes module phase later
    PluginDataB-->>PluginManager: onUpdatePluginStatus(ModuleEnd)
    PluginManager->>PluginManager: modulePhaseFinished(PluginDataB)
    PluginManager->>PluginManager: allModulePhaseFinished() returns true
    PluginManager->>PluginManager: tryStartDataPhase()
    PluginManager->>PluginManager: set m_dataPhaseStarted to true
    PluginManager->>PluginManager: for each plugin in m_plugins call loadPlugin(plugin)

    loop for each plugin
        PluginManager->>PluginDataA: loadPlugin(PluginDataA)
        PluginManager->>PluginManager: branch on status (ModuleEnd, DataBegin, DataEnd)
        PluginManager-->>PluginDataA: start data phase
        PluginManager->>PluginDataB: loadPlugin(PluginDataB)
        PluginManager->>PluginManager: branch on status (ModuleEnd, DataBegin, DataEnd)
        PluginManager-->>PluginDataB: start data phase
    end

    Note over PluginManager: Later ModuleEnd or PluginEnd events will call tryStartDataPhase but m_dataPhaseStarted is true so no effect
Loading

Class diagram for PluginManager plugin phase coordination

classDiagram
    class PluginManager {
        - QList~PluginData*~ m_plugins
        - DccObject* m_rootModule
        - QThreadPool* m_threadPool
        - bool m_isDeleting
        - bool m_dataPhaseStarted
        - QQmlEngine* m_engine
        + PluginManager(DccManager* parent)
        + void loadModules(DccObject* root, bool async, QStringList dirs, QQmlEngine* engine)
        + void loadPlugin(PluginData* plugin)
        + void onUpdatePluginStatus(PluginData* plugin, uint status, QString log)
        + bool preparePluginFactory(PluginData* plugin)
        + bool updatePluginType(PluginData* plugin)
        + bool modulePhaseFinished(PluginData* plugin) const
        + bool allModulePhaseFinished() const
        + void tryStartDataPhase()
        + QThreadPool* threadPool()
    }

    class PluginData {
        + QString name
        + uint status
        + QObject* module
    }

    PluginManager "1" o-- "*" PluginData
    PluginManager --> PluginData : monitors status and phases
    PluginManager --> QThreadPool
    PluginManager --> QQmlEngine
    PluginManager --> DccObject
Loading

File-Level Changes

Change Details Files
Introduce manager-level coordination of the transition from module phase to data phase across all plugins
  • Add m_dataPhaseStarted member to PluginManager and reset it at the beginning of each loadModules() cycle
  • Implement modulePhaseFinished() to consider a plugin done with module phase when it is in ModuleEnd or PluginEnd, handling hidden plugins that may skip module loading
  • Implement allModulePhaseFinished() to short-circuit true on empty plugin lists and otherwise require every plugin to have finished its module phase
  • Implement tryStartDataPhase() to guard with m_dataPhaseStarted and allModulePhaseFinished(), then mark the phase started and call loadPlugin() for every tracked plugin
src/dde-control-center/pluginmanager.cpp
src/dde-control-center/pluginmanager.h
Gate plugin data-phase entry on the new coordination logic and hook it into status transitions
  • Update loadPlugin() to, on ModuleEnd without DataBegin, call tryStartDataPhase() and return early if the data phase has not yet been globally started, deferring createData() until all plugins are ready
  • Update onUpdatePluginStatus() to invoke tryStartDataPhase() whenever a plugin transitions into ModuleEnd or PluginEnd, before emitting pluginEndStatusChanged
  • Ensure PluginManager constructor initializes m_dataPhaseStarted to false so phase tracking starts in a clean state
src/dde-control-center/pluginmanager.cpp
src/dde-control-center/pluginmanager.h

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
Copy Markdown

@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 - I've left some high level feedback:

  • Given the async/thread-pool usage, accesses to m_dataPhaseStarted and iteration over m_plugins in allModulePhaseFinished()/tryStartDataPhase() should be reviewed for thread-safety (e.g. guarding with a mutex or ensuring these paths are only ever called on the main thread).
  • modulePhaseFinished() returning true when plugin is nullptr is slightly surprising and could hide accidental null calls; consider either asserting non-null or keeping this helper private and only calling it from contexts where plugin is guaranteed to be valid.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Given the async/thread-pool usage, accesses to m_dataPhaseStarted and iteration over m_plugins in allModulePhaseFinished()/tryStartDataPhase() should be reviewed for thread-safety (e.g. guarding with a mutex or ensuring these paths are only ever called on the main thread).
- modulePhaseFinished() returning true when plugin is nullptr is slightly surprising and could hide accidental null calls; consider either asserting non-null or keeping this helper private and only calling it from contexts where plugin is guaranteed to be valid.

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.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the control-center plugin loading pipeline to synchronize the transition into the “data phase” so that no plugin starts createData() until all plugins have completed the module phase, avoiding interleaving module/data initialization across plugins.

Changes:

  • Added m_dataPhaseStarted to gate the data-phase transition.
  • Introduced modulePhaseFinished(), allModulePhaseFinished(), and tryStartDataPhase() to coordinate starting the data phase across all plugins.
  • Updated loadPlugin(), onUpdatePluginStatus(), and loadModules() to enforce the synchronized phase transition and reset state per load cycle.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/dde-control-center/pluginmanager.h Adds new helpers and the m_dataPhaseStarted flag to support synchronized phase transitions.
src/dde-control-center/pluginmanager.cpp Implements synchronization logic and integrates it into the plugin status/update flow and module loading lifecycle.

Changed plugin loading logic to ensure all plugins complete their module
phase before any plugin starts the data phase. Previously, when a plugin
reached ModuleEnd status, it would immediately proceed to LoadPluginTask
for data loading. Now, the system waits until all plugins have finished
their module phase (ModuleEnd, ModuleErr, or PluginEnd status) before
starting data loading for any plugin.

Key changes:
1. Added m_modulePhaseFinished flag to track module phase completion
2. Added allModulesFinished() method to check if all plugins have
completed module phase
3. Added loadPluginData() method extracted from original loadPlugin()
logic
4. Added onModulePhaseFinished() slot to handle transition to data phase
5. Modified loadPlugin() to check module phase completion before
proceeding to data loading
6. Connected modulePhaseFinished signal to onModulePhaseFinished slot

This ensures that plugins don't start their data loading (createData())
until all plugins have completed their module initialization, preventing
potential race conditions and ensuring proper synchronization between
plugins.

Log: Fixed plugin loading synchronization issue

Influence:
1. Test plugin loading with multiple plugins to ensure all complete
module phase before data phase starts
2. Verify that plugins with ModuleEnd status wait for others before
proceeding
3. Test edge cases where some plugins may have ModuleErr or PluginEnd
status
4. Verify that the m_modulePhaseFinished flag is properly reset when
needed
5. Test plugin loading performance to ensure no regression
6. Verify that hidden plugins (not visibleToApp) still follow the
synchronization logic

fix: 同步插件数据阶段加载

修改插件加载逻辑,确保所有插件完成模块阶段后再开始数据阶段。之前,当插件
达到 ModuleEnd 状态时,会立即进入 LoadPluginTask 进行数据加载。现在,系
统会等待所有插件完成模块阶段(ModuleEnd、ModuleErr 或 PluginEnd 状态)后
才开始任何插件的数据加载。

主要变更:
1. 添加 m_modulePhaseFinished 标志来跟踪模块阶段完成状态
2. 添加 allModulesFinished() 方法来检查所有插件是否已完成模块阶段
3. 添加 loadPluginData() 方法,从原始 loadPlugin() 逻辑中提取
4. 添加 onModulePhaseFinished() 槽函数来处理向数据阶段的过渡
5. 修改 loadPlugin() 以在进入数据加载前检查模块阶段完成状态
6. 连接 modulePhaseFinished 信号到 onModulePhaseFinished 槽

这确保了插件在所有插件完成模块初始化之前不会开始数据加载
(createData()),防止潜在的竞争条件并确保插件之间的正确同步。

Log: 修复插件加载同步问题

Influence:
1. 测试多插件加载,确保所有插件在数据阶段开始前完成模块阶段
2. 验证具有 ModuleEnd 状态的插件在继续之前会等待其他插件
3. 测试某些插件可能具有 ModuleErr 或 PluginEnd 状态的边缘情况
4. 验证 m_modulePhaseFinished 标志在需要时正确重置
5. 测试插件加载性能,确保没有回归问题
6. 验证隐藏插件(不可见)仍然遵循同步逻辑
@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, caixr23

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

@18202781743 18202781743 merged commit 68441da into linuxdeepin:dcc-coredump Apr 3, 2026
16 checks passed
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.

4 participants