[tracker/wip/carlosg/sparql1.1: 17/56] libtracker-data: Handle attaching and management of "graph" databases



commit 15be25b3bea2af5a8a2fbf77c7bc8e69dbac815c
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Mar 15 00:18:51 2019 +0100

    libtracker-data: Handle attaching and management of "graph" databases

 src/libtracker-data/tracker-data-manager.c        | 133 ++++++++++++++++++++++
 src/libtracker-data/tracker-data-update.c         |  60 +++++++---
 src/libtracker-data/tracker-data-update.h         |   7 ++
 src/libtracker-data/tracker-db-interface-sqlite.c |  49 +++++++-
 src/libtracker-data/tracker-db-interface-sqlite.h |   8 ++
 src/libtracker-data/tracker-db-manager.c          |  38 +++++++
 src/libtracker-data/tracker-db-manager.h          |  10 ++
 7 files changed, 290 insertions(+), 15 deletions(-)
---
diff --git a/src/libtracker-data/tracker-data-manager.c b/src/libtracker-data/tracker-data-manager.c
index 75f4bce6d..4b63137d0 100644
--- a/src/libtracker-data/tracker-data-manager.c
+++ b/src/libtracker-data/tracker-data-manager.c
@@ -83,6 +83,8 @@ struct _TrackerDataManager {
        TrackerOntologies *ontologies;
        TrackerData *data_update;
 
+       GHashTable *graphs;
+
        gchar *status;
 };
 
@@ -150,6 +152,49 @@ tracker_data_ontology_error_quark (void)
        return g_quark_from_static_string ("tracker-data-ontology-error-quark");
 }
 
+static GHashTable *
+tracker_data_manager_get_graphs (TrackerDataManager  *manager,
+                                 TrackerDBInterface  *iface,
+                                 GError             **error)
+{
+       if (!manager->graphs) {
+               TrackerDBCursor *cursor = NULL;
+               TrackerDBStatement *stmt;
+
+               manager->graphs = g_hash_table_new_full (g_str_hash,
+                                                        g_str_equal,
+                                                        g_free,
+                                                        NULL);
+
+               stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_NONE, 
error,
+                                                             "SELECT ID, Url FROM Resource WHERE ID IN 
(SELECT ID FROM Graph)");
+               if (stmt) {
+                       cursor = tracker_db_statement_start_cursor (stmt, error);
+                       g_object_unref (stmt);
+               }
+
+               if (cursor) {
+                       while (tracker_db_cursor_iter_next (cursor, NULL, NULL)) {
+                               const gchar *name;
+                               gint id;
+
+                               id = tracker_db_cursor_get_int (cursor, 0);
+                               name = tracker_db_cursor_get_string (cursor, 1, NULL);
+
+                               g_hash_table_insert (manager->graphs,
+                                                    g_strdup (name),
+                                                    GINT_TO_POINTER (id));
+                       }
+
+                       g_object_unref (cursor);
+               } else {
+                       return NULL;
+               }
+       }
+
+       return manager->graphs;
+}
+
 static void
 handle_unsupported_ontology_change (TrackerDataManager  *manager,
                                     const gchar         *ontology_path,
@@ -3909,6 +3954,7 @@ tracker_data_manager_initable_init (GInitable     *initable,
        TrackerDBCursor *cursor;
        TrackerDBStatement *stmt;
        GHashTable *ontos_table;
+       GHashTable *graphs;
        GList *sorted = NULL, *l;
        gint max_id = 0;
        gboolean read_only;
@@ -4372,6 +4418,22 @@ tracker_data_manager_initable_init (GInitable     *initable,
                                tracker_data_ontology_setup_db (manager, iface, "main", TRUE,
                                                                &ontology_error);
 
+                               graphs = tracker_data_manager_get_graphs (manager, iface, &ontology_error);
+
+                               if (graphs) {
+                                       GHashTableIter iter;
+                                       gpointer value;
+
+                                       g_hash_table_iter_init (&iter, graphs);
+
+                                       while (g_hash_table_iter_next (&iter, &value, NULL)) {
+                                               tracker_data_ontology_setup_db (manager, iface, value, TRUE,
+                                                                               &ontology_error);
+                                               if (ontology_error)
+                                                       break;
+                                       }
+                               }
+
                                if (!ontology_error) {
                                        tracker_data_ontology_import_into_db (manager, iface, TRUE,
                                                                              &ontology_error);
@@ -4470,6 +4532,27 @@ tracker_data_manager_initable_init (GInitable     *initable,
                }
        }
 
+       graphs = tracker_data_manager_get_graphs (manager, iface, &internal_error);
+
+       if (graphs) {
+               GHashTableIter iter;
+               gpointer value;
+
+               g_hash_table_iter_init (&iter, graphs);
+
+               while (g_hash_table_iter_next (&iter, &value, NULL)) {
+                       if (!tracker_db_manager_attach_database (manager->db_manager,
+                                                                iface, value, FALSE,
+                                                                &internal_error))
+                               break;
+               }
+       }
+
+       if (internal_error) {
+               g_propagate_error (error, internal_error);
+               return FALSE;
+       }
+
 skip_ontology_check:
        /* If locale changed, re-create indexes */
        if (!read_only && tracker_db_manager_locale_changed (manager->db_manager, NULL)) {
@@ -4603,6 +4686,7 @@ tracker_data_manager_finalize (GObject *object)
 
        g_clear_object (&manager->ontologies);
        g_clear_object (&manager->data_update);
+       g_clear_pointer (&manager->graphs, g_hash_table_unref);
        g_free (manager->status);
 
        G_OBJECT_CLASS (tracker_data_manager_parent_class)->finalize (object);
@@ -4704,3 +4788,52 @@ tracker_data_manager_get_namespaces (TrackerDataManager *manager)
 
        return ht;
 }
+
+gboolean
+tracker_data_manager_create_graph (TrackerDataManager  *manager,
+                                   const gchar         *name,
+                                   GError             **error)
+{
+       TrackerDBInterface *iface;
+       gint id;
+
+       iface = tracker_db_manager_get_writable_db_interface (manager->db_manager);
+       if (!tracker_db_manager_attach_database (manager->db_manager, iface,
+                                                name, TRUE, error))
+               return FALSE;
+
+       if (!tracker_data_ontology_setup_db (manager, iface, name,
+                                            FALSE, error))
+               goto error;
+
+       id = tracker_data_ensure_graph (manager->data_update, name, error);
+       if (id == 0)
+               goto error;
+
+       g_hash_table_insert (manager->graphs, g_strdup (name), GINT_TO_POINTER (id));
+       return TRUE;
+
+error:
+       tracker_db_manager_detach_database (manager->db_manager, iface, name, NULL);
+       return FALSE;
+}
+
+gboolean
+tracker_data_manager_drop_graph (TrackerDataManager  *manager,
+                                 const gchar         *name,
+                                 GError             **error)
+{
+       TrackerDBInterface *iface;
+
+       iface = tracker_db_manager_get_writable_db_interface (manager->db_manager);
+
+       if (!tracker_db_manager_detach_database (manager->db_manager, iface,
+                                                name, error))
+               return FALSE;
+
+       if (!tracker_data_delete_graph (manager->data_update, name, error))
+               return FALSE;
+
+       g_hash_table_remove (manager->graphs, name);
+       return TRUE;
+}
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index 25baa6df7..5c97652e8 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -734,8 +734,6 @@ ensure_graph_id (TrackerData *data,
                  const gchar *uri,
                 gboolean    *create)
 {
-       TrackerDBInterface *iface;
-       TrackerDBStatement *stmt;
        GError *error = NULL;
        gint id;
 
@@ -743,17 +741,7 @@ ensure_graph_id (TrackerData *data,
        if (id != 0)
                return id;
 
-       id = ensure_resource_id (data, uri, create);
-       iface = tracker_data_manager_get_writable_db_interface (data->manager);
-       stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, &error,
-                                                     "INSERT OR IGNORE INTO Graph (ID) VALUES (?)");
-
-       if (stmt) {
-               tracker_db_statement_bind_int (stmt, 0, id);
-               tracker_db_statement_execute (stmt, &error);
-               g_object_unref (stmt);
-       }
-
+       id = tracker_data_ensure_graph (data, uri, &error);
        if (error) {
                g_critical ("Could not ensure graph existence: %s", error->message);
                g_error_free (error);
@@ -3412,3 +3400,49 @@ tracker_data_load_turtle_file (TrackerData  *data,
 
        tracker_turtle_reader_load (file, data, error);
 }
+
+gint
+tracker_data_ensure_graph (TrackerData  *data,
+                           const gchar  *uri,
+                           GError      **error)
+{
+       TrackerDBInterface *iface;
+       TrackerDBStatement *stmt;
+       gint id;
+
+       id = ensure_resource_id (data, uri, NULL);
+       iface = tracker_data_manager_get_writable_db_interface (data->manager);
+       stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, error,
+                                                     "INSERT OR IGNORE INTO Graph (ID) VALUES (?)");
+       if (!stmt)
+               return 0;
+
+       tracker_db_statement_bind_int (stmt, 0, id);
+       tracker_db_statement_execute (stmt, error);
+       g_object_unref (stmt);
+
+       return id;
+}
+
+gboolean
+tracker_data_delete_graph (TrackerData  *data,
+                           const gchar  *uri,
+                           GError      **error)
+{
+       TrackerDBInterface *iface;
+       TrackerDBStatement *stmt;
+       gint id;
+
+       id = query_resource_id (data, uri);
+       iface = tracker_data_manager_get_writable_db_interface (data->manager);
+       stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, error,
+                                                     "DELETE FROM Graph WHERE ID = ?");
+       if (!stmt)
+               return FALSE;
+
+       tracker_db_statement_bind_int (stmt, 0, id);
+       tracker_db_statement_execute (stmt, error);
+       g_object_unref (stmt);
+
+       return TRUE;
+}
diff --git a/src/libtracker-data/tracker-data-update.h b/src/libtracker-data/tracker-data-update.h
index 3acb11f27..5241167fb 100644
--- a/src/libtracker-data/tracker-data-update.h
+++ b/src/libtracker-data/tracker-data-update.h
@@ -118,6 +118,13 @@ void     tracker_data_load_turtle_file              (TrackerData               *
 
 void     tracker_data_sync                          (TrackerData               *data);
 
+gint     tracker_data_ensure_graph                  (TrackerData               *data,
+                                                     const gchar               *name,
+                                                     GError                   **error);
+gboolean tracker_data_delete_graph                  (TrackerData               *data,
+                                                     const gchar               *uri,
+                                                     GError                   **error);
+
 /* Calling back */
 void     tracker_data_add_insert_statement_callback      (TrackerData               *data,
                                                           TrackerStatementCallback   callback,
diff --git a/src/libtracker-data/tracker-db-interface-sqlite.c 
b/src/libtracker-data/tracker-db-interface-sqlite.c
index d253df52d..52eca4a9f 100644
--- a/src/libtracker-data/tracker-db-interface-sqlite.c
+++ b/src/libtracker-data/tracker-db-interface-sqlite.c
@@ -2382,7 +2382,7 @@ tracker_db_interface_create_statement (TrackerDBInterface           *db_interfac
        return g_object_ref_sink (stmt);
 }
 
-static void
+static gboolean
 execute_stmt (TrackerDBInterface  *interface,
               sqlite3_stmt        *stmt,
               GCancellable        *cancellable,
@@ -2431,7 +2431,7 @@ execute_stmt (TrackerDBInterface  *interface,
                        g_critical ("SQLite error: %s (errno: %s)",
                                    sqlite3_errmsg (interface->db),
                                    g_strerror (errno));
-                       return;
+                       return FALSE;
                }
 
                if (!error) {
@@ -2456,6 +2456,8 @@ execute_stmt (TrackerDBInterface  *interface,
                        }
                }
        }
+
+       return result == SQLITE_DONE;
 }
 
 void
@@ -3171,3 +3173,46 @@ tracker_db_interface_init_vtabs (TrackerDBInterface *db_interface,
        tracker_vtab_triples_init (db_interface->db, ontologies);
        return TRUE;
 }
+
+gboolean
+tracker_db_interface_attach_database (TrackerDBInterface  *db_interface,
+                                      GFile               *file,
+                                      const gchar         *name,
+                                      GError             **error)
+{
+       gchar *sql, *path;
+       sqlite3_stmt *stmt;
+       gboolean retval;
+
+       path = g_file_get_path (file);
+       sql = g_strdup_printf ("ATTACH DATABASE \"%s\" AS \"%s\"", path, name);
+       g_free (path);
+
+       stmt = tracker_db_interface_prepare_stmt (db_interface, sql, error);
+       if (!stmt)
+               return FALSE;
+
+       retval = execute_stmt (db_interface, stmt, NULL, error);
+       sqlite3_finalize (stmt);
+       return retval;
+}
+
+gboolean
+tracker_db_interface_detach_database (TrackerDBInterface  *db_interface,
+                                      const gchar         *name,
+                                      GError             **error)
+{
+       sqlite3_stmt *stmt;
+       gboolean retval;
+       gchar *sql;
+
+       sql = g_strdup_printf ("DETACH DATABASE \"%s\"", name);
+
+       stmt = tracker_db_interface_prepare_stmt (db_interface, sql, error);
+       if (!stmt)
+               return FALSE;
+
+       retval = execute_stmt (db_interface, stmt, NULL, error);
+       sqlite3_finalize (stmt);
+       return retval;
+}
diff --git a/src/libtracker-data/tracker-db-interface-sqlite.h 
b/src/libtracker-data/tracker-db-interface-sqlite.h
index 4608bac94..1715d30ef 100644
--- a/src/libtracker-data/tracker-db-interface-sqlite.h
+++ b/src/libtracker-data/tracker-db-interface-sqlite.h
@@ -83,6 +83,14 @@ void                tracker_db_interface_sqlite_fts_update_rollback    (TrackerD
 
 void                tracker_db_interface_sqlite_fts_rebuild_tokens     (TrackerDBInterface       *interface);
 
+gboolean            tracker_db_interface_attach_database               (TrackerDBInterface       
*db_interface,
+                                                                        GFile                    *file,
+                                                                        const gchar              *name,
+                                                                        GError                  **error);
+gboolean            tracker_db_interface_detach_database               (TrackerDBInterface       
*db_interface,
+                                                                        const gchar              *name,
+                                                                        GError                  **error);
+
 #endif
 
 G_END_DECLS
diff --git a/src/libtracker-data/tracker-db-manager.c b/src/libtracker-data/tracker-db-manager.c
index 09cbf4ded..cb419427d 100644
--- a/src/libtracker-data/tracker-db-manager.c
+++ b/src/libtracker-data/tracker-db-manager.c
@@ -1245,3 +1245,41 @@ tracker_db_manager_check_perform_vacuum (TrackerDBManager *db_manager)
        iface = tracker_db_manager_get_writable_db_interface (db_manager);
        tracker_db_interface_execute_query (iface, NULL, "VACUUM");
 }
+
+gboolean
+tracker_db_manager_attach_database (TrackerDBManager    *db_manager,
+                                    TrackerDBInterface  *iface,
+                                    const gchar         *name,
+                                    gboolean             create,
+                                    GError             **error)
+{
+       gchar *filename;
+       GFile *file;
+
+       filename = g_strdup_printf ("%s.db", name);
+       file = g_file_get_child (db_manager->cache_location, filename);
+       g_free (filename);
+
+       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_propagate_error (error, inner_error);
+                               return FALSE;
+                       }
+               }
+       }
+
+       return tracker_db_interface_attach_database (iface, file, name, error);
+}
+
+gboolean
+tracker_db_manager_detach_database (TrackerDBManager    *db_manager,
+                                    TrackerDBInterface  *iface,
+                                    const gchar         *name,
+                                    GError             **error)
+{
+       return tracker_db_interface_detach_database (iface, name, error);
+}
diff --git a/src/libtracker-data/tracker-db-manager.h b/src/libtracker-data/tracker-db-manager.h
index 432a39810..cd95b2529 100644
--- a/src/libtracker-data/tracker-db-manager.h
+++ b/src/libtracker-data/tracker-db-manager.h
@@ -96,6 +96,16 @@ void                tracker_db_manager_tokenizer_update       (TrackerDBManager
 
 void                tracker_db_manager_check_perform_vacuum   (TrackerDBManager      *db_manager);
 
+gboolean            tracker_db_manager_attach_database        (TrackerDBManager      *db_manager,
+                                                               TrackerDBInterface    *iface,
+                                                               const gchar           *name,
+                                                               gboolean               create,
+                                                               GError               **error);
+gboolean            tracker_db_manager_detach_database        (TrackerDBManager      *db_manager,
+                                                               TrackerDBInterface    *iface,
+                                                               const gchar           *name,
+                                                               GError               **error);
+
 G_END_DECLS
 
 #endif /* __LIBTRACKER_DB_MANAGER_H__ */


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