New discovery algorithm: fixups

Adapt reviews from ckamm in https://github.com/owncloud/client/pull/6738#pullrequestreview-164623532

- SyncJournalFileRecord: initialize everything inline
- Add more comments
- And some ENFORCE
This commit is contained in:
Olivier Goffart 2018-10-15 17:02:04 +02:00 committed by Kevin Ottens
parent 059f722b3b
commit c009dae1ce
No known key found for this signature in database
GPG key ID: 074BBBCB8DECC9E2
6 changed files with 45 additions and 12 deletions

View file

@ -21,8 +21,6 @@
namespace OCC { namespace OCC {
SyncJournalFileRecord::SyncJournalFileRecord() = default;
QByteArray SyncJournalFileRecord::numericFileId() const QByteArray SyncJournalFileRecord::numericFileId() const
{ {
// Use the id up until the first non-numeric character // Use the id up until the first non-numeric character

View file

@ -38,8 +38,6 @@ class SyncFileItem;
class OCSYNC_EXPORT SyncJournalFileRecord class OCSYNC_EXPORT SyncJournalFileRecord
{ {
public: public:
SyncJournalFileRecord();
bool isValid() const bool isValid() const
{ {
return !_path.isEmpty(); return !_path.isEmpty();

View file

@ -24,6 +24,22 @@ class ExcludedFiles;
namespace OCC { namespace OCC {
class SyncJournalDb; class SyncJournalDb;
/**
* Job that handle the discovering of a directory.
*
* This includes:
* - Do a DiscoverySingleDirectoryJob network job which will do a PROPFIND of this directory
* - Stat all the entries in the local file system for this directory
* - Merge all invormation (and the information from the database) in order to know what need
* to be done for every file within this directory.
* - For every sub-directory within this directory, "recursively" create a new ProcessDirectoryJob
*
* This job is tightly couple with the DiscoveryPhase class.
*
* After being start()'ed, one must call progress() on this job until it emit finished().
* This job will call DiscoveryPhase::scheduleMoreJobs when one of its sub-jobs is finished.
* DiscoveryPhase::scheduleMoreJobs is the one which will call progress().
*/
class ProcessDirectoryJob : public QObject class ProcessDirectoryJob : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -32,7 +48,7 @@ public:
NormalQuery, NormalQuery,
ParentDontExist, // Do not query this folder because it does not exist ParentDontExist, // Do not query this folder because it does not exist
ParentNotChanged, // No need to query this folder because it has not changed from what is in the DB ParentNotChanged, // No need to query this folder because it has not changed from what is in the DB
InBlackList // Do not query this folder because it is in th blacklist (remote entries only) InBlackList // Do not query this folder because it is in the blacklist (remote entries only)
}; };
Q_ENUM(QueryMode) Q_ENUM(QueryMode)
explicit ProcessDirectoryJob(const SyncFileItemPtr &dirItem, QueryMode queryLocal, QueryMode queryServer, explicit ProcessDirectoryJob(const SyncFileItemPtr &dirItem, QueryMode queryLocal, QueryMode queryServer,
@ -52,10 +68,16 @@ public:
SyncFileItemPtr _dirItem; SyncFileItemPtr _dirItem;
private: private:
/** Structure representing a path during discovery. A same path may have different value locally
* or on the server in case of renames.
*
* These strings never start or ends with slashes. They are all relative to the folder's root.
* Usually they are all the same and are even shared instance of the same QString.
*/
struct PathTuple struct PathTuple
{ {
QString _original; // Path as in the DB QString _original; // Path as in the DB (before the sync)
QString _target; // Path that will be the result after the sync QString _target; // Path that will be the result after the sync (and will be in the DB)
QString _server; // Path on the server QString _server; // Path on the server
QString _local; // Path locally QString _local; // Path locally
PathTuple addName(const QString &name) const PathTuple addName(const QString &name) const
@ -81,8 +103,12 @@ private:
void processFileFinalize(const SyncFileItemPtr &item, PathTuple, bool recurse, QueryMode recurseQueryLocal, QueryMode recurseQueryServer); void processFileFinalize(const SyncFileItemPtr &item, PathTuple, bool recurse, QueryMode recurseQueryLocal, QueryMode recurseQueryServer);
// Return false if there is an error and that a directory must not be recursively be taken /** Checks the permission for this item, if needed, change the item to a restoration item.
* @return false indicate that this is an error and if it is a directory, one should not recurse
* inside it.
*/
bool checkPermissions(const SyncFileItemPtr &item); bool checkPermissions(const SyncFileItemPtr &item);
void processBlacklisted(const PathTuple &, const LocalInfo &, const SyncJournalFileRecord &dbEntry); void processBlacklisted(const PathTuple &, const LocalInfo &, const SyncJournalFileRecord &dbEntry);
void subJobFinished(); void subJobFinished();

View file

@ -147,7 +147,9 @@ QString DiscoveryPhase::adjustRenamedPath(const QString &original) const
void DiscoveryPhase::startJob(ProcessDirectoryJob *job) void DiscoveryPhase::startJob(ProcessDirectoryJob *job)
{ {
ENFORCE(!_currentRootJob);
connect(job, &ProcessDirectoryJob::finished, this, [this, job] { connect(job, &ProcessDirectoryJob::finished, this, [this, job] {
ENFORCE(_currentRootJob == sender());
_currentRootJob = nullptr; _currentRootJob = nullptr;
if (job->_dirItem) if (job->_dirItem)
emit itemDiscovered(job->_dirItem); emit itemDiscovered(job->_dirItem);
@ -221,7 +223,7 @@ void DiscoverySingleDirectoryJob::abort()
} }
} }
static void propertyMapToFileStat(const QMap<QString, QString> &map, RemoteInfo &result) static void propertyMapToRemoteInfo(const QMap<QString, QString> &map, RemoteInfo &result)
{ {
for (auto it = map.constBegin(); it != map.constEnd(); ++it) { for (auto it = map.constBegin(); it != map.constEnd(); ++it) {
QString property = it.key(); QString property = it.key();
@ -289,7 +291,7 @@ void DiscoverySingleDirectoryJob::directoryListingIteratedSlot(QString file, con
int slash = file.lastIndexOf('/'); int slash = file.lastIndexOf('/');
result.name = file.mid(slash + 1); result.name = file.mid(slash + 1);
result.size = -1; result.size = -1;
propertyMapToFileStat(map, result); propertyMapToRemoteInfo(map, result);
if (result.isDirectory) if (result.isDirectory)
result.size = 0; result.size = 0;
if (result.size == -1 if (result.size == -1

View file

@ -41,9 +41,12 @@ class Account;
class SyncJournalDb; class SyncJournalDb;
class ProcessDirectoryJob; class ProcessDirectoryJob;
/**
* Represent all the meta-data about a file in the server
*/
struct RemoteInfo struct RemoteInfo
{ {
/** FileName of the entry (this does not contains any directory or path, just the plain name */
QString name; QString name;
QByteArray etag; QByteArray etag;
QByteArray fileId; QByteArray fileId;
@ -60,6 +63,7 @@ struct RemoteInfo
struct LocalInfo struct LocalInfo
{ {
/** FileName of the entry (this does not contains any directory or path, just the plain name */
QString name; QString name;
time_t modtime = 0; time_t modtime = 0;
int64_t size = 0; int64_t size = 0;
@ -149,6 +153,11 @@ public:
QMap<QString, SyncFileItemPtr> _deletedItem; QMap<QString, SyncFileItemPtr> _deletedItem;
QMap<QString, ProcessDirectoryJob *> _queuedDeletedDirectories; QMap<QString, ProcessDirectoryJob *> _queuedDeletedDirectories;
QMap<QString, QString> _renamedItems; // map source -> destinations QMap<QString, QString> _renamedItems; // map source -> destinations
/** Given an original path, return the target path obtained when renaming is done.
*
* Note that it only considers parent directory renames. So if A/B got renamed to C/D,
* checking A/B/file would yield C/D/file, but checking A/B would yield A/B.
*/
QString adjustRenamedPath(const QString &original) const; QString adjustRenamedPath(const QString &original) const;
void startJob(ProcessDirectoryJob *); void startJob(ProcessDirectoryJob *);

View file

@ -582,9 +582,9 @@ void SyncEngine::slotStartDiscovery()
_discoveryPhase->_localDir = _localPath; _discoveryPhase->_localDir = _localPath;
_discoveryPhase->_remoteFolder = _remotePath; _discoveryPhase->_remoteFolder = _remotePath;
_discoveryPhase->_syncOptions = _syncOptions; _discoveryPhase->_syncOptions = _syncOptions;
_discoveryPhase->_shouldDiscoverLocaly = [this](const QString &s) { return shouldDiscoverLocally(s); };
_discoveryPhase->_selectiveSyncBlackList = selectiveSyncBlackList; _discoveryPhase->_selectiveSyncBlackList = selectiveSyncBlackList;
_discoveryPhase->_selectiveSyncWhiteList = _journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList, &ok); _discoveryPhase->_selectiveSyncWhiteList = _journal->getSelectiveSyncList(SyncJournalDb::SelectiveSyncWhiteList, &ok);
_discoveryPhase->_shouldDiscoverLocaly = [this](const QString &s) { return shouldDiscoverLocally(s); };
if (!ok) { if (!ok) {
qCWarning(lcEngine) << "Unable to read selective sync list, aborting."; qCWarning(lcEngine) << "Unable to read selective sync list, aborting.";
syncError(tr("Unable to read from the sync journal.")); syncError(tr("Unable to read from the sync journal."));