csync: Use an explicit instruction for should_update_metadata

The current way of tracking the need to update the metadata without
propagation using a separate flag makes it difficult to track
priorities between the local and remote tree. The logic is also
difficult to logically cover since the possibilities matrix isn't
100% covered, leaving the flag only used in a few situations
(mostly involving folders, but not only).

The reason we need to change this is to be able to track the sync
state of files for overlay icons. The instruction alone can't be
used since CSYNC_INSTRUCTION_SYNC is used for folders even though
they won't be propagated. Removing this logic is however not possible
without using something else than CSYNC_INSTRUCTION_NONE since too
many codepath interpret (rightfully) this as meaning "nothing to do".

This patch adds a new CSYNC_INSTRUCTION_UPDATE_METADATA instruction
to let the update and reconcile steps tell the SyncEngine to update
the metadata of a file without any propagation. Other flags are left
to be interpretted by the implementation as implicitly needing
metadata update or not, as this was already the case for most file
propagation jobs. For example, CSYNC_INSTRUCTION_NEW for directories
now also implicitly update the metadata.

Since it's not impossible for folders to emit CSYNC_INSTRUCTION_SYNC
or CSYNC_INSTRUCTION_CONFLICT, the corresponding code paths in the
sync engine have been removed.

Since the reconcile step can now know if the local tree needs metadata
update while the remote side might want propagation, the
localMetadataUpdate logic in SyncEngine::treewalkFile now simply use
a CSYNC_INSTRUCTION_UPDATE_METADATA for the local side, which is now
implemented as a different database query.
Esse commit está contido em:
Jocelyn Turcotte
2016-08-15 14:17:51 +02:00
commit e974771796
14 arquivos alterados com 174 adições e 147 exclusões
+36 -43
Ver Arquivo
@@ -395,8 +395,6 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
item->_remotePerm = QByteArray(file->remotePerm);
}
item->_should_update_metadata = item->_should_update_metadata || file->should_update_metadata;
/* The flag "serverHasIgnoredFiles" is true if item in question is a directory
* that has children which are ignored in sync, either because the files are
* matched by an ignore pattern, or because they are hidden.
@@ -514,10 +512,23 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
int re = 0;
switch(file->instruction) {
case CSYNC_INSTRUCTION_NONE: {
if (remote && item->_should_update_metadata && !isDirectory && item->_instruction == CSYNC_INSTRUCTION_NONE) {
// Any files that are instruction NONE?
if (!isDirectory && file->other.instruction == CSYNC_INSTRUCTION_NONE) {
_hasNoneFiles = true;
}
// No syncing or update to be done.
return re;
}
case CSYNC_INSTRUCTION_UPDATE_METADATA:
dir = SyncFileItem::None;
// For directories, metadata-only updates will be done after all their files are propagated.
if (!isDirectory) {
item->_isDirectory = isDirectory;
emit syncItemDiscovered(*item);
// Update the database now already: New remote fileid or Etag or RemotePerm
// Or for files that were detected as "resolved conflict".
// Or a local inode/mtime change (see localMetadataUpdate below)
// Or a local inode/mtime change
// In case of "resolved conflict": there should have been a conflict because they
// both were new, or both had their local mtime or remote etag modified, but the
@@ -529,47 +540,33 @@ int SyncEngine::treewalkFile( TREE_WALK_FILE *file, bool remote )
// quick to do and we don't want to create a potentially large number of
// mini-jobs later on, we just update metadata right now.
QString filePath = _localPath + item->_file;
if (remote) {
QString filePath = _localPath + item->_file;
// Even if the mtime is different on the server, we always want to keep the mtime from
// the file system in the DB, this is to avoid spurious upload on the next sync
item->_modtime = file->other.modtime;
// same for the size
item->_size = file->other.size;
// Even if the mtime is different on the server, we always want to keep the mtime from
// the file system in the DB, this is to avoid spurious upload on the next sync
item->_modtime = file->other.modtime;
// same for the size
item->_size = file->other.size;
// If the 'W' remote permission changed, update the local filesystem
SyncJournalFileRecord prev = _journal->getFileRecord(item->_file);
if (prev.isValid() && prev._remotePerm.contains('W') != item->_remotePerm.contains('W')) {
const bool isReadOnly = !item->_remotePerm.contains('W');
FileSystem::setFileReadOnlyWeak(filePath, isReadOnly);
// If the 'W' remote permission changed, update the local filesystem
SyncJournalFileRecord prev = _journal->getFileRecord(item->_file);
if (prev.isValid() && prev._remotePerm.contains('W') != item->_remotePerm.contains('W')) {
const bool isReadOnly = !item->_remotePerm.contains('W');
FileSystem::setFileReadOnlyWeak(filePath, isReadOnly);
}
_journal->setFileRecordMetadata(SyncJournalFileRecord(*item, filePath));
} else {
// The local tree is walked first and doesn't have all the info from the server.
// Update only outdated data from the disk.
_journal->updateLocalMetadata(item->_file, item->_modtime, item->_size, item->_inode);
}
_journal->setFileRecordMetadata(SyncJournalFileRecord(*item, filePath));
item->_should_update_metadata = false;
// Technically we're done with this item. See localMetadataUpdate hack below.
_syncItemMap.remove(key);
}
// Any files that are instruction NONE?
if (!isDirectory && file->other.instruction == CSYNC_INSTRUCTION_NONE) {
_hasNoneFiles = true;
}
// We want to still update etags of directories, other NONE
// items can be ignored.
bool directoryEtagUpdate = isDirectory && file->should_update_metadata;
bool localMetadataUpdate = !remote && file->should_update_metadata;
if (!directoryEtagUpdate) {
item->_isDirectory = isDirectory;
if (localMetadataUpdate) {
// Hack, we want a local metadata update to happen, but only if the
// remote tree doesn't ask us to do some kind of propagation.
_syncItemMap.insert(key, item);
}
emit syncItemDiscovered(*item);
// Technically we're done with this item.
return re;
}
break;
}
case CSYNC_INSTRUCTION_RENAME:
dir = !remote ? SyncFileItem::Down : SyncFileItem::Up;
item->_renameTarget = renameTarget;
@@ -1180,9 +1177,8 @@ void SyncEngine::checkForPermission()
if (perms.isNull()) {
// No permissions set
break;
} if (!(*it)->_isDirectory && !perms.contains("W")) {
} if (!perms.contains("W")) {
qDebug() << "checkForPermission: RESTORING" << (*it)->_file;
(*it)->_should_update_metadata = true;
(*it)->_instruction = CSYNC_INSTRUCTION_CONFLICT;
(*it)->_direction = SyncFileItem::Down;
(*it)->_isRestoration = true;
@@ -1204,7 +1200,6 @@ void SyncEngine::checkForPermission()
}
if (!perms.contains("D")) {
qDebug() << "checkForPermission: RESTORING" << (*it)->_file;
(*it)->_should_update_metadata = true;
(*it)->_instruction = CSYNC_INSTRUCTION_NEW;
(*it)->_direction = SyncFileItem::Down;
(*it)->_isRestoration = true;
@@ -1223,7 +1218,6 @@ void SyncEngine::checkForPermission()
}
qDebug() << "checkForPermission: RESTORING" << (*it)->_file;
(*it)->_should_update_metadata = true;
(*it)->_instruction = CSYNC_INSTRUCTION_NEW;
(*it)->_direction = SyncFileItem::Down;
@@ -1372,7 +1366,6 @@ void SyncEngine::restoreOldFiles()
break;
case CSYNC_INSTRUCTION_REMOVE:
qDebug() << "restoreOldFiles: RESTORING" << (*it)->_file;
(*it)->_should_update_metadata = true;
(*it)->_instruction = CSYNC_INSTRUCTION_NEW;
(*it)->_direction = SyncFileItem::Up;
break;