diff options
author | Adam Szmigin <smidge@xsco.net> | 2020-05-10 22:42:26 +0100 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2020-06-05 10:03:57 +0200 |
commit | dae602b16661982a511a8d87f9b72844e9ffa147 (patch) | |
tree | 69d2da1d7ee4aed3041c5767ec98dc60e7fc7655 | |
parent | a5c345260b8518aec0c87cfecb561cc4ffbb6f54 (diff) |
Export tracks on worker thread, progress dialog fixed
-rw-r--r-- | src/library/export/engineprimeexportjob.cpp | 73 | ||||
-rw-r--r-- | src/library/export/engineprimeexportjob.h | 6 | ||||
-rw-r--r-- | src/library/export/libraryexporter.cpp | 3 |
3 files changed, 59 insertions, 23 deletions
diff --git a/src/library/export/engineprimeexportjob.cpp b/src/library/export/engineprimeexportjob.cpp index 0d5600f051..b2e8fa0d1b 100644 --- a/src/library/export/engineprimeexportjob.cpp +++ b/src/library/export/engineprimeexportjob.cpp @@ -231,8 +231,6 @@ void exportMetadata(djinterop::database& db, qInfo() << "No waveform data found for track" << pTrack->getId() << "(" << pTrack->getFileInfo().fileName() << ")"; } - - qInfo() << "Wrote all meta-data for track"; } void exportTrack(TrackCollection& trackCollection, @@ -293,24 +291,26 @@ EnginePrimeExportJob::EnginePrimeExportJob(QObject* parent, TrackLoader& trackLoader, EnginePrimeExportRequest request) : QThread(parent), m_trackCollectionManager(trackCollectionManager), m_trackLoader(trackLoader), m_request{std::move(request)} { - connect(&m_trackLoader, &TrackLoader::trackLoaded, this, &EnginePrimeExportJob::trackLoaded); + // Note that the `trackLoaded()` slot will, by default, execute in whatever + // thread constructs this object, and not this object's worker thread. This + // is not a problem, as the slot simply enqueues each loaded track for + // subsequent processing in the worker thread. + connect(&m_trackLoader, &TrackLoader::trackLoaded, + this, &EnginePrimeExportJob::trackLoaded); } void EnginePrimeExportJob::trackLoaded(TrackRef trackRef, TrackPointer trackPtr) { // See if this track is in our queue. - auto index = m_trackQueue.indexOf(trackRef); + auto index = m_trackRefs.indexOf(trackRef); if (index == -1) { // Not a track we're interested in. return; } - qInfo() << "Exporting track" << trackRef.getId().value() << "at" - << trackRef.getLocation() << "..."; - exportTrack(*m_trackCollectionManager.internalCollection(), m_request, *m_pDb, m_mixxxToEnginePrimeTrackIdMap, trackPtr); - - // Removing this track from the queue and notify it has been exported. + // Enqueue the loaded track onto the queue, and notify that it is loaded. QMutexLocker lock{&m_trackMutex}; - m_trackQueue.removeAt(index); + m_loadedTrackQueue.enqueue(trackPtr); + m_tracksLoaded++; m_waitAnyTrack.wakeAll(); } @@ -397,23 +397,47 @@ void EnginePrimeExportJob::run() { m_mixxxToEnginePrimeTrackIdMap.clear(); // Load all tracks (asynchronously). - m_trackQueue = trackRefs.toList(); - for (auto iter = m_trackQueue.cbegin(); iter != m_trackQueue.cend(); ++iter) { + m_trackRefs = trackRefs.toList(); + for (auto iter = m_trackRefs.cbegin(); iter != m_trackRefs.cend(); ++iter) { m_trackLoader.invokeSlotLoadTrack(*iter); } // Run a consumer queue, waiting for tracks that have been loaded. - int tracksDone = 0; - while (!m_trackQueue.isEmpty()) { - // Wait for a track to be loaded and exported. + while (true) { + TrackPointer pTrack; + { QMutexLocker lock(&m_trackMutex); - m_waitAnyTrack.wait(&m_trackMutex); + if (m_cancellationRequested) { + qInfo() << "Cancelling export"; + return; + } + + if (m_loadedTrackQueue.isEmpty()) { + if (m_tracksLoaded == trackRefs.size()) { + break; + } + + // We expect to be informed when there are more tracks. + m_waitAnyTrack.wait(&m_trackMutex); + if (m_loadedTrackQueue.isEmpty()) { + // Note that this branch is not a warning/error situation: + // it can happen if an export job is cancelled mid-load. + qDebug() << "Track export woken with no tracks to process"; + continue; + } + } + + // We have at least one loaded track we can export right now. + pTrack = m_loadedTrackQueue.dequeue(); } + qInfo() << "Exporting track" << pTrack->getId().value() << "at" + << pTrack->getFileInfo().location() << "..."; + exportTrack(*m_trackCollectionManager.internalCollection(), m_request, + *m_pDb, m_mixxxToEnginePrimeTrackIdMap, pTrack); + ++currProgress; - ++tracksDone; - qInfo() << "Track export progress" << tracksDone << "/" << trackRefs.size(); emit(jobProgress(currProgress)); } @@ -439,6 +463,14 @@ void EnginePrimeExportJob::run() { // Export all Mixxx crates for (const CrateId& crateId : crateIds) { + { + QMutexLocker lock(&m_trackMutex); + if (m_cancellationRequested) { + qInfo() << "Cancelling export"; + return; + } + } + qInfo() << "Exporting crate" << crateId.value() << "..."; exportCrate(*m_trackCollectionManager.internalCollection(), extRootCrate, @@ -454,8 +486,9 @@ void EnginePrimeExportJob::run() { void EnginePrimeExportJob::cancel() { - // TODO(mr-smidge): implement cancellation! - qInfo() << "Would cancel..."; + QMutexLocker lock(&m_trackMutex); + m_cancellationRequested = true; + m_waitAnyTrack.wakeAll(); } } // namespace mixxx diff --git a/src/library/export/engineprimeexportjob.h b/src/library/export/engineprimeexportjob.h index 55a3fbfe1b..9e480c0016 100644 --- a/src/library/export/engineprimeexportjob.h +++ b/src/library/export/engineprimeexportjob.h @@ -6,6 +6,7 @@ #include <QHash> #include <QList> #include <QMutex> +#include <QQueue> #include <QSet> #include <QThread> #include <QWaitCondition> @@ -44,9 +45,12 @@ class EnginePrimeExportJob : public QThread { QSet<TrackRef> getAllTrackRefs() const; QSet<TrackRef> getTracksRefsInCrates(const QSet<CrateId>& crateIds) const; - QList<TrackRef> m_trackQueue; + QList<TrackRef> m_trackRefs; + QQueue<TrackPointer> m_loadedTrackQueue; + int m_tracksLoaded = 0; QMutex m_trackMutex; QWaitCondition m_waitAnyTrack; + bool m_cancellationRequested = false; TrackCollectionManager& m_trackCollectionManager; TrackLoader& m_trackLoader; diff --git a/src/library/export/libraryexporter.cpp b/src/library/export/libraryexporter.cpp index 1f33809259..a54de53b77 100644 --- a/src/library/export/libraryexporter.cpp +++ b/src/library/export/libraryexporter.cpp @@ -42,8 +42,7 @@ void LibraryExporter::beginEnginePrimeExport( this, m_trackCollectionManager, *m_pTrackLoader, std::move(request)}; connect(pJobThread, &EnginePrimeExportJob::finished, pJobThread, &QObject::deleteLater); - // Construct a modal dialog to monitor job progress. - // TODO(mr-smidge) - dialog doesn't appear to update with new progress until after track export? + // Construct a dialog to monitor job progress and offer cancellation. auto *pd = new QProgressDialog(this); pd->setLabelText(tr("Exporting to Engine Prime...")); pd->setMinimumDuration(0); |