app/FtsIndexCoordinator.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "FtsIndexCoordinator.h" | ||
| 2 | |||
| 3 | #include <QThread> | ||
| 4 | #include <QTimer> | ||
| 5 | |||
| 6 | #include <algorithm> | ||
| 7 | #include <memory> | ||
| 8 | #include <utility> | ||
| 9 | |||
| 10 | 820 | FtsIndexCoordinator::FtsIndexCoordinator(RebuildJob rebuildJob, | |
| 11 | QObject *parent, | ||
| 12 | 820 | QList<int> retryDelaysMs) | |
| 13 | 820 | : QObject(parent), m_rebuildJob(std::move(rebuildJob)), | |
| 14 | 1640 | m_retryDelaysMs(std::move(retryDelaysMs)) {} | |
| 15 | |||
| 16 | 1640 | FtsIndexCoordinator::~FtsIndexCoordinator() { shutdown(); } | |
| 17 | |||
| 18 | ✗ | void FtsIndexCoordinator::requestRebuild() { | |
| 19 | ✗ | if (m_state == State::ShuttingDown) | |
| 20 | ✗ | return; | |
| 21 | ✗ | if (m_state == State::Queued || m_state == State::Running) { | |
| 22 | ✗ | ++m_coalescedRequests; | |
| 23 | ✗ | return; | |
| 24 | } | ||
| 25 | |||
| 26 | ✗ | m_terminalError.clear(); | |
| 27 | ✗ | m_retriesScheduled = 0; | |
| 28 | ✗ | m_oldestRequest.start(); | |
| 29 | ✗ | setState(State::Queued); | |
| 30 | ✗ | QTimer::singleShot(0, this, &FtsIndexCoordinator::startQueuedRebuild); | |
| 31 | } | ||
| 32 | |||
| 33 | ✗ | void FtsIndexCoordinator::startQueuedRebuild() { | |
| 34 | ✗ | if (m_state != State::Queued || m_worker) | |
| 35 | ✗ | return; | |
| 36 | |||
| 37 | ✗ | setState(State::Running); | |
| 38 | ✗ | auto result = std::make_shared<bool>(false); | |
| 39 | ✗ | const RebuildJob job = m_rebuildJob; | |
| 40 | ✗ | m_worker = QThread::create([job, result]() { | |
| 41 | ✗ | if (job) | |
| 42 | ✗ | *result = job(); | |
| 43 | ✗ | }); | |
| 44 | ✗ | connect(m_worker, &QThread::finished, this, [this, result]() { | |
| 45 | ✗ | QThread *finishedWorker = m_worker; | |
| 46 | ✗ | m_worker = nullptr; | |
| 47 | ✗ | if (m_state != State::ShuttingDown) { | |
| 48 | ✗ | if (*result) { | |
| 49 | ✗ | ++m_completionGeneration; | |
| 50 | ✗ | m_retriesScheduled = 0; | |
| 51 | ✗ | m_terminalError.clear(); | |
| 52 | ✗ | setState(State::Ready); | |
| 53 | ✗ | emit rebuildFinished(true, m_completionGeneration); | |
| 54 | ✗ | } else if (m_retriesScheduled < m_retryDelaysMs.size()) { | |
| 55 | const int delayMs = | ||
| 56 | ✗ | std::max(0, m_retryDelaysMs.at(m_retriesScheduled)); | |
| 57 | ✗ | ++m_retriesScheduled; | |
| 58 | ✗ | setState(State::Queued); | |
| 59 | ✗ | emit rebuildRetryScheduled(int(m_retriesScheduled + 1), | |
| 60 | ✗ | int(m_retryDelaysMs.size() + 1), delayMs); | |
| 61 | ✗ | QTimer::singleShot(delayMs, this, | |
| 62 | ✗ | &FtsIndexCoordinator::startQueuedRebuild); | |
| 63 | } else { | ||
| 64 | ✗ | m_terminalError = tr("FTS index rebuild failed"); | |
| 65 | ✗ | setState(State::Failed); | |
| 66 | ✗ | emit rebuildFinished(false, m_completionGeneration); | |
| 67 | } | ||
| 68 | } | ||
| 69 | // finished() is emitted just before the thread ends; deleting it before | ||
| 70 | // then aborts ("Destroyed while thread is still running"). | ||
| 71 | ✗ | finishedWorker->wait(); | |
| 72 | ✗ | finishedWorker->deleteLater(); | |
| 73 | ✗ | }); | |
| 74 | ✗ | m_worker->start(); | |
| 75 | ✗ | } | |
| 76 | |||
| 77 | 1640 | void FtsIndexCoordinator::shutdown() { | |
| 78 |
2/2✓ Branch 2 → 3 taken 820 times.
✓ Branch 2 → 4 taken 820 times.
|
1640 | if (m_state == State::ShuttingDown) |
| 79 | 820 | return; | |
| 80 | 820 | setState(State::ShuttingDown); | |
| 81 |
1/2✓ Branch 5 → 6 taken 820 times.
✗ Branch 5 → 7 not taken.
|
820 | if (!m_worker) |
| 82 | 820 | return; | |
| 83 | |||
| 84 | ✗ | QThread *worker = m_worker; | |
| 85 | ✗ | m_worker = nullptr; | |
| 86 | ✗ | disconnect(worker, nullptr, this, nullptr); | |
| 87 | ✗ | worker->requestInterruption(); | |
| 88 | ✗ | worker->quit(); | |
| 89 | ✗ | worker->wait(); | |
| 90 | ✗ | delete worker; | |
| 91 | } | ||
| 92 | |||
| 93 | ✗ | int FtsIndexCoordinator::queueDepth() const { | |
| 94 | ✗ | return m_state == State::Queued || m_state == State::Running ? 1 : 0; | |
| 95 | } | ||
| 96 | |||
| 97 | ✗ | qint64 FtsIndexCoordinator::oldestAgeMs() const { | |
| 98 | ✗ | return queueDepth() > 0 && m_oldestRequest.isValid() | |
| 99 | ✗ | ? m_oldestRequest.elapsed() | |
| 100 | ✗ | : 0; | |
| 101 | } | ||
| 102 | |||
| 103 | 820 | void FtsIndexCoordinator::setState(State state) { | |
| 104 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 820 times.
|
820 | if (m_state == state) |
| 105 | ✗ | return; | |
| 106 | 820 | m_state = state; | |
| 107 | 820 | emit stateChanged(state); | |
| 108 | } | ||
| 109 |