opt._parallelNetworkJobs = _accountState->account()->isHttp2Supported() ? 20 : 6;
// Chunk V2: Size of chunks must be between 5MB and 5GB, except for the last chunk which can be smaller
- opt._minChunkSize = qMin(cfgFile.minChunkSize(), 5LL * 1000LL * 1000LL);
- opt._maxChunkSize = qMax(cfgFile.maxChunkSize(), 5LL * 1000LL * 1000LL);
- opt._initialChunkSize = qBound(opt._minChunkSize, cfgFile.chunkSize(), opt._maxChunkSize);
+ opt.setMinChunkSize(cfgFile.minChunkSize());
+ opt.setMaxChunkSize(cfgFile.maxChunkSize());
+ opt._initialChunkSize = ::qBound(opt.minChunkSize(), cfgFile.chunkSize(), opt.maxChunkSize());
opt._targetChunkUploadDuration = cfgFile.targetChunkUploadDuration();
opt.fillFromEnvironmentVariables();
return true;
};
- return account()->capabilities().bulkUpload() && !_scheduleDelayedTasks && !item->isEncrypted() && _syncOptions._minChunkSize > item->_size && !isInBulkUploadBlackList(item->_file) && !checkFileShouldBeEncrypted(item);
+ return account()->capabilities().bulkUpload() && !_scheduleDelayedTasks && !item->isEncrypted() && _syncOptions.minChunkSize() > item->_size
+ && !isInBulkUploadBlackList(item->_file) && !checkFileShouldBeEncrypted(item);
}
void OwncloudPropagator::setScheduleDelayedTasks(bool active)
qint64 targetSize = propagator()->_chunkSize / 2 + predictedGoodSize / 2;
// Adjust the dynamic chunk size _chunkSize used for sizing of the item's chunks to be send
- propagator()->_chunkSize = qBound(
- propagator()->syncOptions()._minChunkSize,
- targetSize,
- propagator()->syncOptions()._maxChunkSize);
+ propagator()->_chunkSize = ::qBound(propagator()->syncOptions().minChunkSize(), targetSize, propagator()->syncOptions().maxChunkSize());
qCInfo(lcPropagateUploadNG) << "Chunked upload of" << _currentChunkSize << "bytes took" << uploadTime.count()
<< "ms, desired is" << targetDuration.count() << "ms, expected good chunk size is"
SyncOptions::~SyncOptions() = default;
+qint64 SyncOptions::minChunkSize() const
+{
+ return _minChunkSize;
+}
+
+void SyncOptions::setMinChunkSize(const qint64 minChunkSize)
+{
+ _minChunkSize = ::qBound(_minChunkSize, minChunkSize, _maxChunkSize);
+}
+
+qint64 SyncOptions::maxChunkSize() const
+{
+ return _maxChunkSize;
+}
+
+void SyncOptions::setMaxChunkSize(const qint64 maxChunkSize)
+{
+ _maxChunkSize = ::qBound(_minChunkSize, maxChunkSize, _maxChunkSize);
+}
+
void SyncOptions::fillFromEnvironmentVariables()
{
QByteArray chunkSizeEnv = qgetenv("OWNCLOUD_CHUNK_SIZE");
*/
qint64 _initialChunkSize = 10 * 1000 * 1000; // 10MB
- /** The minimum chunk size in bytes for chunked uploads */
- qint64 _minChunkSize = 1 * 1000 * 1000; // 1MB
-
- /** The maximum chunk size in bytes for chunked uploads */
- qint64 _maxChunkSize = 1000 * 1000 * 1000; // 1000MB
-
/** The target duration of chunk uploads for dynamic chunk sizing.
*
* Set to 0 it will disable dynamic chunk sizing.
/** The maximum number of active jobs in parallel */
int _parallelNetworkJobs = 6;
+ static constexpr auto chunkV2MinChunkSize = 5LL * 1000LL * 1000LL; // 5 MB
+ static constexpr auto chunkV2MaxChunkSize = 5LL * 1000LL * 1000LL * 1000LL; // 5 GB
+
+ /** The minimum chunk size in bytes for chunked uploads */
+ qint64 minChunkSize() const;
+ void setMinChunkSize(const qint64 minChunkSize);
+
+ /** The maximum chunk size in bytes for chunked uploads */
+ qint64 maxChunkSize() const;
+ void setMaxChunkSize(const qint64 maxChunkSize);
+
/** Reads settings from env vars where available.
*
* Currently reads _initialChunkSize, _minChunkSize, _maxChunkSize,
* Invalid pattern by default.
*/
QRegularExpression _fileRegex = QRegularExpression(QStringLiteral("("));
+
+ qint64 _minChunkSize = chunkV2MinChunkSize;
+ qint64 _maxChunkSize = chunkV2MaxChunkSize;
};
}
fakeFolder.syncEngine().account()->setCapabilities({ { "dav", QVariantMap{ { "chunking", "1.0" } } } });
// Reduce max chunk size a bit so we get more chunks
SyncOptions options;
- options._maxChunkSize = 20 * 1000;
+ options.setMaxChunkSize(20 * 1000);
fakeFolder.syncEngine().setSyncOptions(options);
int nGET = 0;
testCases[file] = { std::move(cb) };
};
fakeFolder.localModifier().mkdir("success");
- insertFile("success/chunked_success", options._maxChunkSize * 3, successCallback);
+ insertFile("success/chunked_success", options.maxChunkSize() * 3, successCallback);
insertFile("success/single_success", 300, successCallback);
- insertFile("success/chunked_patience", options._maxChunkSize * 3,
- waitAndChain(waitAndChain(successCallback)));
+ insertFile("success/chunked_patience", options.maxChunkSize() * 3, waitAndChain(waitAndChain(successCallback)));
insertFile("success/single_patience", 300,
waitAndChain(waitAndChain(successCallback)));
fakeFolder.localModifier().mkdir("err");
- insertFile("err/chunked_error", options._maxChunkSize * 3, errorCallback);
+ insertFile("err/chunked_error", options.maxChunkSize() * 3, errorCallback);
insertFile("err/single_error", 300, errorCallback);
- insertFile("err/chunked_error2", options._maxChunkSize * 3, waitAndChain(errorCallback));
+ insertFile("err/chunked_error2", options.maxChunkSize() * 3, waitAndChain(errorCallback));
insertFile("err/single_error2", 300, waitAndChain(errorCallback));
// First sync should finish by itself.
fakeFolder.localModifier().mkdir("waiting");
insertFile("waiting/small", 300, waitForeverCallback);
insertFile("waiting/willNotConflict", 300, waitForeverCallback);
- insertFile("waiting/big", options._maxChunkSize * 3,
- waitAndChain(waitAndChain([&](TestCase *tc, const QNetworkRequest &request) {
- QTimer::singleShot(0, &fakeFolder.syncEngine(), &SyncEngine::abort);
- return waitAndChain(waitForeverCallback)(tc, request);
- })));
+ insertFile("waiting/big", options.maxChunkSize() * 3, waitAndChain(waitAndChain([&](TestCase *tc, const QNetworkRequest &request) {
+ QTimer::singleShot(0, &fakeFolder.syncEngine(), &SyncEngine::abort);
+ return waitAndChain(waitForeverCallback)(tc, request);
+ })));
QVERIFY(fakeFolder.syncJournal().wipeErrorBlacklist() != -1);
static void setChunkSize(SyncEngine &engine, qint64 size)
{
SyncOptions options;
- options._maxChunkSize = size;
+ options.setMaxChunkSize(size);
+ options.setMinChunkSize(size);
options._initialChunkSize = size;
- options._minChunkSize = size;
engine.setSyncOptions(options);
}
void testVeryBigFiles() {
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
fakeFolder.syncEngine().account()->setCapabilities({ { "dav", QVariantMap{ {"chunking", "1.0"} } } });
+
+ // Dynamic chunk sizing tries to go for biggest chunks possible depending on upload speed.
+ // In the tests this is immediate, so we need to give a file larger than the max chunk size
+ // and cap the max chunk size a bit
+ auto opts = fakeFolder.syncEngine().syncOptions();
+ opts.setMaxChunkSize(500LL * 1000LL * 1000LL); // 500MB
+ fakeFolder.syncEngine().setSyncOptions(opts);
const qint64 size = 2.5 * 1024 * 1024 * 1024; // 2.5 GiB
// Partial upload of big files
QCOMPARE(fakeFolder.uploadState().children.count(), 1);
QCOMPARE(fakeFolder.uploadState().children.first().name, chunkingId);
-
// Upload another file again, this time without interruption
fakeFolder.localModifier().appendByte("A/a0");
QVERIFY(fakeFolder.syncOnce());
FakeFolder fakeFolder{ FileInfo{} };
SyncOptions options;
options._initialChunkSize = 10;
- options._maxChunkSize = 10;
- options._minChunkSize = 10;
+ options.setMaxChunkSize(10);
+ options.setMinChunkSize(10);
fakeFolder.syncEngine().setSyncOptions(options);
QObject parent;