namespace OCC {
+qint64 criticalFreeSpaceLimit()
+{
+ qint64 value = 50 * 1000 * 1000LL;
+
+ static bool hasEnv = false;
+ static qint64 env = qgetenv("OWNCLOUD_CRITICAL_FREE_SPACE").toLongLong(&hasEnv);
+ if (hasEnv) {
+ value = env;
+ }
+
+ return qBound(0LL, value, freeSpaceLimit());
+}
+
+qint64 freeSpaceLimit()
+{
+ qint64 value = 250 * 1000 * 1000LL;
+
+ static bool hasEnv = false;
+ static qint64 env = qgetenv("OWNCLOUD_FREE_SPACE").toLongLong(&hasEnv);
+ if (hasEnv) {
+ value = env;
+ }
+
+ return value;
+}
+
OwncloudPropagator::~OwncloudPropagator()
{}
return _account;
}
+OwncloudPropagator::DiskSpaceResult OwncloudPropagator::diskSpaceCheck() const
+{
+ const qint64 freeBytes = Utility::freeDiskSpace(_localDir);
+ if (freeBytes < 0) {
+ return DiskSpaceOk;
+ }
+
+ if (freeBytes < criticalFreeSpaceLimit()) {
+ return DiskSpaceCritical;
+ }
+
+ if (freeBytes - _rootJob->committedDiskSpace() < freeSpaceLimit()) {
+ return DiskSpaceFailure;
+ }
+
+ return DiskSpaceOk;
+}
+
// ================================================================================
PropagatorJob::JobParallelism PropagateDirectory::parallelism()
emit finished(_hasError == SyncFileItem::NoStatus ? SyncFileItem::Success : _hasError);
}
+qint64 PropagateDirectory::committedDiskSpace() const
+{
+ qint64 needed = 0;
+ foreach (PropagatorJob* job, _subJobs) {
+ needed += job->committedDiskSpace();
+ }
+ return needed;
+}
+
CleanupPollsJob::~CleanupPollsJob()
{}
namespace OCC {
+/** Free disk space threshold below which syncs will abort and not even start.
+ */
+qint64 criticalFreeSpaceLimit();
+
+/** The client will not intentionally reduce the available free disk space below
+ * this limit.
+ *
+ * Uploads will still run and downloads that are small enough will continue too.
+ */
+qint64 freeSpaceLimit();
+
class SyncJournalDb;
class OwncloudPropagator;
virtual JobParallelism parallelism() { return FullParallelism; }
+ /** The space that the running jobs need to complete but don't actually use yet.
+ *
+ * Note that this does *not* include the disk space that's already
+ * in use by running jobs for things like a download-in-progress.
+ */
+ virtual qint64 committedDiskSpace() const { return 0; }
+
public slots:
virtual void abort() {}
void finalize();
+ qint64 committedDiskSpace() const Q_DECL_OVERRIDE;
+
private slots:
bool possiblyRunNextJob(PropagatorJob *next) {
if (next->_state == NotYetStarted) {
AccountPtr account() const;
+ enum DiskSpaceResult
+ {
+ DiskSpaceOk,
+ DiskSpaceFailure,
+ DiskSpaceCritical
+ };
+
+ /** Checks whether there's enough disk space available to complete
+ * all jobs that are currently running.
+ */
+ DiskSpaceResult diskSpaceCheck() const;
private slots:
FileSystem::setFileHidden(_tmpFile.fileName(), true);
+ _resumeStart = _tmpFile.size();
+ if (_resumeStart > 0) {
+ if (_resumeStart == _item->_size) {
+ qDebug() << "File is already complete, no need to download";
+ _tmpFile.close();
+ downloadFinished();
+ return;
+ }
+ }
+
+ // If there's not enough space to fully download this file, stop.
+ const auto diskSpaceResult = _propagator->diskSpaceCheck();
+ if (diskSpaceResult == OwncloudPropagator::DiskSpaceFailure) {
+ done(SyncFileItem::NormalError,
+ tr("The download would reduce free disk space below %1").arg(
+ Utility::octetsToString(freeSpaceLimit())));
+ return;
+ } else if (diskSpaceResult == OwncloudPropagator::DiskSpaceCritical) {
+ done(SyncFileItem::FatalError,
+ tr("Free space on disk is less than %1").arg(
+ Utility::octetsToString(criticalFreeSpaceLimit())));
+ return;
+ }
+
{
SyncJournalDb::DownloadInfo pi;
pi._etag = _item->_etag;
_propagator->_journal->commit("download file start");
}
-
QMap<QByteArray, QByteArray> headers;
- quint64 startSize = _tmpFile.size();
- if (startSize > 0) {
- if (startSize == _item->_size) {
- qDebug() << "File is already complete, no need to download";
- _tmpFile.close();
- downloadFinished();
- return;
- }
- }
-
if (_item->_directDownloadUrl.isEmpty()) {
// Normal job, download from oC instance
_job = new GETFileJob(_propagator->account(),
_propagator->_remoteFolder + _item->_file,
- &_tmpFile, headers, expectedEtagForResume, startSize);
+ &_tmpFile, headers, expectedEtagForResume, _resumeStart);
} else {
// We were provided a direct URL, use that one
qDebug() << Q_FUNC_INFO << "directDownloadUrl given for " << _item->_file << _item->_directDownloadUrl;
QUrl url = QUrl::fromUserInput(_item->_directDownloadUrl);
_job = new GETFileJob(_propagator->account(),
url,
- &_tmpFile, headers, expectedEtagForResume, startSize);
+ &_tmpFile, headers, expectedEtagForResume, _resumeStart);
}
_job->setBandwidthManager(&_propagator->_bandwidthManager);
connect(_job, SIGNAL(finishedSignal()), this, SLOT(slotGetFinished()));
_job->start();
}
+qint64 PropagateDownloadFileQNAM::committedDiskSpace() const
+{
+ if (_state == Running) {
+ return qBound(0ULL, _item->_size - _resumeStart - _downloadProgress, _item->_size);
+ }
+ return 0;
+}
+
const char owncloudCustomSoftErrorStringC[] = "owncloud-custom-soft-error-string";
void PropagateDownloadFileQNAM::slotGetFinished()
{
void PropagateDownloadFileQNAM::slotDownloadProgress(qint64 received, qint64)
{
if (!_job) return;
- emit progress(*_item, received + _job->resumeStart());
+ _downloadProgress = received;
+ emit progress(*_item, _resumeStart + received);
}
Q_OBJECT
public:
PropagateDownloadFileQNAM(OwncloudPropagator* propagator,const SyncFileItemPtr& item)
- : PropagateItemJob(propagator, item) {}
+ : PropagateItemJob(propagator, item), _resumeStart(0), _downloadProgress(0) {}
void start() Q_DECL_OVERRIDE;
+ qint64 committedDiskSpace() const Q_DECL_OVERRIDE;
private slots:
void slotGetFinished();
void slotChecksumFail( const QString& errMsg );
private:
+ quint64 _resumeStart;
+ qint64 _downloadProgress;
QPointer<GETFileJob> _job;
QFile _tmpFile;
};
namespace OCC {
-/* The minimum amount of space required to start a sync run */
-static qint64 minFreeSpace()
-{
- static bool ok = false;
- static qint64 freeSpace = qgetenv("OWNCLOUD_MIN_FREE_SPACE").toLongLong(&ok);
- if (ok) {
- return freeSpace;
- }
-
- return 250 * 1000 * 1000LL;
-}
-
bool SyncEngine::_syncRunning = false;
SyncEngine::SyncEngine(AccountPtr account, CSYNC *ctx, const QString& localPath,
}
// Check free size on disk first.
- const qint64 minFree = minFreeSpace();
+ const qint64 minFree = criticalFreeSpaceLimit();
const qint64 freeBytes = Utility::freeDiskSpace(_localPath);
if (freeBytes >= 0) {
qDebug() << "There are" << freeBytes << "bytes available at" << _localPath