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:
parent
230532d15e
commit
aa524aa8b7
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue