From 681e012fb542ee1bb2ea5312dc673987a7a8ee29 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 27 Feb 2014 16:36:11 +0100 Subject: db/update: cancel the update on shutdown --- src/db/update/Queue.hxx | 4 ++++ src/db/update/Service.cxx | 19 +++++++++++++++++++ src/db/update/Service.hxx | 8 ++++++++ src/db/update/Walk.cxx | 2 +- src/db/update/Walk.hxx | 23 +++++++++++++++++++++++ 5 files changed, 55 insertions(+), 1 deletion(-) (limited to 'src/db/update') 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; @@ -56,6 +63,22 @@ public: UpdateWalk(EventLoop &_loop, DatabaseListener &_listener, 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. */ -- cgit v1.2.3