[tracker/wip/carlosg/automatic-store-shutdown: 53/53] tracker-store: Automatically shutdown on inactivity



commit efd69c3629952931e4ec255a494d025eccb9769d
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sun Nov 11 13:18:38 2018 +0100

    tracker-store: Automatically shutdown on inactivity
    
    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.

 src/tracker-store/tracker-main.vala  | 32 ++++++++++++++++++-
 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 () {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]