From 3be36643a1bded02171d8ddaac7d7aecfdc1915a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 27 Feb 2014 16:14:10 +0100 Subject: db/UpdateGlue: rename to Service.cxx --- src/db/update/Service.cxx | 140 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) (limited to 'src/db/update/Service.cxx') diff --git a/src/db/update/Service.cxx b/src/db/update/Service.cxx index cc2a86968..0018e2cc0 100644 --- a/src/db/update/Service.cxx +++ b/src/db/update/Service.cxx @@ -19,3 +19,143 @@ #include "config.h" #include "Service.hxx" +#include "UpdateDomain.hxx" +#include "db/DatabaseListener.hxx" +#include "db/plugins/simple/SimpleDatabasePlugin.hxx" +#include "Idle.hxx" +#include "util/Error.hxx" +#include "Log.hxx" +#include "Instance.hxx" +#include "system/FatalError.hxx" +#include "thread/Id.hxx" +#include "thread/Thread.hxx" +#include "thread/Util.hxx" + +#ifndef NDEBUG +#include "event/Loop.hxx" +#endif + +#include + +UpdateService::UpdateService(EventLoop &_loop, SimpleDatabase &_db, + Storage &_storage, + DatabaseListener &_listener) + :DeferredMonitor(_loop), db(_db), listener(_listener), + progress(UPDATE_PROGRESS_IDLE), + update_task_id(0), + walk(_loop, _listener, _storage) +{ +} + +inline void +UpdateService::Task() +{ + if (!next.path_utf8.empty()) + FormatDebug(update_domain, "starting: %s", + next.path_utf8.c_str()); + else + LogDebug(update_domain, "starting"); + + SetThreadIdlePriority(); + + modified = walk.Walk(*db.GetRoot(), next.path_utf8.c_str(), + next.discard); + + if (modified || !db.FileExists()) { + Error error; + if (!db.Save(error)) + LogError(error, "Failed to save database"); + } + + if (!next.path_utf8.empty()) + FormatDebug(update_domain, "finished: %s", + next.path_utf8.c_str()); + else + LogDebug(update_domain, "finished"); + + progress = UPDATE_PROGRESS_DONE; + DeferredMonitor::Schedule(); +} + +void +UpdateService::Task(void *ctx) +{ + UpdateService &service = *(UpdateService *)ctx; + return service.Task(); +} + +void +UpdateService::StartThread(UpdateQueueItem &&i) +{ + assert(GetEventLoop().IsInsideOrNull()); + + progress = UPDATE_PROGRESS_RUNNING; + modified = false; + + next = std::move(i); + + Error error; + if (!update_thread.Start(Task, this, error)) + FatalError(error); + + FormatDebug(update_domain, + "spawned thread for update job id %i", next.id); +} + +unsigned +UpdateService::GenerateId() +{ + unsigned id = update_task_id + 1; + if (id > update_task_id_max) + id = 1; + return id; +} + +unsigned +UpdateService::Enqueue(const char *path, bool discard) +{ + assert(GetEventLoop().IsInsideOrNull()); + + if (progress != UPDATE_PROGRESS_IDLE) { + const unsigned id = GenerateId(); + if (!queue.Push(path, discard, id)) + return 0; + + update_task_id = id; + return id; + } + + const unsigned id = update_task_id = GenerateId(); + StartThread(UpdateQueueItem(path, discard, id)); + + idle_add(IDLE_UPDATE); + + return id; +} + +/** + * Called in the main thread after the database update is finished. + */ +void +UpdateService::RunDeferred() +{ + assert(progress == UPDATE_PROGRESS_DONE); + assert(next.IsDefined()); + + update_thread.Join(); + next = UpdateQueueItem(); + + idle_add(IDLE_UPDATE); + + if (modified) + /* send "idle" events */ + listener.OnDatabaseModified(); + + auto i = queue.Pop(); + if (i.IsDefined()) { + /* schedule the next path */ + StartThread(std::move(i)); + } else { + progress = UPDATE_PROGRESS_IDLE; + } +} -- cgit v1.2.3