From 6b8589f4dc1aecd59e57d5f51f45b1ab165a1387 Mon Sep 17 00:00:00 2001 From: Duncan Mac-Vicar P Date: Sun, 27 Mar 2011 01:26:41 +0100 Subject: [PATCH] When syncing, disable event notifier and start accumulating them until the sync is done. When they are enabled again, a forced event is scheduled to empty the queue. --- src/mirall/folder.cpp | 3 ++ src/mirall/folder.h | 14 +++++++-- src/mirall/folderwatcher.cpp | 56 +++++++++++++++++++++++++++++------- src/mirall/folderwatcher.h | 29 ++++++++++++++++++- src/mirall/unisonfolder.cpp | 14 ++++++--- src/mirall/unisonfolder.h | 4 ++- 6 files changed, 102 insertions(+), 18 deletions(-) diff --git a/src/mirall/folder.cpp b/src/mirall/folder.cpp index 0d711c0e9..f6b4ceb39 100644 --- a/src/mirall/folder.cpp +++ b/src/mirall/folder.cpp @@ -53,11 +53,14 @@ void Folder::slotOpenFolder() void Folder::slotSyncStarted() { + // disable events until syncing is done + _watcher->setEventsEnabled(false); _openAction->setIcon(QIcon(FOLDER_SYNC_ICON)); } void Folder::slotSyncFinished() { + _watcher->setEventsEnabled(true); _openAction->setIcon(QIcon(FOLDER_ICON)); } diff --git a/src/mirall/folder.h b/src/mirall/folder.h index fe8507813..35cdea54b 100644 --- a/src/mirall/folder.h +++ b/src/mirall/folder.h @@ -32,9 +32,14 @@ public: */ virtual void startSync(const QStringList &pathList) = 0; - virtual bool isSyncing() const = 0; + /** + * True if the folder is busy and can't initiate + * a synchronization + */ + virtual bool isBusy() const = 0; signals: + void syncStarted(); void syncFinished(); @@ -44,8 +49,13 @@ private: QString _path; FolderWatcher *_watcher; QAction *_openAction; -private slots: + QStringList _pendingPaths; +protected slots: + + /* called when the watcher detect a list of changed + paths */ void slotChanged(const QStringList &pathList); + void slotOpenFolder(); void slotSyncStarted(); diff --git a/src/mirall/folderwatcher.cpp b/src/mirall/folderwatcher.cpp index 79e018c93..3e82b23f8 100644 --- a/src/mirall/folderwatcher.cpp +++ b/src/mirall/folderwatcher.cpp @@ -19,13 +19,15 @@ static const uint32_t standard_event_mask = /* minimum amount of seconds between two events to consider it a new event */ -#define MIN_EVENT_INTERVAL_SEC 5 +#define DEFAULT_EVENT_INTERVAL_SEC 5 namespace Mirall { FolderWatcher::FolderWatcher(const QString &root, QObject *parent) : QObject(parent), + _eventsEnabled(true), + _eventInterval(DEFAULT_EVENT_INTERVAL_SEC), _root(root), _processTimer(new QTimer(this)), _lastEventTime(QTime::currentTime()) @@ -49,6 +51,40 @@ QString FolderWatcher::root() const return _root; } +bool FolderWatcher::eventsEnabled() const +{ + return _eventsEnabled; +} + +void FolderWatcher::setEventsEnabled(bool enabled) +{ + _eventsEnabled = enabled; + if (_eventsEnabled) { + // schedule a queue cleanup for accumulated events + if ( _pendingPaths.empty() ) + return; + + if (!_processTimer->isActive()) + _processTimer->start(eventInterval() * 1000); + } + else + { + // if we are disabling events, clear any ongoing timer + if (_processTimer->isActive()) + _processTimer->stop(); + } +} + +int FolderWatcher::eventInterval() const +{ + return _eventInterval; +} + +void FolderWatcher::setEventInterval(int seconds) +{ + _eventInterval = seconds; +} + QStringList FolderWatcher::folders() const { return _inotify->directories(); @@ -104,29 +140,29 @@ void FolderWatcher::slotINotifyEvent(int mask, int cookie, const QString &path) qDebug() << cookie << " OTHER " << mask << " :" << path; } - _pendingPathList.append(path); + _pendingPaths.append(path); slotProcessPaths(); - - //if (!_processTimer->isActive()) - // _processTimer->start(); } void FolderWatcher::slotProcessPaths() { QTime eventTime = QTime::currentTime(); - if (_lastEventTime.secsTo(eventTime) < MIN_EVENT_INTERVAL_SEC) { - qDebug() << "Last event happened less than " << MIN_EVENT_INTERVAL_SEC << " seconds ago..."; + if (!eventsEnabled()) + return; + + if (_lastEventTime.secsTo(eventTime) < eventInterval()) { + qDebug() << "Last event happened less than " << eventInterval() << " seconds ago..."; // schedule a forced queue cleanup later if (!_processTimer->isActive()) - _processTimer->start(MIN_EVENT_INTERVAL_SEC * 1000); + _processTimer->start(eventInterval() * 1000); return; } _lastEventTime = eventTime; - QStringList notifyPaths(_pendingPathList); - _pendingPathList.clear(); + QStringList notifyPaths(_pendingPaths); + _pendingPaths.clear(); emit folderChanged(notifyPaths); } diff --git a/src/mirall/folderwatcher.h b/src/mirall/folderwatcher.h index 35b75d5f0..984f4c329 100644 --- a/src/mirall/folderwatcher.h +++ b/src/mirall/folderwatcher.h @@ -42,6 +42,31 @@ public: */ QString root() const; + /** + * If true, folderChanged() events are sent + * at least as often as eventInterval() seconds. + */ + bool eventsEnabled() const; + + /** + * Enabled or disables folderChanged() events. + * If disabled, events are accumulated and emptied + * the next time a folderChanged() event happens. + */ + void setEventsEnabled(bool enabled); + + /** + * The minimum amounts of seconds that will separate + * folderChanged() intervals + */ + int eventInterval() const; + + /** + * Sets minimum amounts of seconds that will separate + * folderChanged() intervals + */ + void setEventInterval(int seconds); + signals: /** * Emitted when one of the paths is changed @@ -53,10 +78,12 @@ protected slots: void slotAddFolderRecursive(const QString &path); void slotProcessPaths(); private: + bool _eventsEnabled; + int _eventInterval; INotify *_inotify; QString _root; // paths pending to notified - QStringList _pendingPathList; + QStringList _pendingPaths; QTimer *_processTimer; QTime _lastEventTime; }; diff --git a/src/mirall/unisonfolder.cpp b/src/mirall/unisonfolder.cpp index c1fa88e86..5e37ef4c8 100644 --- a/src/mirall/unisonfolder.cpp +++ b/src/mirall/unisonfolder.cpp @@ -22,15 +22,18 @@ UnisonFolder::UnisonFolder(const QString &path, const QString &secondPath, QObje QObject::connect(_unison, SIGNAL(error(QProcess::ProcessError)), SLOT(slotError(QProcess::ProcessError))); + + QObject::connect(_unison, SIGNAL(finished(int, QProcess::ExitStatus)), + SLOT(slotFinished(int, QProcess::ExitStatus))); } UnisonFolder::~UnisonFolder() { } -bool UnisonFolder::isSyncing() const +bool UnisonFolder::isBusy() const { - return false; + return (_unison->state() != QProcess::NotRunning); } QString UnisonFolder::secondPath() const @@ -42,6 +45,8 @@ void UnisonFolder::startSync(const QStringList &pathList) { QMutexLocker locker(&_syncMutex); + emit syncStarted(); + QString program = "unison"; QStringList args; args << "-ui" << "text"; @@ -57,10 +62,11 @@ void UnisonFolder::startSync(const QStringList &pathList) args << path(); args << secondPath(); - emit syncStarted(); - _unison->start(program, args); +} +void UnisonFolder::slotFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ emit syncFinished(); } diff --git a/src/mirall/unisonfolder.h b/src/mirall/unisonfolder.h index cdcf0b4cc..7bc777850 100644 --- a/src/mirall/unisonfolder.h +++ b/src/mirall/unisonfolder.h @@ -22,11 +22,13 @@ public: virtual void startSync(const QStringList &pathList); - virtual bool isSyncing() const; + virtual bool isBusy() const; + protected slots: void slotReadyReadStandardOutput(); void slotReadyReadStandardError(); void slotStateChanged(QProcess::ProcessState); + void slotFinished(int exitCode, QProcess::ExitStatus exitStatus); void slotError(QProcess::ProcessError); private: QMutex _syncMutex;