From 1c6e43509cc023cd852d1ef7ea39f3af60d50a50 Mon Sep 17 00:00:00 2001 From: Jim Broadus Date: Tue, 21 Jan 2020 00:32:55 -0800 Subject: [PATCH] Cancel scan when directory is removed. When a directory is removed from the library during a scan, the scan continues until complete. This change cancels the scan immediately, unblocking the watcher thread, then signals the watcher to remove the directory. A second issue occurs when a previously scanned device is removed during a scan. All remaining files will be marked as deleted. This change mitigates this issue, but a timing hole still remains here. --- src/devices/filesystemdevice.cpp | 5 +++-- src/library/library.cpp | 5 +++-- src/library/librarywatcher.cpp | 6 ++++++ src/library/librarywatcher.h | 6 +++++- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/devices/filesystemdevice.cpp b/src/devices/filesystemdevice.cpp index 42134c455..40e660c9f 100644 --- a/src/devices/filesystemdevice.cpp +++ b/src/devices/filesystemdevice.cpp @@ -49,8 +49,9 @@ FilesystemDevice::FilesystemDevice(const QUrl& url, DeviceLister* lister, connect(backend_.get(), SIGNAL(DirectoryDiscovered(Directory, SubdirectoryList)), watcher_, SLOT(AddDirectory(Directory, SubdirectoryList))); - connect(backend_.get(), SIGNAL(DirectoryDeleted(Directory)), watcher_, - SLOT(RemoveDirectory(Directory))); + // RemoveDirectory should be called from the sender's thread. + connect(backend_.get(), &LibraryBackend::DirectoryDeleted, watcher_, + &LibraryWatcher::RemoveDirectory, Qt::DirectConnection); connect(watcher_, SIGNAL(NewOrUpdatedSongs(SongList)), backend_.get(), SLOT(AddOrUpdateSongs(SongList))); connect(watcher_, SIGNAL(SongsMTimeUpdated(SongList)), backend_.get(), diff --git a/src/library/library.cpp b/src/library/library.cpp index da30dbeb2..3999488b2 100644 --- a/src/library/library.cpp +++ b/src/library/library.cpp @@ -141,8 +141,9 @@ void Library::Init() { connect(backend_.get(), SIGNAL(DirectoryDiscovered(Directory, SubdirectoryList)), watcher_, SLOT(AddDirectory(Directory, SubdirectoryList))); - connect(backend_.get(), SIGNAL(DirectoryDeleted(Directory)), watcher_, - SLOT(RemoveDirectory(Directory))); + // RemoveDirectory should be called from the sender's thread. + connect(backend_.get(), &LibraryBackend::DirectoryDeleted, watcher_, + &LibraryWatcher::RemoveDirectory, Qt::DirectConnection); connect(backend_.get(), SIGNAL(SongsRatingChanged(SongList)), SLOT(SongsRatingChanged(SongList))); connect(backend_.get(), SIGNAL(SongsStatisticsChanged(SongList)), diff --git a/src/library/librarywatcher.cpp b/src/library/librarywatcher.cpp index 62accc8f6..a52e08be3 100644 --- a/src/library/librarywatcher.cpp +++ b/src/library/librarywatcher.cpp @@ -663,6 +663,12 @@ void LibraryWatcher::RemoveWatch(const Directory& dir, } void LibraryWatcher::RemoveDirectory(const Directory& dir) { + watched_dirs_.Stop(dir); + // Invoke the DoRemoveDirectory slot on the watcher's thread. + QMetaObject::invokeMethod(this, "DoRemoveDirectory", Q_ARG(Directory, dir)); +} + +void LibraryWatcher::DoRemoveDirectory(const Directory& dir) { rescan_queue_.remove(dir.id); watched_dirs_.Remove(dir.id); diff --git a/src/library/librarywatcher.h b/src/library/librarywatcher.h index 68980375d..668335664 100644 --- a/src/library/librarywatcher.h +++ b/src/library/librarywatcher.h @@ -55,6 +55,10 @@ class LibraryWatcher : public QObject { void FullScanAsync(); void SetRescanPausedAsync(bool pause); void ReloadSettingsAsync(); + // This thread-safe method will cause a scan of this directory to cancel to + // unblock the watcher thread. It will then invoke the DoRemoveDirectory on + // the watcher's thread to complete the removal. + void RemoveDirectory(const Directory& dir); void Stop() { watched_dirs_.StopAll(); } @@ -74,7 +78,6 @@ class LibraryWatcher : public QObject { public slots: void ReloadSettings(); void AddDirectory(const Directory& dir, const SubdirectoryList& subdirs); - void RemoveDirectory(const Directory& dir); void SetRescanPaused(bool pause); private: @@ -158,6 +161,7 @@ class LibraryWatcher : public QObject { void RescanPathsNow(); void ScanSubdirectory(const QString& path, const Subdirectory& subdir, ScanTransaction* t, bool force_noincremental = false); + void DoRemoveDirectory(const Directory& dir); private: static bool FindSongByPath(const SongList& list, const QString& path,