[Pkg-owncloud-commits] [owncloud-client] 66/211: SocketAPI: Use non-recursive (heuristic) computation of icons
Sandro Knauß
hefee-guest at moszumanska.debian.org
Sat Oct 25 09:10:27 UTC 2014
This is an automated email from the git hooks/post-receive script.
hefee-guest pushed a commit to branch master
in repository owncloud-client.
commit f1ce0a1cf353438270e07dd8dd54b9e125b05df8
Author: Markus Goetz <markus at woboq.com>
Date: Mon Oct 13 17:23:42 2014 +0200
SocketAPI: Use non-recursive (heuristic) computation of icons
---
src/mirall/folder.cpp | 94 ++++++++++++++++++++++++++++
src/mirall/folder.h | 16 +++--
src/mirall/folderman.cpp | 21 +++++--
src/mirall/folderwatcher.cpp | 2 +-
src/mirall/socketapi.cpp | 144 +++++++++++++++++--------------------------
src/mirall/syncengine.cpp | 14 ++++-
src/mirall/syncengine.h | 7 +++
src/mirall/syncfileitem.h | 7 +++
src/mirall/utility.cpp | 12 ++++
src/mirall/utility.h | 4 ++
10 files changed, 223 insertions(+), 98 deletions(-)
diff --git a/src/mirall/folder.cpp b/src/mirall/folder.cpp
index cf85dc5..1e3816c 100644
--- a/src/mirall/folder.cpp
+++ b/src/mirall/folder.cpp
@@ -512,11 +512,90 @@ QString Folder::configFile()
return _configFile;
}
+static void addErroredSyncItemPathsToList(const SyncFileItemVector& items, QSet<QString>* set) {
+ Q_FOREACH(const SyncFileItem &item, items) {
+ if (item.hasErrorStatus()) {
+ set->insert(item._file);
+ }
+ }
+}
+
void Folder::slotThreadTreeWalkResult(const SyncFileItemVector& items)
{
+ addErroredSyncItemPathsToList(items, &this->_stateLastSyncItemsWithError);
_syncResult.setSyncFileItemVector(items);
}
+void Folder::slotAboutToPropagate(const SyncFileItemVector& items)
+{
+ // empty the tainted list since the status generation code will use the _syncedItems
+ // (which imply the folder) to generate the syncing state icon now.
+ _stateTaintedFolders.clear();
+
+ addErroredSyncItemPathsToList(items, &this->_stateLastSyncItemsWithError);
+}
+
+
+bool Folder::estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s)
+{
+ if (t == CSYNC_FTW_TYPE_DIR) {
+ qDebug() << Q_FUNC_INFO << "ASKING ERROR FOLDERS" << fn;
+ if (Utility::doesSetContainPrefix(_stateLastSyncItemsWithError, fn)) {
+ s->set(SyncFileStatus::STATUS_ERROR);
+ return true;
+ }
+ // If sync is running, check _syncedItems, possibly give it STATUS_EVAL (=syncing down)
+ if (!_engine.isNull()) {
+ qDebug() << Q_FUNC_INFO << "SYNC IS RUNNING, asking SyncEngine" << fn;
+ if (_engine->estimateState(fn, t, s)) {
+ return true;
+ }
+ }
+ qDebug() << Q_FUNC_INFO << "ASKING TAINTED FOLDERS" << fn;
+ if (Utility::doesSetContainPrefix(_stateTaintedFolders, fn)) {
+ qDebug() << Q_FUNC_INFO << "Folder is tainted, EVAL!" << fn;
+ s->set(SyncFileStatus::STATUS_EVAL);
+ return true;
+ }
+ return false;
+ } else if ( t== CSYNC_FTW_TYPE_FILE) {
+ // check if errorList has the directory/file
+ if (Utility::doesSetContainPrefix(_stateLastSyncItemsWithError, fn)) {
+ s->set(SyncFileStatus::STATUS_ERROR);
+ return true;
+ }
+ // If sync running: _syncedItems -> SyncingState
+ if (!_engine.isNull()) {
+ if (_engine->estimateState(fn, t, s)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void Folder::watcherSlot(QString fn)
+{
+ // FIXME: On OS X we could not do this "if" since on OS X the file watcher ignores events for ourselves
+ // however to have the same behaviour atm on all platforms, we don't do it
+ if (!_engine.isNull()) {
+ qDebug() << Q_FUNC_INFO << "Sync running, IGNORE event for " << fn;
+ return;
+ }
+ QFileInfo fi(fn);
+ if (fi.isFile()) {
+ fn = fi.path(); // depending on OS, file watcher might be for dir or file
+ }
+ // Make it a relative path depending on the folder
+ QString relativePath = fn.remove(0, path().length());
+ qDebug() << Q_FUNC_INFO << fi.canonicalFilePath() << fn << relativePath;
+ _stateTaintedFolders.insert(relativePath);
+
+ // Notify the SocketAPI?
+}
+
+
+
void Folder::slotTerminateSync()
{
qDebug() << "folder " << alias() << " Terminating!";
@@ -639,6 +718,8 @@ void Folder::startSync(const QStringList &pathList)
connect( _engine.data(), SIGNAL(treeWalkResult(const SyncFileItemVector&)),
this, SLOT(slotThreadTreeWalkResult(const SyncFileItemVector&)), Qt::QueuedConnection);
+ connect( _engine.data(), SIGNAL(aboutToPropagate(const SyncFileItemVector&)),
+ this, SLOT(slotAboutToPropagate(const SyncFileItemVector&)), Qt::QueuedConnection);
connect(_engine.data(), SIGNAL(started()), SLOT(slotSyncStarted()), Qt::QueuedConnection);
connect(_engine.data(), SIGNAL(finished()), SLOT(slotSyncFinished()), Qt::QueuedConnection);
@@ -720,6 +801,15 @@ void Folder::slotSyncFinished()
// _watcher->setEventsEnabledDelayed(2000);
+ // This is for sync state calculation
+ _stateLastSyncItemsWithError = _stateLastSyncItemsWithErrorNew;
+ _stateLastSyncItemsWithErrorNew.clear();
+ _stateTaintedFolders.clear(); // heuristic: assume the sync had been done, new file watches needed to taint dirs
+ if (_csyncError || _csyncUnavail) {
+ // Taint the whole sync dir, we cannot give reliable state information
+ _stateTaintedFolders.insert(QLatin1String("/"));
+ }
+
if (_csyncError) {
_syncResult.setStatus(SyncResult::Error);
@@ -786,6 +876,10 @@ void Folder::slotTransmissionProgress(const Progress::Info &pi)
// a job is completed: count the errors and forward to the ProgressDispatcher
void Folder::slotJobCompleted(const SyncFileItem &item)
{
+ if (item.hasErrorStatus()) {
+ _stateLastSyncItemsWithError.insert(item._file);
+ }
+
if (Progress::isWarningKind(item._status)) {
// Count all error conditions.
_syncResult.setWarnCount(_syncResult.warnCount()+1);
diff --git a/src/mirall/folder.h b/src/mirall/folder.h
index af96511..c09863e 100644
--- a/src/mirall/folder.h
+++ b/src/mirall/folder.h
@@ -27,6 +27,7 @@
#include <QDir>
#include <QHash>
+#include <QSet>
#include <QObject>
#include <QStringList>
@@ -34,15 +35,12 @@
#include <QTimer>
#include <qelapsedtimer.h>
-class QFileSystemWatcher;
class QThread;
namespace Mirall {
class SyncEngine;
-class FolderWatcher;
-
class Folder : public QObject
{
Q_OBJECT
@@ -119,12 +117,12 @@ public:
// Used by the Socket API
SyncJournalDb *journalDb() { return &_journal; }
- CSYNC *csyncContext() { return _csync_ctx; }
QStringList selectiveSyncBlackList() { return _selectiveSyncBlackList; }
void setSelectiveSyncBlackList(const QStringList &blackList)
{ _selectiveSyncBlackList = blackList; }
+ bool estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s);
signals:
void syncStateChange();
@@ -170,10 +168,13 @@ private slots:
void etagRetreived(const QString &);
void slotNetworkUnavailable();
- void slotThreadTreeWalkResult(const SyncFileItemVector& );
+ void slotAboutToPropagate(const SyncFileItemVector& );
+ void slotThreadTreeWalkResult(const SyncFileItemVector& ); // after sync is done
void slotEmitFinishedDelayed();
+ void watcherSlot(QString);
+
private:
bool init();
@@ -204,6 +205,11 @@ private:
QElapsedTimer _timeSinceLastSync;
bool _forceSyncOnPollTimeout;
+ // For the SocketAPI folder states
+ QSet<QString> _stateLastSyncItemsWithErrorNew; // gets moved to _stateLastSyncItemsWithError at end of sync
+ QSet<QString> _stateLastSyncItemsWithError;
+ QSet<QString> _stateTaintedFolders;
+
SyncJournalDb _journal;
ClientProxy _clientProxy;
diff --git a/src/mirall/folderman.cpp b/src/mirall/folderman.cpp
index 5c3a939..6e7b8db 100644
--- a/src/mirall/folderman.cpp
+++ b/src/mirall/folderman.cpp
@@ -147,6 +147,9 @@ void FolderMan::registerFolderMonitor( Folder *folder )
connect(fw, SIGNAL(folderChanged(QString)), _folderWatcherSignalMapper, SLOT(map()));
_folderWatcherSignalMapper->setMapping(fw, folder->alias());
_folderWatchers.insert(folder->alias(), fw);
+
+ // This is at the moment only for the behaviour of the SocketApi.
+ connect(fw, SIGNAL(folderChanged(QString)), folder, SLOT(watcherSlot(QString)));
}
// register the folder with the socket API
@@ -437,19 +440,27 @@ void FolderMan::slotScheduleAllFolders()
*/
void FolderMan::slotScheduleSync( const QString& alias )
{
+ if( alias.isEmpty() || ! _folderMap.contains(alias) ) {
+ qDebug() << "Not scheduling sync for empty or unknown folder" << alias;
+ return;
+ }
+
// The folder watcher fires a lot of bogus notifications during
// a sync operation, both for actual user files and the database
// and log. Never enqueue a folder for sync while it is syncing.
// We lose some genuine sync requests that way, but that can't be
// helped.
+ // ^^ FIXME: Note that this is not the case on OS X
if( _currentSyncFolder == alias ) {
qDebug() << "folder " << alias << " is currently syncing. NOT scheduling.";
return;
}
- if( alias.isEmpty() || ! _folderMap.contains(alias) ) {
- qDebug() << "Not scheduling sync for empty or unknown folder" << alias;
- return;
+ if( _socketApi ) {
+ // We want the SocketAPI to already now update so that it can show the EVAL icon
+ // for files/folders. Only do this when not syncing, else we might get a lot
+ // of those notifications.
+ _socketApi->slotUpdateFolderView(alias);
}
qDebug() << "Schedule folder " << alias << " to sync!";
@@ -578,11 +589,11 @@ Folder *FolderMan::folderForPath(const QString &path)
const QString folderPath = QDir::cleanPath(folder->path())+QLatin1Char('/');
if(absolutePath.startsWith(folderPath)) {
- qDebug() << "found folder: " << folder->path() << " for " << absolutePath;
+ //qDebug() << "found folder: " << folder->path() << " for " << absolutePath;
return folder;
}
}
-
+ qDebug() << "ERROR: could not find folder for " << absolutePath;
return 0;
}
diff --git a/src/mirall/folderwatcher.cpp b/src/mirall/folderwatcher.cpp
index 7813a1e..303534c 100644
--- a/src/mirall/folderwatcher.cpp
+++ b/src/mirall/folderwatcher.cpp
@@ -81,7 +81,7 @@ bool FolderWatcher::pathIsIgnored( const QString& path )
QFileInfo fInfo(path);
if( fInfo.isHidden() ) {
- qDebug() << "* Discarded as is hidden!";
+ qDebug() << "* Discarded as is hidden!" << fInfo.filePath();
return true;
}
diff --git a/src/mirall/socketapi.cpp b/src/mirall/socketapi.cpp
index 05b70af..c98ec36 100644
--- a/src/mirall/socketapi.cpp
+++ b/src/mirall/socketapi.cpp
@@ -71,50 +71,6 @@ namespace SocketApiHelper {
SyncFileStatus fileStatus(Folder *folder, const QString& systemFileName, c_strlist_t *excludes );
-/**
- * @brief recursiveFolderStatus
- * @param fileName - the relative file name to examine
- * @return the resulting status
- *
- * The resulting status can only be either SYNC which means all files
- * are in sync, ERROR if an error occured, or EVAL if something needs
- * to be synced underneath this dir.
- */
-// compute the file status of a directory recursively. It returns either
-// "all in sync" or "needs update" or "error", no more details.
-SyncFileStatus recursiveFolderStatus(Folder *folder, const QString& fileName, c_strlist_t *excludes )
-{
- QDir dir(folder->path() + fileName);
-
- const QStringList dirEntries = dir.entryList( QDir::AllEntries | QDir::NoDotAndDotDot );
-
- SyncFileStatus result(SyncFileStatus::STATUS_SYNC);
-
- foreach( const QString entry, dirEntries ) {
- QString normalizedFile = QString(fileName + QLatin1Char('/') + entry).normalized(QString::NormalizationForm_C);
- QFileInfo fi(entry);
- SyncFileStatus sfs;
-
- if( fi.isDir() ) {
- sfs = recursiveFolderStatus(folder, normalizedFile, excludes );
- } else {
- QString fs( normalizedFile );
- if( fileName.isEmpty() ) {
- // toplevel, no slash etc. needed.
- fs = entry.normalized(QString::NormalizationForm_C);
- }
- sfs = fileStatus(folder, fs, excludes);
- }
-
- if( sfs.tag() == SyncFileStatus::STATUS_STAT_ERROR || sfs.tag() == SyncFileStatus::STATUS_ERROR ) {
- return SyncFileStatus::STATUS_ERROR;
- } else if( sfs.tag() == SyncFileStatus::STATUS_EVAL || sfs.tag() == SyncFileStatus::STATUS_NEW) {
- result.set(SyncFileStatus::STATUS_EVAL);
- }
- }
- return result;
-}
-
SyncJournalFileRecord dbFileRecord_capi( Folder *folder, QString fileName )
{
@@ -211,7 +167,8 @@ SyncFileStatus fileStatus(Folder *folder, const QString& systemFileName, c_strli
if( fi.isSymLink() ) {
return SyncFileStatus(SyncFileStatus::STATUS_IGNORE);
}
- int type = CSYNC_FTW_TYPE_FILE;
+
+ csync_ftw_type_e type = CSYNC_FTW_TYPE_FILE;
if( fi.isDir() ) {
type = CSYNC_FTW_TYPE_DIR;
}
@@ -224,55 +181,67 @@ SyncFileStatus fileStatus(Folder *folder, const QString& systemFileName, c_strli
return SyncFileStatus(SyncFileStatus::STATUS_IGNORE);
}
- // Problem: for the sync dir itself we do not have a record in the sync journal
- // so the next check must not be used for the sync root folder.
- SyncJournalFileRecord rec = dbFileRecord_capi(folder, unixFileName );
- if( !isSyncRootFolder && !rec.isValid() ) {
- // check the parent folder if it is shared and if it is allowed to create a file/dir within
- QDir d( fi.path() );
- QString parentPath = d.path();
- SyncJournalFileRecord dirRec = dbFileRecord_capi(folder, parentPath);
- while( !d.isRoot() && !(d.exists() && dirRec.isValid()) ) {
- d.cdUp(); // returns true if the dir exists.
-
- parentPath = d.path();
- // cut the folder path
- dirRec = dbFileRecord_capi(folder, parentPath);
+
+ SyncFileStatus status(SyncFileStatus::STATUS_NONE);
+ if (type == CSYNC_FTW_TYPE_DIR) {
+ if (folder->estimateState(fileName, type, &status)) {
+ qDebug() << Q_FUNC_INFO << "Folder estimated status for" << fileName << "to" << status.toSocketAPIString();
+ return status;
+ }
+ if (fileName == "") {
+ // sync folder itself
+ if (folder->syncResult().status() == SyncResult::Undefined
+ || folder->syncResult().status() == SyncResult::NotYetStarted
+ || folder->syncResult().status() == SyncResult::SyncPrepare
+ || folder->syncResult().status() == SyncResult::SyncRunning
+ || folder->syncResult().status() == SyncResult::Paused) {
+ status.set(SyncFileStatus::STATUS_EVAL);
+ return status;
+ } else if (folder->syncResult().status() == SyncResult::Success
+ || folder->syncResult().status() == SyncResult::Problem) {
+ status.set(SyncFileStatus::STATUS_SYNC);
+ return status;
+ } else if (folder->syncResult().status() == SyncResult::Error
+ || folder->syncResult().status() == SyncResult::SetupError
+ || folder->syncResult().status() == SyncResult::SyncAbortRequested) {
+ status.set(SyncFileStatus::STATUS_ERROR);
+ return status;
+ }
}
- if( dirRec.isValid() ) {
- if( dirRec._type == CSYNC_FTW_TYPE_DIR ) {
- if( !dirRec._remotePerm.contains("K") ) {
- return SyncFileStatus::STATUS_ERROR;
- }
+ SyncJournalFileRecord rec = dbFileRecord_capi(folder, unixFileName );
+ if (rec.isValid()) {
+ status.set(SyncFileStatus::STATUS_SYNC);
+ if (rec._remotePerm.contains("S")) {
+ status.setSharedWithMe(true);
+ }
+ } else {
+ status.set(SyncFileStatus::STATUS_EVAL);
+ }
+ } else if (type == CSYNC_FTW_TYPE_FILE) {
+ if (folder->estimateState(fileName, type, &status)) {
+ return status;
+ }
+ SyncJournalFileRecord rec = dbFileRecord_capi(folder, unixFileName );
+ if (rec.isValid()) {
+ if (rec._remotePerm.contains("S")) {
+ status.setSharedWithMe(true);
+ }
+ if( FileSystem::getModTime(fi.absoluteFilePath()) == Utility::qDateTimeToTime_t(rec._modtime) ) {
+ status.set(SyncFileStatus::STATUS_SYNC);
+ return status;
} else {
- if( !dirRec._remotePerm.contains("C") ) {
- return SyncFileStatus::STATUS_ERROR;
- }
+ status.set(SyncFileStatus::STATUS_EVAL);
+ return status;
}
}
- return SyncFileStatus(SyncFileStatus::STATUS_NEW);
- }
-
- SyncFileStatus status(SyncFileStatus::STATUS_NONE);
- if( type == CSYNC_FTW_TYPE_DIR ) {
- // compute recursive status of the directory
- status = recursiveFolderStatus( folder, fileName, excludes );
- } else if( FileSystem::getModTime(fi.absoluteFilePath()) != Utility::qDateTimeToTime_t(rec._modtime) ) {
- // file was locally modified.
- status.set(SyncFileStatus::STATUS_EVAL);
- } else {
- status.set(SyncFileStatus::STATUS_SYNC);
- }
-
- if (rec._remotePerm.contains("S")) {
- status.setSharedWithMe(true);
+ status.set(SyncFileStatus::STATUS_NEW);
+ return status;
}
return status;
}
-
-}
+} // namespace
SocketApi::SocketApi(QObject* parent)
: QObject(parent)
@@ -450,6 +419,8 @@ void SocketApi::slotUpdateFolderView(const QString& alias)
} else {
broadcastMessage(QLatin1String("UPDATE_VIEW"), f->path() );
}
+ } else {
+ qDebug() << "Not sending UPDATE_VIEW for" << alias << "because status() is" << f->syncResult().status();
}
}
}
@@ -521,7 +492,8 @@ void SocketApi::broadcastMessage( const QString& verb, const QString& path, cons
msg.append(QDir::toNativeSeparators(path));
}
- DEBUG << "Broadcasting to" << _listeners.count() << "listeners: " << msg;
+ // sendMessage already has a debug output
+ //DEBUG << "Broadcasting to" << _listeners.count() << "listeners: " << msg;
foreach(SocketType *socket, _listeners) {
sendMessage(socket, msg, doWait);
}
diff --git a/src/mirall/syncengine.cpp b/src/mirall/syncengine.cpp
index ae0edf5..6c24d05 100644
--- a/src/mirall/syncengine.cpp
+++ b/src/mirall/syncengine.cpp
@@ -22,6 +22,7 @@
#include "discoveryphase.h"
#include "creds/abstractcredentials.h"
#include "csync_util.h"
+#include "mirall/syncfilestatus.h"
#ifdef Q_OS_WIN
#include <windows.h>
@@ -1069,7 +1070,18 @@ void SyncEngine::setSelectiveSyncBlackList(const QStringList& list)
}
}
-
+bool SyncEngine::estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s)
+{
+ Q_FOREACH(const SyncFileItem &item, _syncedItems) {
+ //qDebug() << Q_FUNC_INFO << fn << item._file << fn.startsWith(item._file) << item._file.startsWith(fn);
+ if (item._file.startsWith(fn)) {
+ qDebug() << Q_FUNC_INFO << "Setting" << fn << " to STATUS_EVAL";
+ s->set(SyncFileStatus::STATUS_EVAL);
+ return true;
+ }
+ }
+ return false;
+}
void SyncEngine::abort()
{
diff --git a/src/mirall/syncengine.h b/src/mirall/syncengine.h
index 0b25a43..e37ce7c 100644
--- a/src/mirall/syncengine.h
+++ b/src/mirall/syncengine.h
@@ -33,6 +33,7 @@
#include "mirall/syncfileitem.h"
#include "mirall/progressdispatcher.h"
#include "mirall/utility.h"
+#include "mirall/syncfilestatus.h"
class QProcess;
@@ -66,6 +67,8 @@ public:
/* Return true if we detected that another sync is needed to complete the sync */
bool isAnotherSyncNeeded() { return _anotherSyncNeeded; }
+ bool estimateState(QString fn, csync_ftw_type_e t, SyncFileStatus* s);
+
signals:
void csyncError( const QString& );
void csyncUnavailable();
@@ -123,7 +126,11 @@ private:
void finalize();
static bool _syncRunning; //true when one sync is running somewhere (for debugging)
+
QMap<QString, SyncFileItem> _syncItemMap;
+
+ // should be called _syncItems (present tense). It's the items from the _syncItemMap but
+ // sorted and re-adjusted based on permissions.
SyncFileItemVector _syncedItems;
CSYNC *_csync_ctx;
diff --git a/src/mirall/syncfileitem.h b/src/mirall/syncfileitem.h
index fccc91a..22a7581 100644
--- a/src/mirall/syncfileitem.h
+++ b/src/mirall/syncfileitem.h
@@ -72,6 +72,13 @@ public:
return _file.isEmpty();
}
+ bool hasErrorStatus() const {
+ return _status == SyncFileItem::SoftError
+ || _status == SyncFileItem::NormalError
+ || _status == SyncFileItem::FatalError
+ || !_errorString.isEmpty();
+ }
+
// Variables usefull for everybody
QString _file;
QString _renameTarget;
diff --git a/src/mirall/utility.cpp b/src/mirall/utility.cpp
index 4e38a8d..63d6fee 100644
--- a/src/mirall/utility.cpp
+++ b/src/mirall/utility.cpp
@@ -224,6 +224,18 @@ QString Utility::toCSyncScheme(const QString &urlStr)
return url.toString();
}
+bool Utility::doesSetContainPrefix(QSet<QString> &l, QString &p) {
+
+ Q_FOREACH (const QString &setPath, l) {
+ //qDebug() << Q_FUNC_INFO << p << setPath << setPath.startsWith(p);
+ if (setPath.startsWith(p)) {
+ return true;
+ }
+ }
+ //qDebug() << "-> NOOOOO!!!" << p << l.count();
+ return false;
+}
+
QString Utility::escape(const QString &in)
{
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
diff --git a/src/mirall/utility.h b/src/mirall/utility.h
index ac451cf..32eab30 100644
--- a/src/mirall/utility.h
+++ b/src/mirall/utility.h
@@ -42,6 +42,10 @@ namespace Utility
OWNCLOUDSYNC_EXPORT QString toCSyncScheme(const QString &urlStr);
/** Like QLocale::toString(double, 'f', prec), but drops trailing zeros after the decimal point */
+ OWNCLOUDSYNC_EXPORT bool doesSetContainPrefix(QSet<QString> &l, QString &p);
+
+
+
/**
* @brief compactFormatDouble - formats a double value human readable.
*
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-owncloud/owncloud-client.git
More information about the Pkg-owncloud-commits
mailing list