From fb55ea21c891a75f2e7e06d336faa9b5b8b105a3 Mon Sep 17 00:00:00 2001 From: Javier Date: Sun, 14 Jun 2015 20:18:59 +0200 Subject: improve sync locking and status messages --- mainwindow.cc | 14 ++++++ mainwindow.h | 2 + notebookmodel.cc | 22 ++++++-- notebookmodel.h | 1 + smartpenmanager.cc | 14 +++++- smartpenmanager.h | 1 + smartpensyncer.cc | 145 ++++++++++++++++++++++++++++++++++++++++++----------- smartpensyncer.h | 2 + 8 files changed, 166 insertions(+), 35 deletions(-) diff --git a/mainwindow.cc b/mainwindow.cc index 0610993..5d4f503 100644 --- a/mainwindow.cc +++ b/mainwindow.cc @@ -56,6 +56,10 @@ MainWindow::MainWindow(QWidget *parent) : this, SLOT(handleNotebookRowsInserted(QModelIndex,int,int))); connect(_manager, SIGNAL(pensBeingSynchronizedChanged()), this, SLOT(handlePensBeingSynchronizedChanged())); + connect(_manager, SIGNAL(syncComplete(QString)), + this, SLOT(handlePenSyncComplete(QString))); + connect(_manager, SIGNAL(syncFailed(QString)), + this, SLOT(handlePenSyncFailed(QString))); connect(_media, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(handleMediaStateChange(Phonon::State))); connect(_media, SIGNAL(totalTimeChanged(qint64)), @@ -278,6 +282,16 @@ void MainWindow::handlePensBeingSynchronizedChanged() } } +void MainWindow::handlePenSyncComplete(const QString &penName) +{ + ui->statusBar->showMessage(tr("Completed synchronization with %1").arg(penName), 10000); +} + +void MainWindow::handlePenSyncFailed(const QString &penName) +{ + ui->statusBar->showMessage(tr("Failed synchronization with %1").arg(penName), 10000); +} + void MainWindow::handleExport() { if (_curNotebookName == PAPER_REPLAY) { diff --git a/mainwindow.h b/mainwindow.h index e176122..6689795 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -59,6 +59,8 @@ private slots: void handleMediaTotalTimeChanged(qint64 time); void handleMediaTick(qint64 time); void handlePensBeingSynchronizedChanged(); + void handlePenSyncComplete(const QString &penName); + void handlePenSyncFailed(const QString &penName); void handleExport(); void handleAbout(); diff --git a/notebookmodel.cc b/notebookmodel.cc index dc72931..e52d3f4 100644 --- a/notebookmodel.cc +++ b/notebookmodel.cc @@ -139,8 +139,14 @@ QVariant NotebookModel::data(const QModelIndex &index, int role) const case 1: return QVariant(); case 2: - if (isNotebookLocked(penName, notebookName)) { - return QApplication::style()->standardIcon(QStyle::SP_BrowserReload); + if (notebookName != PAPER_REPLAY) { + if (isNotebookLocked(penName, notebookName)) { + return QApplication::style()->standardIcon(QStyle::SP_BrowserReload); + } + } else { + if (isPaperReplayLocked(penName)) { + return QApplication::style()->standardIcon(QStyle::SP_BrowserReload); + } } break; } @@ -385,7 +391,17 @@ bool NotebookModel::isNotebookLocked(const QString &pen, const QString ¬ebook { QDir dir = notebookDir(pen, notebook); if (dir.exists(".sync.lck")) { - return true; // TODO check if stale + return true; + } else { + return false; + } +} + +bool NotebookModel::isPaperReplayLocked(const QString &pen) const +{ + QDir dir(paperReplayDirectory(pen)); + if (dir.exists(".sync.lck")) { + return true; } else { return false; } diff --git a/notebookmodel.h b/notebookmodel.h index 17b5211..1d69e14 100644 --- a/notebookmodel.h +++ b/notebookmodel.h @@ -60,6 +60,7 @@ private: QIcon getNotebookIcon(const QString &pen, const QString ¬ebook) const; bool isPenLocked(const QString &pen) const; bool isNotebookLocked(const QString &pen, const QString ¬ebook) const; + bool isPaperReplayLocked(const QString &pen) const; int estimatePagesOfNotebook(const QString &pen, const QString ¬ebook) const; diff --git a/smartpenmanager.cc b/smartpenmanager.cc index 1750589..0ac56e2 100644 --- a/smartpenmanager.cc +++ b/smartpenmanager.cc @@ -65,7 +65,7 @@ QStringList SmartpenManager::pensBeingSynchronized() const QString name = it.value()->penName(); if (name.isEmpty()) { Smartpen::Address addr = it.value()->penAddress(); - name = QString("%1-%2").arg(addr.first, addr.second); + name = QString("%1-%2").arg(addr.first).arg(addr.second); } pens.append(name); } @@ -89,10 +89,20 @@ void SmartpenManager::handleSyncerFinished() { SmartpenSyncer *syncer = static_cast(sender()); Smartpen::Address addr = syncer->penAddress(); + qDebug() << "Finished synchronization with pen with address:" << addr; + _syncers.remove(addr); - syncer->deleteLater(); emit pensBeingSynchronizedChanged(); + + if (syncer->hasErrors()) { + qWarning() << "Synchronization with address" << addr << "failed"; + emit syncFailed(syncer->penName()); + } else { + emit syncComplete(syncer->penName()); + } + + syncer->deleteLater(); } void SmartpenManager::processDevice(udev_device *dev) diff --git a/smartpenmanager.h b/smartpenmanager.h index d9c349e..42bdc06 100644 --- a/smartpenmanager.h +++ b/smartpenmanager.h @@ -41,6 +41,7 @@ public: signals: void syncComplete(const QString &penName); + void syncFailed(const QString &penName); void pensBeingSynchronizedChanged(); public slots: diff --git a/smartpensyncer.cc b/smartpensyncer.cc index 551162e..cdf9bc6 100644 --- a/smartpensyncer.cc +++ b/smartpensyncer.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include "paperreplay.h" #include "notebookmodel.h" #include "smartpensyncer.h" @@ -28,33 +29,98 @@ #define BUFFER_SIZE 16 * 1024 namespace { -static QDateTime getTimestampFileDate(const QString &path) +class LockFile { - QFileInfo info(path); - qDebug() << "Checking timestamp" << info.filePath(); +public: + LockFile(const QString &path); + ~LockFile(); + + bool lock(); + +private: + QString _path; + FILE * _file; + bool _locked; +}; + +class TimestampFile +{ +public: + TimestampFile(const QString &path); + + QDateTime get(); + void set(); + +private: + QFileInfo _fi; +}; + +LockFile::LockFile(const QString &path) + : _path(path), _file(0), _locked(false) +{ + +} + +LockFile::~LockFile() +{ + if (_file) { + fclose(_file); + } + if (_locked) { + if (!QFile::remove(_path)) { + qWarning() << "Cannot remove lock file:" << _path; + } + } +} + +bool LockFile::lock() +{ + Q_ASSERT(!_locked); + + QFileInfo info(_path); if (info.exists()) { - return info.lastModified(); + if (info.created().secsTo(QDateTime::currentDateTime()) > 10 * 60) { + if (QFile::remove(info.filePath())) { + qDebug() << "Removing stale lock file:" << info.absoluteFilePath(); + } + } else { + return false; + } + } + + _file = ::fopen(info.absoluteFilePath().toLocal8Bit().data(), "wx"); + if (_file) { + _locked = true; + return true; } else { - return QDateTime(); + return false; } } -static void setTimestampFileDate(const QString &path) +TimestampFile::TimestampFile(const QString &path) + : _fi(path) { - QFile f(path); - if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - qWarning() << "Could not set timestamp file:" << path; - return; +} + +QDateTime TimestampFile::get() +{ + qDebug() << "Checking timestamp" << _fi.filePath(); + if (_fi.exists()) { + return _fi.lastModified(); + } else { + return QDateTime(); } - f.close(); } -void removeTimestampFile(const QString &path) +void TimestampFile::set() { - QFile f(path); - if (!f.remove()) { - qWarning() << "Cannot remove timestamp file:" << path; + QFile f(_fi.filePath()); + if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qWarning() << "Could not set timestamp file:" << _fi.absoluteFilePath(); + return; } + f.close(); + _fi.refresh(); } } @@ -81,6 +147,11 @@ QString SmartpenSyncer::penName() const return _penName; } +bool SmartpenSyncer::hasErrors() const +{ + return _errored; +} + void SmartpenSyncer::abort() { _aborted = true; @@ -123,10 +194,14 @@ void SmartpenSyncer::run() bool SmartpenSyncer::syncPen() { - QDateTime lastSyncTime = getTimestampFileDate(_penDataDir.filePath(".lastsync")); - QList changes = _pen->getChangeList(lastSyncTime); + LockFile lock(_penDataDir.filePath(".sync.lck")); + if (!lock.lock()) { + qWarning() << "Pen is already being synchronized; delete this file if it is not:" << _penDataDir.absoluteFilePath(".sync.lck"); + return false; + } - setTimestampFileDate(_penDataDir.filePath(".sync.lck")); + TimestampFile lastSync(_penDataDir.filePath(".lastsync")); + QList changes = _pen->getChangeList(lastSync.get()); foreach(const Smartpen::ChangeReport &change, changes) { if (!change.guid.isEmpty()) { @@ -140,10 +215,14 @@ bool SmartpenSyncer::syncPen() return false; } } + + if (_aborted) { + qWarning() << "Aborting sync"; + return false; + } } - setTimestampFileDate(_penDataDir.filePath(".lastsync")); - removeTimestampFile(_penDataDir.filePath(".sync.lck")); + lastSync.set(); return true; } @@ -157,17 +236,20 @@ bool SmartpenSyncer::syncNotebook(const Smartpen::ChangeReport &change) } } - setTimestampFileDate(notebookDir.filePath(".sync.lck")); + LockFile lock(notebookDir.filePath(".sync.lck")); + if (!lock.lock()) { + qWarning() << "Notebook is already being synchronized; delete this file if it is not:" << notebookDir.absoluteFilePath(".sync.lck"); + return false; + } - QDateTime lastSyncTime = getTimestampFileDate(notebookDir.filePath(".lastsync")); - QByteArray lspData = _pen->getLspData(change.guid, lastSyncTime); + TimestampFile lastSync(notebookDir.filePath(".lastsync")); + QByteArray lspData = _pen->getLspData(change.guid, lastSync.get()); if (!extractZip(lspData, notebookDir)) { return false; } - setTimestampFileDate(notebookDir.filePath(".lastsync")); - removeTimestampFile(notebookDir.filePath(".sync.lck")); + lastSync.set(); return true; } @@ -181,17 +263,20 @@ bool SmartpenSyncer::syncPaperReplay() } } - setTimestampFileDate(replayDir.filePath(".sync.lck")); + LockFile lock(replayDir.filePath(".sync.lck")); + if (!lock.lock()) { + qWarning() << "Paper replay is already being synchronized; delete this file if it is not:" << replayDir.absoluteFilePath(".sync.lck"); + return false; + } - QDateTime lastSyncTime = getTimestampFileDate(replayDir.filePath(".lastsync")); - QByteArray replayData = _pen->getPaperReplay(lastSyncTime); + TimestampFile lastSync(replayDir.filePath(".lastsync")); + QByteArray replayData = _pen->getPaperReplay(lastSync.get()); if (!extractZip(replayData, replayDir)) { return false; } - setTimestampFileDate(replayDir.filePath(".lastsync")); - removeTimestampFile(replayDir.filePath(".sync.lck")); + lastSync.set(); return true; } diff --git a/smartpensyncer.h b/smartpensyncer.h index 9577bff..57ac6d7 100644 --- a/smartpensyncer.h +++ b/smartpensyncer.h @@ -33,6 +33,8 @@ public: Smartpen::Address penAddress() const; QString penName() const; + bool hasErrors() const; + signals: void penNameChanged(); -- cgit v1.2.3