diff options
author | Olivier Goffart <ogoffart@woboq.com> | 2017-12-11 21:25:51 +0300 |
---|---|---|
committer | Olivier Goffart <olivier@woboq.com> | 2017-12-14 13:56:12 +0300 |
commit | 4dc49ff3b01f196dfac0ac928688d90a001b49e8 (patch) | |
tree | 7cf9995f7c23c88e70b1b11dd05e1ddfa54ca6c0 /src/csync | |
parent | 4369853ddb21525a9b83f83ef3d44dd838a17d8d (diff) |
SyncEngine: Recover when the PUT reply (or chunkin's MOVE) is lost
This can happen if the upload of a file is finished, but we just got
disconnected right before recieving the reply containing the etag.
So nothing was save din the DB, and we are not sure if the server
recieved the file properly or not. Further local update of the file
will cause a conflict.
In order to fix this, store the checksum of the uploading file in
the uploadinfo table of the local db (even if there is no chunking
involved). And when we have a conflict, check that it is not because
of this situation by checking the entry in the uploadinfo table.
Issue #5106
Diffstat (limited to 'src/csync')
-rw-r--r-- | src/csync/csync_reconcile.cpp | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/src/csync/csync_reconcile.cpp b/src/csync/csync_reconcile.cpp index 97863fb8b..daad534ae 100644 --- a/src/csync/csync_reconcile.cpp +++ b/src/csync/csync_reconcile.cpp @@ -27,6 +27,7 @@ #include "csync_rename.h" #include "common/c_jhash.h" #include "common/asserts.h" +#include "common/syncjournalfilerecord.h" #include <QLoggingCategory> Q_LOGGING_CATEGORY(lcReconcile, "sync.csync.reconciler", QtInfoMsg) @@ -316,6 +317,35 @@ static int _csync_merge_algorithm_visitor(csync_file_stat_t *cur, CSYNC * ctx) { (ctx->current == REMOTE_REPLICA ? cur->checksumHeader : other->checksumHeader); if (!remoteChecksumHeader.isEmpty()) { is_conflict = true; + + // Do we have an UploadInfo for this? + // Maybe the Upload was completed, but the connection was broken just before + // we recieved the etag (Issue #5106) + auto up = ctx->statedb->getUploadInfo(cur->path); + if (up._valid && up._contentChecksum == remoteChecksumHeader) { + // Solve the conflict into an upload, or nothing + auto remoteNode = ctx->current == REMOTE_REPLICA ? cur : other; + auto localNode = ctx->current == REMOTE_REPLICA ? other : cur; + remoteNode->instruction = CSYNC_INSTRUCTION_NONE; + localNode->instruction = up._modtime == localNode->modtime ? CSYNC_INSTRUCTION_UPDATE_METADATA : CSYNC_INSTRUCTION_SYNC; + + // Update the etag and other server metadata in the journal already + // (We can't use a typical CSYNC_INSTRUCTION_UPDATE_METADATA because + // we must not store the size/modtime from the file system) + OCC::SyncJournalFileRecord rec; + if (ctx->statedb->getFileRecord(remoteNode->path, &rec)) { + rec._path = remoteNode->path; + rec._etag = remoteNode->etag; + rec._fileId = remoteNode->file_id; + rec._modtime = remoteNode->modtime; + rec._type = remoteNode->type; + rec._fileSize = remoteNode->size; + rec._remotePerm = remoteNode->remotePerm; + rec._checksumHeader = remoteNode->checksumHeader; + ctx->statedb->setFileRecordMetadata(rec); + } + break; + } } // SO: If there is no checksum, we can have !is_conflict here |