[tracker/wip/carlosg/wal-and-other-fixes: 8/8] libtracker-data: Create graph databases with a separate interface



commit f3bb1b11dc677d1bad40c0807e7e2cb4006c1803
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Jul 1 18:51:04 2020 +0200

    libtracker-data: Create graph databases with a separate interface
    
    Due to the way we create graphs (either implicitly on updates, or
    via a CREATE GRAPH update), those always happen inside a DB
    transaction, whereas WAL is documented to be ineffective (immediately
    at least) if set inside a transaction.
    
    This leaves freshly created database connections running on the
    "delete" journal mode, even though WAL is "set", and would eventually
    apply the next time the database is opened. This journal mode has
    many drawbacks (worse performance, readers and writers possibly stalling
    each other, ...) that are noticeable on eg. first index.
    
    To fix this, delegate database file construction to a separate writable
    interface created exclusively for this task, the WAL journal mode and
    page size will be set there, so it is ensured to open with the right
    journal mode when we open it with the readwrite interface.
    
    Immediate benefits:
    - First time tracker-miner-fs indexing (not involving tracker-extract)
      went locally from ~15s to ~9s, much closer to 2.x performance.
    - Select queries won't stall, hopefully fixes some of those weird timeouts
      we've been seeing.

 src/libtracker-data/tracker-db-manager.c | 52 +++++++++++++++++++++++++-------
 1 file changed, 41 insertions(+), 11 deletions(-)
---
diff --git a/src/libtracker-data/tracker-db-manager.c b/src/libtracker-data/tracker-db-manager.c
index 08ab085bf..6b3c4bdd7 100644
--- a/src/libtracker-data/tracker-db-manager.c
+++ b/src/libtracker-data/tracker-db-manager.c
@@ -1000,6 +1000,44 @@ tracker_db_manager_check_perform_vacuum (TrackerDBManager *db_manager)
        tracker_db_interface_execute_query (iface, NULL, "VACUUM");
 }
 
+static gboolean
+ensure_create_database_file (TrackerDBManager  *db_manager,
+                             GFile             *file,
+                             GError           **error)
+{
+       TrackerDBInterface *iface;
+       GError *file_error = NULL;
+       gchar *path;
+
+       /* Ensure the database is created from scratch */
+       if (!g_file_delete (file, NULL, &file_error)) {
+               if (!g_error_matches (file_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
+                       g_propagate_error (error, file_error);
+                       return FALSE;
+               }
+
+               g_clear_error (&file_error);
+       }
+
+       /* Create the database file in a separate interface, so we can
+        * configure page_size and journal_mode outside a transaction, so
+        * they apply throughout the whole lifetime.
+        */
+       path = g_file_get_path (file);
+       iface = tracker_db_interface_sqlite_new (path,
+                                                db_manager->shared_cache_key,
+                                                0, error);
+       if (!iface)
+               return FALSE;
+
+       tracker_db_interface_execute_query (iface, NULL, "PRAGMA cache_size = %d",
+                                           db_manager->db.page_size);
+       tracker_db_interface_execute_query (iface, NULL, "PRAGMA journal_mode = WAL");
+
+       g_object_unref (iface);
+       return TRUE;
+}
+
 gboolean
 tracker_db_manager_attach_database (TrackerDBManager    *db_manager,
                                     TrackerDBInterface  *iface,
@@ -1018,17 +1056,9 @@ tracker_db_manager_attach_database (TrackerDBManager    *db_manager,
                g_free (escaped);
 
                if (create) {
-                       GError *inner_error = NULL;
-
-                       /* Create the database from scratch */
-                       if (!g_file_delete (file, NULL, &inner_error)) {
-                               if (!g_error_matches (inner_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
-                                       g_object_unref (file);
-                                       g_propagate_error (error, inner_error);
-                                       return FALSE;
-                               }
-
-                               g_clear_error (&inner_error);
+                       if (!ensure_create_database_file (db_manager, file, error)) {
+                               g_object_unref (file);
+                               return FALSE;
                        }
                }
        }


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