Skip to content

fix: resolve high CPU usage and account loading failures#320

Merged
wyu71 merged 1 commit intolinuxdeepin:masterfrom
wyu71:master
Apr 7, 2026
Merged

fix: resolve high CPU usage and account loading failures#320
wyu71 merged 1 commit intolinuxdeepin:masterfrom
wyu71:master

Conversation

@wyu71
Copy link
Copy Markdown
Contributor

@wyu71 wyu71 commented Apr 7, 2026

Fix infinite DBus loop in year view by using cached lunar data loading instead of direct queries. Fix range filter bug (|| to &&) in lunar manager. Add anti-reentry protection for in-flight queries. Optimize timer-driven repaints to only update visible view. Retry failed DBus calls synchronously to prevent permanent account info loss.

修复年视图无限DBus循环导致CPU满占用,改用缓存的农历数据加载。
修复农历管理器日期范围过滤条件错误(||改&&),增加查询中防重入
保护。优化定时器重绘只更新当前可见视图。DBus异步调用失败时
同步重试,防止账户信息永久不显示。

Log: 修复CPU高占用和账户信息加载失败问题
PMS: BUG-355799
Influence: 修复年视图无限信号循环导致CPU持续满载,修复账户信息偶尔永久不显示,
优化定时器驱动的视图重绘减少不必要的开销。

Summary by Sourcery

Resolve high CPU usage and intermittent account data loading failures by improving lunar data caching, preventing redundant DBus queries, and adding synchronous fallbacks for critical DBus calls.

Bug Fixes:

  • Correct lunar and festival date range filtering to only return data within the requested interval.
  • Prevent re-entrant lunar data queries for the same date range to avoid infinite DBus loops and excessive CPU usage.
  • Ensure account lists and general settings are still loaded when asynchronous DBus calls fail by retrying them synchronously.
  • Avoid unnecessary calendar view updates by only repainting the currently visible view and limiting time updates in the day view to when it is shown.
  • Load year view lunar data via the cached loader instead of direct DBus queries to break the DBus signal loop.

Enhancements:

  • Accumulate lunar and festival query results into a persistent cache keyed by date ranges to improve reuse of previously fetched data.

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Apr 7, 2026

Reviewer's Guide

This PR fixes high CPU usage from an infinite DBus-driven year-view refresh loop and addresses intermittent account info loading failures by switching the year view to use cached lunar data with anti-reentry protection, correcting lunar range filters, optimizing timer-driven view updates, and adding synchronous fallbacks for failed DBus account/general-settings calls.

Sequence diagram for year view lunar data loading with caching and anti reentry

sequenceDiagram
    actor User
    participant MainWindow as Calendarmainwindow
    participant YearWin as CYearWindow
    participant LunarMgr as LunarManager
    participant DBus as DBusLunarService

    User ->> MainWindow: Open year view
    MainWindow ->> YearWin: show()
    User ->> YearWin: Enable lunar display
    YearWin ->> LunarMgr: ensureLunarDataLoaded(yearStart, yearEnd)

    alt Range already fully cached
        LunarMgr --> YearWin: Return (no DBus calls)
        YearWin ->> LunarMgr: getHuangLiDayMap(yearStart, yearEnd)
        YearWin ->> LunarMgr: getFestivalInfoDateMap(yearStart, yearEnd)
        YearWin --> User: Render year view with cached lunar data
    else Range not fully cached and not pending
        LunarMgr ->> LunarMgr: Insert (yearStart, yearEnd) into m_pendingQueries
        LunarMgr ->> DBus: Async queryLunarInfo(yearStart, yearEnd)
        LunarMgr ->> DBus: Async queryFestivalInfo(yearStart, yearEnd)

        DBus -->> LunarMgr: lunar data result
        LunarMgr ->> LunarMgr: Merge result into m_lunarInfoMap
        LunarMgr ->> LunarMgr: Remove (yearStart, yearEnd) from m_pendingQueries
        LunarMgr ->> YearWin: emit lunarInfoReady()

        DBus -->> LunarMgr: festival data result
        LunarMgr ->> LunarMgr: Update m_festivalDateMap
        LunarMgr ->> LunarMgr: Remove (yearStart, yearEnd) from m_pendingQueries (idempotent)
        LunarMgr ->> YearWin: emit festivalInfoReady()

        YearWin ->> LunarMgr: getHuangLiDayMap(yearStart, yearEnd)
        YearWin ->> LunarMgr: getFestivalInfoDateMap(yearStart, yearEnd)
        YearWin --> User: Render year view with newly cached lunar data
    end

    Note over LunarMgr: If ensureLunarDataLoaded is called again for the same range
    LunarMgr ->> LunarMgr: Check m_pendingQueries
    LunarMgr --> YearWin: Return immediately to prevent reentrant DBus queries
Loading

Sequence diagram for DBus account list loading with synchronous retry

sequenceDiagram
    actor User
    participant UI as AccountUI
    participant Req as DbusAccountManagerRequest
    participant DBus as DBusAccountService

    User ->> UI: Open accounts panel
    UI ->> Req: Async getAccountList()
    Req ->> DBus: callWithArgumentList(Async, getAccountList, args)

    DBus -->> Req: Async reply (error)
    Req ->> Req: slotCallFinished(call)
    Req ->> Req: Detect isError() and getmember() == getAccountList
    Req ->> Req: Log warning

    Req ->> DBus: callWithArgumentList(Block, getAccountList, emptyArgs)
    DBus -->> Req: Sync reply(accountJson)

    Req ->> Req: DAccount::fromJsonListString(accountList, accountJson)
    Req -->> UI: signalGetAccountListFinish(accountList)
    UI --> User: Show account list

    opt General settings load
        UI ->> Req: Async getCalendarGeneralSettings()
        Req ->> DBus: callWithArgumentList(Async, getCalendarGeneralSettings, args)
        DBus -->> Req: Async reply (error)
        Req ->> Req: slotCallFinished(call)
        Req ->> Req: Detect isError() and getmember() == getCalendarGeneralSettings
        Req ->> DBus: callWithArgumentList(Block, getCalendarGeneralSettings, emptyArgs)
        DBus -->> Req: Sync reply(settingsJson)
        Req ->> Req: DCalendarGeneralSettings::fromJsonString(settingsPtr, settingsJson)
        Req -->> UI: signalGetGeneralSettingsFinish(settingsPtr)
    end
Loading

Class diagram for updated lunar data loading and DBus retry logic

classDiagram
    class LunarManager {
        +QMap~QDate, CaHuangLiDayInfo~ m_lunarInfoMap
        +QMap~QDate, int~ m_festivalDateMap
        +QList~QPair~QDate, QDate~~ m_queriedRanges
        +QSet~QPair~QDate, QDate~~ m_pendingQueries
        +void queryLunarInfo(QDate startDate, QDate stopDate)
        +void queryFestivalInfo(QDate startDate, QDate stopDate)
        +QMap~QDate, CaHuangLiDayInfo~ getHuangLiDayMap(QDate startDate, QDate stopDate)
        +QMap~QDate, int~ getFestivalInfoDateMap(QDate startDate, QDate stopDate)
        +void ensureLunarDataLoaded(QDate startDate, QDate endDate)
        +static LunarManager* getInstace()
    }

    class CYearWindow {
        +void updateShowLunar()
        +QDate getSelectDate()
    }

    class Calendarmainwindow {
        +void slotCurrentDateUpdate()
        -QStackedWidget* m_stackWidget
        -CScheduleBaseWidget* m_DayWindow
        -CScheduleBaseWidget* m_monthWindow
        -CYearWindow* m_yearwindow
    }

    class CScheduleBaseWidget {
        +void updateData()
    }

    class CDynamicIcon {
        +static CDynamicIcon* getInstance()
        +QDate getDate()
        +void setDate(QDate date)
        +void setIcon()
    }

    class DbusAccountManagerRequest {
        +void slotCallFinished(CDBusPendingCallWatcher* call)
        +QDBusReply~QString~ callWithArgumentList(QDBus::CallMode mode, QString method, QList~QVariant~ args)
        +void signalGetAccountListFinish(DAccount::List accountList)
        +void signalGetGeneralSettingsFinish(DCalendarGeneralSettings::Ptr settings)
    }

    class CDBusPendingCallWatcher {
        +bool isError()
        +QDBusMessage reply()
        +QDBusError error()
        +QString getmember()
    }

    class DAccount {
        <<static>> bool fromJsonListString(DAccount::List accountList, QString json)
        +typedef QList~DAccount~ List
    }

    class DCalendarGeneralSettings {
        +typedef QSharedPointer~DCalendarGeneralSettings~ Ptr
        <<static>> bool fromJsonString(DCalendarGeneralSettings::Ptr settings, QString json)
    }

    CYearWindow --> LunarManager : uses gLunarManager
    Calendarmainwindow o--> CYearWindow : owns
    Calendarmainwindow o--> CScheduleBaseWidget : owns via m_stackWidget
    Calendarmainwindow --> CDynamicIcon : uses
    DbusAccountManagerRequest --> CDBusPendingCallWatcher : handles
    DbusAccountManagerRequest --> DAccount : parses account list
    DbusAccountManagerRequest --> DCalendarGeneralSettings : parses settings
    LunarManager --> QDBusInterface : uses for DBus calls
    LunarManager --> QFutureWatcher : uses for async queries
    LunarManager --> QMap
    LunarManager --> QSet
    LunarManager --> QList
Loading

File-Level Changes

Change Details Files
Make lunar and festival data loading cached, range-correct, and non-reentrant to avoid redundant DBus calls and infinite loops.
  • On lunar query completion, merge newly fetched results into the existing lunar cache instead of overwriting it, then remove the corresponding pending query entry and emit readiness signals.
  • On festival query completion, populate the festival date map incrementally without clearing existing data, then remove the corresponding pending query entry and emit readiness signals.
  • Fix date range filters for lunar and festival maps to use inclusive AND conditions so only dates within [startDate, stopDate] are returned.
  • Add a pending-queries set and early-return guard in ensureLunarDataLoaded to avoid re-entrant DBus queries for the same date range while a previous call is still in flight, and mark ranges as pending before dispatching queries.
src/calendar-client/src/dataManage/lunarmanager.cpp
src/calendar-client/src/dataManage/lunarmanager.h
Switch the year view to rely on the cached lunar loading API instead of issuing raw DBus queries, breaking the infinite signal loop.
  • Replace direct calls to queryLunarInfo and queryFestivalInfo with ensureLunarDataLoaded for the selected year’s date range when showing lunar info in the year window.
src/calendar-client/src/widget/yearWidget/yearwindow.cpp
Optimize timer-driven UI updates so only the visible view and necessary widgets are refreshed.
  • Only update the day view’s current time when the day view is visible in the stacked widget, reducing unnecessary repaints.
  • When the date rolls over, update data only on the currently visible schedule widget instead of all stacked widgets, while still refreshing year view data, month view current-date marker, and the day view’s time line.
src/calendar-client/src/widget/calendarmainwindow.cpp
Add synchronous fallback retries for critical DBus calls to prevent permanent loss of account and settings information when async calls fail.
  • Include QDBusReply and, on async DBus error, log the error and synchronously retry getAccountList; on success, parse the JSON string into a DAccount::List and emit the existing completion signal.
  • Similarly, synchronously retry getCalendarGeneralSettings on async error; on success, construct settings object from JSON and emit the general-settings completion signal, while preserving existing error handling for other methods.
src/calendar-client/src/dbus/dbusaccountmanagerrequest.cpp

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 found 1 issue, and left some high level feedback:

  • The synchronous callWithArgumentList(QDBus::Block, ...) retries inside slotCallFinished risk blocking the main thread/event loop on DBus failure; consider moving the blocking retry to a worker thread or using a bounded, non-blocking fallback strategy to avoid UI stalls.
  • Using QSet<QPair<QDate, QDate>> m_pendingQueries relies on a suitable qHash for QPair<QDate,QDate>; verify that your Qt version provides this or add an explicit qHash overload, otherwise membership checks may not compile or behave as expected.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The synchronous `callWithArgumentList(QDBus::Block, ...)` retries inside `slotCallFinished` risk blocking the main thread/event loop on DBus failure; consider moving the blocking retry to a worker thread or using a bounded, non-blocking fallback strategy to avoid UI stalls.
- Using `QSet<QPair<QDate, QDate>> m_pendingQueries` relies on a suitable `qHash` for `QPair<QDate,QDate>`; verify that your Qt version provides this or add an explicit `qHash` overload, otherwise membership checks may not compile or behave as expected.

## Individual Comments

### Comment 1
<location path="src/calendar-client/src/dbus/dbusaccountmanagerrequest.cpp" line_range="199-208" />
<code_context>
+        if (call->getmember() == "getAccountList") {
</code_context>
<issue_to_address>
**issue (bug_risk):** Return status `ret` is always set to error even if the synchronous retry succeeds.

You’re unconditionally setting `ret = 1` in the error branch after the synchronous retry. As a result, callers of `slotCallFinished` will still see an error even when the retry successfully decodes the response and emits the finish signals. Please either update `ret` based on the retry result or bypass the outer error handling when the retry succeeds.
</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 thread src/calendar-client/src/dbus/dbusaccountmanagerrequest.cpp
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

  • 敏感词检查失败, 检测到1个文件存在敏感词
详情
{
    "src/calendar-client/src/widget/calendarmainwindow.cpp": [
        {
            "line": "            url = \"https://www.deepin.org/zh/agreement/privacy/\";",
            "line_number": 1168,
            "rule": "S35",
            "reason": "Url link | 20e2eab189"
        },
        {
            "line": "            url = \"https://www.uniontech.com/agreement/privacy-cn\";",
            "line_number": 1170,
            "rule": "S35",
            "reason": "Url link | 4850a00dd7"
        },
        {
            "line": "            url = \"https://www.deepin.org/en/agreement/privacy/\";",
            "line_number": 1174,
            "rule": "S35",
            "reason": "Url link | 38d42f63bf"
        },
        {
            "line": "            url = \"https://www.uniontech.com/agreement/privacy-en\";",
            "line_number": 1176,
            "rule": "S35",
            "reason": "Url link | f82409d3b5"
        }
    ]
}

Fix infinite DBus loop in year view by using cached lunar data loading
instead of direct queries. Fix range filter bug (|| to &&) in lunar
manager. Add anti-reentry protection for in-flight queries. Optimize
timer-driven repaints to only update visible view. Retry failed DBus
calls synchronously to prevent permanent account info loss.

修复年视图无限DBus循环导致CPU满占用,改用缓存的农历数据加载。
修复农历管理器日期范围过滤条件错误(||改&&),增加查询中防重入
保护。优化定时器重绘只更新当前可见视图。DBus异步调用失败时
同步重试,防止账户信息永久不显示。

Log: 修复CPU高占用和账户信息加载失败问题
PMS: BUG-355799
Influence: 修复年视图无限信号循环导致CPU持续满载,修复账户信息偶尔永久不显示,
优化定时器驱动的视图重绘减少不必要的开销。
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

  • 敏感词检查失败, 检测到1个文件存在敏感词
详情
{
    "src/calendar-client/src/widget/calendarmainwindow.cpp": [
        {
            "line": "            url = \"https://www.deepin.org/zh/agreement/privacy/\";",
            "line_number": 1168,
            "rule": "S35",
            "reason": "Url link | 20e2eab189"
        },
        {
            "line": "            url = \"https://www.uniontech.com/agreement/privacy-cn\";",
            "line_number": 1170,
            "rule": "S35",
            "reason": "Url link | 4850a00dd7"
        },
        {
            "line": "            url = \"https://www.deepin.org/en/agreement/privacy/\";",
            "line_number": 1174,
            "rule": "S35",
            "reason": "Url link | 38d42f63bf"
        },
        {
            "line": "            url = \"https://www.uniontech.com/agreement/privacy-en\";",
            "line_number": 1176,
            "rule": "S35",
            "reason": "Url link | f82409d3b5"
        }
    ]
}

@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

@wyu71 wyu71 merged commit 2b15a79 into linuxdeepin:master Apr 7, 2026
19 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.

3 participants