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.
This commit is contained in:
Duncan Mac-Vicar P 2011-03-27 01:26:41 +01:00
parent 64e4d531b3
commit 6b8589f4dc
6 changed files with 102 additions and 18 deletions

View file

@ -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));
}

View file

@ -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();

View file

@ -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);
}

View file

@ -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;
};

View file

@ -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();
}

View file

@ -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;