Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove file from bulk upload black list only when upload succeeded. #5998

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 36 additions & 6 deletions src/libsync/bulkpropagatorjob.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in src/libsync/bulkpropagatorjob.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on src/libsync/bulkpropagatorjob.cpp

File src/libsync/bulkpropagatorjob.cpp does not conform to Custom style guidelines. (lines 87, 120, 123)
* Copyright 2021 (c) Matthieu Gallien <matthieu.gallien@nextcloud.com>
*
* This program is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -70,6 +70,7 @@
BulkPropagatorJob::BulkPropagatorJob(OwncloudPropagator *propagator, const std::deque<SyncFileItemPtr> &items)
: PropagatorJob(propagator)
, _items(items)
, _currentBatchSize(batchSize)
{
_filesToUpload.reserve(batchSize);
_pendingChecksumFiles.reserve(batchSize);
Expand All @@ -83,7 +84,7 @@

_state = Running;

for(auto i = 0; i < batchSize && !_items.empty(); ++i) {
for(auto i = 0; i < _currentBatchSize && !_items.empty(); ++i) {
const auto currentItem = _items.front();
_items.pop_front();
_pendingChecksumFiles.insert(currentItem->_file);
Expand All @@ -107,6 +108,29 @@
return _items.empty() && _filesToUpload.empty();
}

bool BulkPropagatorJob::handleBatchSize()
{
// no error, no batch size to change
if (_finalStatus == SyncFileItem::Success || _finalStatus == SyncFileItem::NoStatus) {
qCDebug(lcBulkPropagatorJob) << "No error, no need to change the bulk upload batch size!";
return true;
}

// change batch size before trying it again
const auto halfBatchSize = batchSize/2;
camilasan marked this conversation as resolved.
Show resolved Hide resolved

// we already tried to upload with half of the batch size
if(_currentBatchSize == halfBatchSize) {
qCDebug(lcBulkPropagatorJob) << "There was another error, stop syncing now!";
return false;
}

// try to upload with half of the batch size
_currentBatchSize = halfBatchSize;
qCDebug(lcBulkPropagatorJob) << "There was an error, sync again with bulk upload batch size cut to half!";
camilasan marked this conversation as resolved.
Show resolved Hide resolved
return true;
}

PropagatorJob::JobParallelism BulkPropagatorJob::parallelism() const
{
return PropagatorJob::JobParallelism::FullParallelism;
Expand Down Expand Up @@ -254,13 +278,16 @@
// just wait for the other job to finish.
return;
}

qCInfo(lcBulkPropagatorJob) << "final status" << _finalStatus;
emit finished(_finalStatus);
propagator()->scheduleNextJob();
} else {
scheduleSelfOrChild();
if (handleBatchSize()) {
scheduleSelfOrChild();
return;
}
}

qCInfo(lcBulkPropagatorJob) << "final status" << _finalStatus;
emit finished(_finalStatus);
propagator()->scheduleNextJob();
}

void BulkPropagatorJob::slotComputeTransmissionChecksum(SyncFileItemPtr item,
Expand Down Expand Up @@ -374,6 +401,9 @@

singleFile._item->_status = SyncFileItem::Success;

// upload succeeded, so remove from black list
propagator()->removeFromBulkUploadBlackList(singleFile._item->_file);

// Check the file again post upload.
// Two cases must be considered separately: If the upload is finished,
// the file is on the server and has a changed ETag. In that case,
Expand Down
3 changes: 3 additions & 0 deletions src/libsync/bulkpropagatorjob.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ private slots:

void checkPropagationIsDone();

bool handleBatchSize();

std::deque<SyncFileItemPtr> _items;

QVector<AbstractNetworkJob *> _jobs; /// network jobs that are currently in transit
Expand All @@ -166,6 +168,7 @@ private slots:
qint64 _sentTotal = 0;

SyncFileItem::Status _finalStatus = SyncFileItem::Status::NoStatus;
int _currentBatchSize = 0;
};

}
5 changes: 2 additions & 3 deletions src/libsync/owncloudpropagator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,8 +428,6 @@ std::unique_ptr<PropagateUploadFileCommon> OwncloudPropagator::createUploadJob(S

job->setDeleteExisting(deleteExisting);

removeFromBulkUploadBlackList(item->_file);

return job;
}

Expand Down Expand Up @@ -1329,8 +1327,9 @@ void PropagatorCompositeJob::finalize()
{
// The propagator will do parallel scheduling and this could be posted
// multiple times on the event loop, ignore the duplicate calls.
if (_state == Finished)
if (_state == Finished) {
return;
}

_state = Finished;
emit finished(_hasError == SyncFileItem::NoStatus ? SyncFileItem::Success : _hasError);
Expand Down
78 changes: 78 additions & 0 deletions test/testsyncengine.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*

Check notice on line 1 in test/testsyncengine.cpp

View workflow job for this annotation

GitHub Actions / build

Run clang-format on test/testsyncengine.cpp

File test/testsyncengine.cpp does not conform to Custom style guidelines. (lines 1091, 1092, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1122, 1127, 1128, 1129, 1133, 1135, 1141, 1151)
* This software is in the public domain, furnished "as is", without technical
* support, and with no warranty, express or implied, as to its usefulness for
* any purpose.
Expand Down Expand Up @@ -1086,6 +1086,84 @@
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
}

void testNetworkErrorsWithSmallerBatchSizes()
{
FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
fakeFolder.syncEngine().account()->setCapabilities({ { "dav", QVariantMap{ {"bulkupload", "1.0"} } } });

int nPUT = 0;
int nPOST = 0;
fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData) -> QNetworkReply * {
auto contentType = request.header(QNetworkRequest::ContentTypeHeader).toString();
if (op == QNetworkAccessManager::PostOperation) {
++nPOST;
if (contentType.startsWith(QStringLiteral("multipart/related; boundary="))) {
auto jsonReplyObject = fakeFolder.forEachReplyPart(outgoingData, contentType, [] (const QMap<QString, QByteArray> &allHeaders) -> QJsonObject {
auto reply = QJsonObject{};
const auto fileName = allHeaders[QStringLiteral("X-File-Path")];
if(fileName.endsWith("B/small30") ||
fileName.endsWith("B/small60") ||
fileName.endsWith("B/big30") ||
fileName.endsWith("B/big60")) {
reply.insert(QStringLiteral("error"), true);
reply.insert(QStringLiteral("etag"), {});
return reply;
} else {
reply.insert(QStringLiteral("error"), false);
reply.insert(QStringLiteral("etag"), {});
}
return reply;
});
if (jsonReplyObject.size()) {
auto jsonReply = QJsonDocument{};
jsonReply.setObject(jsonReplyObject);
return new FakeJsonErrorReply{op, request, this, 200, jsonReply};
}
return nullptr;
}
} else if (op == QNetworkAccessManager::PutOperation) {
++nPUT;
const auto fileName = getFilePathFromUrl(request.url());
if (fileName.endsWith("B/small30") ||
fileName.endsWith("B/small60") ||
fileName.endsWith("B/big30") ||
fileName.endsWith("B/big60")) {
return new FakeErrorReply(op, request, this, 504);
}
return nullptr;
}
return nullptr;
});

const auto smallSize = 0.5 * 1000 * 1000;
const auto bigSize = 10 * 1000 * 1000;

for(auto i = 0 ; i < 120; ++i) {
fakeFolder.localModifier().insert(QString("A/small%1").arg(i), smallSize);
}

QVERIFY(fakeFolder.syncOnce());
QCOMPARE(nPUT, 0);
QCOMPARE(nPOST, 2);
nPUT = 0;
nPOST = 0;

for(auto i = 0 ; i < 120; ++i) {
fakeFolder.localModifier().insert(QString("B/small%1").arg(i), smallSize);
fakeFolder.localModifier().insert(QString("B/big%1").arg(i), bigSize);
}

QVERIFY(!fakeFolder.syncOnce());
QCOMPARE(nPUT, 120);
QCOMPARE(nPOST, 2);
nPUT = 0;
nPOST = 0;

QVERIFY(!fakeFolder.syncOnce());
QCOMPARE(nPUT, 2);
QCOMPARE(nPOST, 0);
}

void testRemoteMoveFailedInsufficientStorageLocalMoveRolledBack()
{
FakeFolder fakeFolder{FileInfo{}};
Expand Down
Loading