aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2014-02-27 16:36:11 +0100
committerMax Kellermann <max@duempel.org>2014-02-27 16:58:35 +0100
commit681e012fb542ee1bb2ea5312dc673987a7a8ee29 (patch)
tree2887e01d906c89f99516d67c555a2318473cc169 /src
parent3be36643a1bded02171d8ddaac7d7aecfdc1915a (diff)
downloadmpd-681e012fb542ee1bb2ea5312dc673987a7a8ee29.tar.gz
mpd-681e012fb542ee1bb2ea5312dc673987a7a8ee29.tar.xz
mpd-681e012fb542ee1bb2ea5312dc673987a7a8ee29.zip
db/update: cancel the update on shutdown
Diffstat (limited to 'src')
-rw-r--r--src/Main.cxx3
-rw-r--r--src/db/update/Queue.hxx4
-rw-r--r--src/db/update/Service.cxx19
-rw-r--r--src/db/update/Service.hxx8
-rw-r--r--src/db/update/Walk.cxx2
-rw-r--r--src/db/update/Walk.hxx23
6 files changed, 58 insertions, 1 deletions
diff --git a/src/Main.cxx b/src/Main.cxx
index 4b161fd6b..61e5fb2b6 100644
--- a/src/Main.cxx
+++ b/src/Main.cxx
@@ -596,6 +596,9 @@ int mpd_main(int argc, char *argv[])
#if defined(ENABLE_DATABASE) && defined(ENABLE_INOTIFY)
mpd_inotify_finish();
+
+ if (instance->update != nullptr)
+ instance->update->CancelAllAsync();
#endif
if (state_file != nullptr) {
diff --git a/src/db/update/Queue.hxx b/src/db/update/Queue.hxx
index a5b2aa9ac..eb0b268bf 100644
--- a/src/db/update/Queue.hxx
+++ b/src/db/update/Queue.hxx
@@ -50,6 +50,10 @@ public:
bool Push(const char *path, bool discard, unsigned id);
UpdateQueueItem Pop();
+
+ void Clear() {
+ update_queue = decltype(update_queue)();
+ }
};
#endif
diff --git a/src/db/update/Service.cxx b/src/db/update/Service.cxx
index 0018e2cc0..112d97760 100644
--- a/src/db/update/Service.cxx
+++ b/src/db/update/Service.cxx
@@ -47,6 +47,23 @@ UpdateService::UpdateService(EventLoop &_loop, SimpleDatabase &_db,
{
}
+UpdateService::~UpdateService()
+{
+ CancelAllAsync();
+
+ if (update_thread.IsDefined())
+ update_thread.Join();
+}
+
+void
+UpdateService::CancelAllAsync()
+{
+ assert(GetEventLoop().IsInsideOrNull());
+
+ queue.Clear();
+ walk.Cancel();
+}
+
inline void
UpdateService::Task()
{
@@ -94,6 +111,8 @@ UpdateService::StartThread(UpdateQueueItem &&i)
next = std::move(i);
+ walk.Prepare();
+
Error error;
if (!update_thread.Start(Task, this, error))
FatalError(error);
diff --git a/src/db/update/Service.hxx b/src/db/update/Service.hxx
index 936c2bb55..ebdda7bd1 100644
--- a/src/db/update/Service.hxx
+++ b/src/db/update/Service.hxx
@@ -64,6 +64,8 @@ public:
Storage &_storage,
DatabaseListener &_listener);
+ ~UpdateService();
+
/**
* Returns a non-zero job id when we are currently updating
* the database.
@@ -82,6 +84,12 @@ public:
gcc_nonnull_all
unsigned Enqueue(const char *path, bool discard);
+ /**
+ * Clear the queue and cancel the current update. Does not
+ * wait for the thread to exit.
+ */
+ void CancelAllAsync();
+
private:
/* virtual methods from class DeferredMonitor */
virtual void RunDeferred() override;
diff --git a/src/db/update/Walk.cxx b/src/db/update/Walk.cxx
index c65480873..db05b1823 100644
--- a/src/db/update/Walk.cxx
+++ b/src/db/update/Walk.cxx
@@ -358,7 +358,7 @@ UpdateWalk::UpdateDirectory(Directory &directory, const FileInfo &info)
PurgeDeletedFromDirectory(directory);
const char *name_utf8;
- while ((name_utf8 = reader->Read()) != nullptr) {
+ while (!cancel && (name_utf8 = reader->Read()) != nullptr) {
if (skip_path(name_utf8))
continue;
diff --git a/src/db/update/Walk.hxx b/src/db/update/Walk.hxx
index bf3eb8ae4..353f6f3ed 100644
--- a/src/db/update/Walk.hxx
+++ b/src/db/update/Walk.hxx
@@ -48,6 +48,13 @@ class UpdateWalk final {
bool walk_discard;
bool modified;
+ /**
+ * Set to true by the main thread when the update thread shall
+ * cancel as quickly as possible. Access to this flag is
+ * unprotected.
+ */
+ volatile bool cancel;
+
Storage &storage;
DatabaseEditor editor;
@@ -57,6 +64,22 @@ public:
Storage &_storage);
/**
+ * Cancel the current update and quit the Walk() method as
+ * soon as possible.
+ */
+ void Cancel() {
+ cancel = true;
+ }
+
+ /**
+ * Call from the main thread before starting the update
+ * thread.
+ */
+ void Prepare() {
+ cancel = false;
+ }
+
+ /**
* Returns true if the database was modified.
*/
bool Walk(Directory &root, const char *path, bool discard);