// Delete the job and remove it from our list of jobs.
subJob->deleteLater();
- bool wasFirstJob = false;
- if (subJob == _firstJob.data()) {
- wasFirstJob = true;
- _firstJob.take();
+ int i = _runningJobs.indexOf(subJob);
+ ASSERT(i >= 0);
+ _runningJobs.remove(i);
+
+ if (status == SyncFileItem::FatalError
+ || status == SyncFileItem::NormalError
+ || status == SyncFileItem::SoftError) {
+ _hasError = status;
+ }
+
+ if (_jobsToDo.isEmpty() && _tasksToDo.isEmpty() && _runningJobs.isEmpty()) {
+ finalize();
} else {
- int i = _subJobs.indexOf(subJob);
- // Shouldn't happen but could be -1 if finished was emitted twice for a job.
- ASSERT(i >= 0);
- if (i >= 0)
- _subJobs.remove(i);
+ propagator()->scheduleNextJob();
+ }
+}
+
+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)
+ return;
+
+ _state = Finished;
+ emit finished(_hasError == SyncFileItem::NoStatus ? SyncFileItem::Success : _hasError);
+}
+
+qint64 PropagatorCompositeJob::committedDiskSpace() const
+{
+ qint64 needed = 0;
+ foreach (PropagatorJob* job, _runningJobs) {
+ needed += job->committedDiskSpace();
+ }
+ return needed;
+}
+
+// ================================================================================
+
+PropagateDirectory::PropagateDirectory(OwncloudPropagator *propagator, const SyncFileItemPtr &item)
+ : PropagatorJob(propagator)
+ , _item(item)
+ , _firstJob(propagator->createJob(item))
+ , _subJobs(propagator)
+{
+ if (_firstJob) {
+ connect(_firstJob.data(), SIGNAL(finished(SyncFileItem::Status)), this, SLOT(slotFirstJobFinished(SyncFileItem::Status)));
+ }
+ connect(&_subJobs, SIGNAL(finished(SyncFileItem::Status)), this, SLOT(slotSubJobsFinished(SyncFileItem::Status)));
+}
+
+PropagatorJob::JobParallelism PropagateDirectory::parallelism()
+{
+ // If any of the non-finished sub jobs is not parallel, we have to wait
+ if (_firstJob && _firstJob->parallelism() != FullParallelism) {
+ return WaitForFinished;
+ }
+ if (_subJobs.parallelism() != FullParallelism) {
+ return WaitForFinished;
+ }
+ return FullParallelism;
+}
+
+
+bool PropagateDirectory::scheduleSelfOrChild()
+{
+ if (_state == Finished) {
+ return false;
+ }
+
+ if (_state == NotYetStarted) {
+ _state = Running;
}
- if (status == SyncFileItem::FatalError ||
- (wasFirstJob && status != SyncFileItem::Success && status != SyncFileItem::Restoration)) {
+ if (_firstJob && _firstJob->_state == NotYetStarted) {
+ return _firstJob->scheduleSelfOrChild();
+ }
+
+ if (_firstJob && _firstJob->_state == Running) {
+ // Don't schedule any more job until this is done.
+ return false;
+ }
+
+ return _subJobs.scheduleSelfOrChild();
+
+}
+
+void PropagateDirectory::slotFirstJobFinished(SyncFileItem::Status status)
+{
+ _firstJob.take()->deleteLater();
+
+ if (status != SyncFileItem::Success && status != SyncFileItem::Restoration) {
- abort();
- _state = Finished;
- emit finished(status);
+ if (_state != Finished) {
+ abort();
+ _state = Finished;
+ emit finished(status);
+ }
return;
- } else if (status == SyncFileItem::NormalError || status == SyncFileItem::SoftError) {
- _hasError = status;
}
- // We finished processing all the jobs
- // check if we finished
- if (!_firstJob && _subJobs.isEmpty()) {
- finalize();
- } else {
- emit ready();
- }
+ propagator()->scheduleNextJob();
}
-void PropagateDirectory::finalize()
+void PropagateDirectory::slotSubJobsFinished(SyncFileItem::Status status)
{
- if (_state == Finished)
- return;
-
- bool ok = true;
- if (!_item->isEmpty() && _hasError == SyncFileItem::NoStatus) {
+ if (!_item->isEmpty() && status == SyncFileItem::Success) {
if( !_item->_renameTarget.isEmpty() ) {
if(_item->_instruction == CSYNC_INSTRUCTION_RENAME
&& _item->_originalFile != _item->_renameTarget) {