Make event handling of `syncthingctl wait-for-idle` more efficient

Don't go though the list of dirs/devs for every dir/dev change event. Just
go though the list once after receiving new events. This makes also the
code a little bit easier to follow.
This commit is contained in:
Martchus 2023-09-20 18:12:55 +02:00
parent 230532d15e
commit aa524aa8b7
4 changed files with 40 additions and 28 deletions

View File

@ -943,46 +943,45 @@ void Application::waitForIdle(const ArgumentOccurrence &)
{
m_preventDisconnect = true;
// setup timer
QTimer idleTime;
// setup timer for handling minimum idle duration
auto idleTime = QTimer();
idleTime.setSingleShot(true);
idleTime.setInterval(m_idleDuration);
// define variable which is set to true if handleTimeout to indicate the idle state has persisted long enough
bool isLongEnoughIdle = false;
// define handler for timer timeout
function<void(void)> handleTimeout([this, &isLongEnoughIdle] {
// define event handlers
auto isLongEnoughIdle = false, dirsOrDevsChanged = true, newDirsOrDevs = true;
const auto handleStatusChange = [&dirsOrDevsChanged] { dirsOrDevsChanged = true; };
const auto handleNewDirsOrDevs = [&newDirsOrDevs] { newDirsOrDevs = true; };
const auto handleAllEventsProcessed = [this, &newDirsOrDevs, &dirsOrDevsChanged, &idleTime] {
if (newDirsOrDevs) {
findRelevantDirsAndDevs(OperationType::WaitForIdle);
}
if (newDirsOrDevs || dirsOrDevsChanged) {
if (!checkWhetherIdle()) {
idleTime.stop();
return;
}
if (!idleTime.isActive()) {
idleTime.start();
}
}
newDirsOrDevs = dirsOrDevsChanged = false;
};
const auto handleIdleTimer = [this, &isLongEnoughIdle] {
if (checkWhetherIdle()) {
isLongEnoughIdle = true;
}
});
// define handler for dirStatusChanged/devStatusChanged
function<void(void)> handleStatusChange([this, &idleTime] {
if (!checkWhetherIdle()) {
idleTime.stop();
return;
}
if (!idleTime.isActive()) {
idleTime.start();
}
});
// define handler for newDirs/newDevices to call findRelevantDirsAndDevs() in that case
function<void(void)> handleNewDirsOrDevs([this, &handleStatusChange] {
findRelevantDirsAndDevs(OperationType::WaitForIdle);
handleStatusChange();
});
};
// invoke handler manually because Syncthing could already be idling
handleNewDirsOrDevs();
handleAllEventsProcessed();
waitForSignals(&noop, m_idleTimeout, signalInfo(&m_connection, &SyncthingConnection::dirStatusChanged, handleStatusChange, &isLongEnoughIdle),
signalInfo(&m_connection, &SyncthingConnection::devStatusChanged, handleStatusChange, &isLongEnoughIdle),
signalInfo(&m_connection, &SyncthingConnection::newDirs, handleNewDirsOrDevs, &isLongEnoughIdle),
signalInfo(&m_connection, &SyncthingConnection::newDevices, handleNewDirsOrDevs, &isLongEnoughIdle),
signalInfo(&idleTime, &QTimer::timeout, handleTimeout, &isLongEnoughIdle));
signalInfo(&m_connection, &SyncthingConnection::allEventsProcessed, handleAllEventsProcessed, &isLongEnoughIdle),
signalInfo(&idleTime, &QTimer::timeout, handleIdleTimer, &isLongEnoughIdle));
if (!isLongEnoughIdle) {
cerr << Phrases::Warning << "Exiting after timeout" << Phrases::End << flush;

View File

@ -1113,6 +1113,16 @@ void SyncthingConnection::recalculateStatus()
* \remarks New events are automatically polled when connected.
*/
/*!
* \fn SyncthingConnection::allEventsProcesses()
* \brief Indicates all new events have been processed.
* \remarks
* This event is emitted after newEvents() and dirStatusChanged(), devStatusChanged() and other specific events.
* If you would go through the list of all directories on every dirStatusChanged() event using instead might
* be a more efficient alternative allEventsProcesses(). Just set a flag on dirStatusChanged() and go though the
* list of directories only once on the allEventsProcesses() event when the flag has been set.
*/
/*!
* \fn SyncthingConnection::dirStatusChanged()
* \brief Indicates the status of the specified \a dir changed.

View File

@ -233,6 +233,7 @@ Q_SIGNALS:
void newDevices(const std::vector<SyncthingDev> &devs);
void newConfigApplied();
void newEvents(const QJsonArray &events);
void allEventsProcessed();
void dirStatusChanged(const Data::SyncthingDir &dir, int index);
void devStatusChanged(const Data::SyncthingDev &dev, int index);
void fileChanged(const Data::SyncthingDir &dir, int index, const Data::SyncthingFileChange &fileChange);

View File

@ -1737,7 +1737,9 @@ void SyncthingConnection::readEvents()
m_hasEvents = true;
const auto replyArray = replyDoc.array();
emit newEvents(replyArray);
if (!readEventsFromJsonArray(replyArray, m_lastEventId)) {
const auto res = readEventsFromJsonArray(replyArray, m_lastEventId);
emit allEventsProcessed();
if (!res) {
return;
}