diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2018-11-11 13:18:38 +0100 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2018-11-13 12:17:51 +0100 |
commit | efd69c3629952931e4ec255a494d025eccb9769d (patch) | |
tree | 228b33696d190558c089b0535b81ac7fa3c0afcf | |
parent | 96ef9ab1003ec391df9fc42219e8305aa7c708a0 (diff) | |
download | tracker-wip/carlosg/automatic-store-shutdown.tar.gz |
tracker-store: Automatically shutdown on inactivitywip/carlosg/automatic-store-shutdown
If the right conditions apply, tracker-store will shut down
after 30s of inactivity (no clients doing updates/selects).
Bringing it back again is relatively cheap, so let's see how
this flies.
For the cases it won't, tracker-store has a --disable-shutdown
switch (also useful for testing from terminal), also running on
other buses than the session one will disable it, since both
shutting down and later restart pose questions and risks.
In theory, this will make tracker-store disappear 99% of the
time, since database updates are sparse. There's also the
possibility of clients running with TRACKER_SPARQL_BACKEND=bus
or resorting to bus connection (eg. flatpak apps), that will
make selects go through tracker-store.
-rw-r--r-- | src/tracker-store/tracker-main.vala | 32 | ||||
-rw-r--r-- | src/tracker-store/tracker-store.vala | 59 |
2 files changed, 80 insertions, 11 deletions
diff --git a/src/tracker-store/tracker-main.vala b/src/tracker-store/tracker-main.vala index 478076278..1e8d1ddd2 100644 --- a/src/tracker-store/tracker-main.vala +++ b/src/tracker-store/tracker-main.vala @@ -37,6 +37,7 @@ License which can be viewed at: static MainLoop main_loop; static string log_filename; + static uint shutdown_timeout_id; static bool shutdown; static Tracker.Direct.Connection connection; @@ -52,11 +53,13 @@ License which can be viewed at: static File data_location; static File ontology_location; static string domain; + static bool disable_shutdown; const OptionEntry entries[] = { /* Daemon options */ { "version", 'V', 0, OptionArg.NONE, ref version, N_("Displays version information"), null }, { "verbosity", 'v', 0, OptionArg.INT, ref verbosity, N_("Logging, 0 = errors only, 1 = minimal, 2 = detailed and 3 = debug (default = 0)"), null }, + { "disable-shutdown", 's', 0, OptionArg.NONE, ref disable_shutdown, N_("Disable automatic shutdown"), null }, /* Indexer options */ { "force-reindex", 'r', 0, OptionArg.NONE, ref force_reindex, N_("Force a re-index of all content"), null }, @@ -180,6 +183,33 @@ License which can be viewed at: return connection; } + private static bool shutdown_timeout () { + message ("Store shutting down after timeout"); + do_shutdown (); + return GLib.Source.REMOVE; + } + + private static void idle_cb () { + /* Do not perform shutdown in case of exotic buses */ + if (Tracker.IPC.bus () != GLib.BusType.SESSION) + return; + if (shutdown_timeout_id != 0) + return; + if (disable_shutdown) + return; + + message ("Store is idle, setting shutdown timeout"); + shutdown_timeout_id = GLib.Timeout.add_seconds (30, shutdown_timeout); + } + + private static void busy_cb () { + if (shutdown_timeout_id == 0) + return; + message ("Store is busy, removing shutdown timeout"); + GLib.Source.remove (shutdown_timeout_id); + shutdown_timeout_id = 0; + } + static int main (string[] args) { Intl.setlocale (LocaleCategory.ALL, ""); @@ -265,7 +295,7 @@ License which can be viewed at: var notifier = Tracker.DBus.register_notifier (); - Tracker.Store.init (config); + Tracker.Store.init (config, idle_cb, busy_cb); /* Make Tracker available for introspection */ if (!Tracker.DBus.register_objects ()) { diff --git a/src/tracker-store/tracker-store.vala b/src/tracker-store/tracker-store.vala index 03cc8078a..f7b03a601 100644 --- a/src/tracker-store/tracker-store.vala +++ b/src/tracker-store/tracker-store.vala @@ -39,6 +39,11 @@ public class Tracker.Store { public delegate void SparqlQueryInThread (Sparql.Cursor cursor) throws Error; + public delegate void StateCallback (); + static unowned StateCallback idle_cb; + static unowned StateCallback busy_cb; + static bool busy; + class CursorTask { public Sparql.Cursor cursor; public unowned SourceFunc callback; @@ -61,11 +66,12 @@ public class Tracker.Store { Idle.add (() => { task.callback (); + update_state (); return false; }); } - public static void init (Tracker.Config config_p) { + public static void init (Tracker.Config config_p, StateCallback idle, StateCallback busy) { string max_task_time_env = Environment.get_variable ("TRACKER_STORE_MAX_TASK_TIME"); if (max_task_time_env != null) { max_task_time = int.parse (max_task_time_env); @@ -88,6 +94,9 @@ public class Tracker.Store { ThreadPool.set_max_unused_threads (2); config = config_p; + idle_cb = idle; + busy_cb = busy; + idle_cb (); } public static void shutdown () { @@ -158,30 +167,41 @@ public class Tracker.Store { // Ignore harmless error } + update_state (); + yield; if (task.error != null) throw task.error; } + private static void pre_update () { + n_updates++; + update_state (); + ensure_signal_timeout (); + } + + private static void post_update () { + n_updates--; + update_state (); + } + public static async void sparql_update (Tracker.Direct.Connection conn, string sparql, int priority, string client_id) throws Error { if (!active) throw new Sparql.Error.UNSUPPORTED ("Store is not active"); - n_updates++; - ensure_signal_timeout (); + pre_update (); var cancellable = create_cancellable (client_id); yield conn.update_async (sparql, priority, cancellable); - n_updates--; + post_update (); } public static async Variant sparql_update_blank (Tracker.Direct.Connection conn, string sparql, int priority, string client_id) throws Error { if (!active) throw new Sparql.Error.UNSUPPORTED ("Store is not active"); - n_updates++; - ensure_signal_timeout (); + pre_update (); var cancellable = create_cancellable (client_id); var nodes = yield conn.update_blank_async (sparql, priority, cancellable); - n_updates--; + post_update (); return nodes; } @@ -189,11 +209,10 @@ public class Tracker.Store { public static async void queue_turtle_import (Tracker.Direct.Connection conn, File file, string client_id) throws Error { if (!active) throw new Sparql.Error.UNSUPPORTED ("Store is not active"); - n_updates++; - ensure_signal_timeout (); + pre_update (); var cancellable = create_cancellable (client_id); yield conn.load_async (file, cancellable); - n_updates--; + post_update (); } public static void unreg_batches (string client_id) { @@ -202,6 +221,7 @@ public class Tracker.Store { if (cancellable != null) { cancellable.cancel (); client_cancellables.remove (client_id); + update_state (); } } @@ -216,10 +236,29 @@ public class Tracker.Store { Tracker.Store.active = true; } + private static void update_state () { + bool cur_busy; + + cur_busy = (!Tracker.Store.active || /* Keep busy while paused */ + n_updates != 0 || /* There are updates */ + cursor_pool.unprocessed () > 0 || /* Select cursor pool is busy */ + cursor_pool.get_num_threads () > 0); + + if (busy == cur_busy) + return; + + busy = cur_busy; + if (busy) + busy_cb (); + else + idle_cb (); + } + private static void on_statements_committed () { Tracker.Events.transact (); Tracker.Writeback.transact (); check_graph_updated_signal (); + update_state (); } private static void on_statements_rolled_back () { |