aboutsummaryrefslogtreecommitdiffstats
path: root/src/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/db')
-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
5 files changed, 55 insertions, 1 deletions
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);