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



commit 03e772ee5ad20d8bd9d7614ed03cc6ef5c4bac1b
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        | 194 ++++++++++++++++++++++
 src/libtracker-data/tracker-data-manager.h        |  13 ++
 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          |  40 +++++
 src/libtracker-data/tracker-db-manager.h          |  10 ++
 8 files changed, 366 insertions(+), 15 deletions(-)
---
diff --git a/src/libtracker-data/tracker-data-manager.c b/src/libtracker-data/tracker-data-manager.c
index 2781ae59d..15f4d976b 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,65 @@ tracker_data_ontology_error_quark (void)
        return g_quark_from_static_string ("tracker-data-ontology-error-quark");
 }
 
+static gboolean
+tracker_data_manager_ensure_graphs (TrackerDataManager  *manager,
+                                   TrackerDBInterface  *iface,
+                                   GError             **error)
+{
+       TrackerDBCursor *cursor = NULL;
+       TrackerDBStatement *stmt;
+       GHashTable *graphs;
+
+       if (manager->graphs)
+               return TRUE;
+
+       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, Uri FROM Resource WHERE ID IN (SELECT ID 
FROM Graph)");
+       if (!stmt) {
+               g_hash_table_unref (graphs);
+               return FALSE;
+       }
+
+       cursor = tracker_db_statement_start_cursor (stmt, error);
+       g_object_unref (stmt);
+
+       if (!cursor) {
+               g_hash_table_unref (graphs);
+               return FALSE;
+       }
+
+       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 (graphs, g_strdup (name),
+                                    GINT_TO_POINTER (id));
+       }
+
+       g_object_unref (cursor);
+       manager->graphs = graphs;
+       return TRUE;
+}
+
+static GHashTable *
+tracker_data_manager_get_graphs (TrackerDataManager  *manager,
+                                 TrackerDBInterface  *iface,
+                                 GError             **error)
+{
+       if (!tracker_data_manager_ensure_graphs (manager, iface, error))
+               return NULL;
+
+       return manager->graphs;
+}
+
 static void
 handle_unsupported_ontology_change (TrackerDataManager  *manager,
                                     const gchar         *ontology_path,
@@ -3898,9 +3959,32 @@ setup_interface_cb (TrackerDBManager   *db_manager,
                     TrackerDBInterface *iface,
                     TrackerDataManager *data_manager)
 {
+       GHashTable *graphs;
+       GError *error = NULL;
+
 #if HAVE_TRACKER_FTS
        tracker_data_manager_init_fts (iface, FALSE);
 #endif
+       graphs = tracker_data_manager_get_graphs (data_manager, iface, NULL);
+
+       if (graphs) {
+               GHashTableIter iter;
+               gpointer value;
+               GError *error = NULL;
+
+               g_hash_table_iter_init (&iter, graphs);
+
+               while (g_hash_table_iter_next (&iter, &value, NULL)) {
+                       if (!tracker_db_manager_attach_database (db_manager,
+                                                                iface, value, FALSE,
+                                                                &error)) {
+                               g_critical ("Could not attach database '%s': %s\n",
+                                           (gchar *) value, error->message);
+                               g_clear_error (&error);
+                               continue;
+                       }
+               }
+       }
 }
 
 static gboolean
@@ -3914,6 +3998,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;
@@ -4380,6 +4465,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);
@@ -4611,6 +4712,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);
@@ -4712,3 +4814,95 @@ 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 detach;
+
+       id = tracker_data_ensure_graph (manager->data_update, name, error);
+       if (id == 0)
+               goto detach;
+
+       g_hash_table_insert (manager->graphs, g_strdup (name), GINT_TO_POINTER (id));
+       return TRUE;
+
+detach:
+       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;
+
+       if (manager->graphs)
+               g_hash_table_remove (manager->graphs, name);
+
+       return TRUE;
+}
+
+gint
+tracker_data_manager_find_graph (TrackerDataManager *manager,
+                                 const gchar        *name)
+{
+       TrackerDBInterface *iface;
+       GHashTable *graphs;
+
+       iface = tracker_db_manager_get_writable_db_interface (manager->db_manager);
+       graphs = tracker_data_manager_get_graphs (manager, iface, NULL);
+
+       if (!graphs)
+               return 0;
+
+       return GPOINTER_TO_UINT (g_hash_table_lookup (graphs, name));
+}
+
+const gchar *
+tracker_data_manager_find_graph_by_id (TrackerDataManager *manager,
+                                       gint                id)
+{
+       TrackerDBInterface *iface;
+       GHashTableIter iter;
+       GHashTable *graphs;
+       gpointer key, value;
+
+       iface = tracker_db_manager_get_writable_db_interface (manager->db_manager);
+       graphs = tracker_data_manager_get_graphs (manager, iface, NULL);
+
+       if (!graphs)
+               return NULL;
+
+       g_hash_table_iter_init (&iter, graphs);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               if (id == GPOINTER_TO_INT (value))
+                       return key;
+       }
+
+       return NULL;
+}
diff --git a/src/libtracker-data/tracker-data-manager.h b/src/libtracker-data/tracker-data-manager.h
index 71795a56a..ebb992753 100644
--- a/src/libtracker-data/tracker-data-manager.h
+++ b/src/libtracker-data/tracker-data-manager.h
@@ -80,6 +80,19 @@ TrackerData *        tracker_data_manager_get_data            (TrackerDataManage
 
 GHashTable *         tracker_data_manager_get_namespaces      (TrackerDataManager *manager);
 
+gboolean             tracker_data_manager_create_graph (TrackerDataManager  *manager,
+                                                        const gchar         *name,
+                                                        GError             **error);
+
+gboolean             tracker_data_manager_drop_graph (TrackerDataManager  *manager,
+                                                      const gchar         *name,
+                                                      GError             **error);
+
+gint                 tracker_data_manager_find_graph       (TrackerDataManager *manager,
+                                                            const gchar        *name);
+const gchar *        tracker_data_manager_find_graph_by_id (TrackerDataManager *manager,
+                                                            gint                id);
+
 G_END_DECLS
 
 #endif /* __LIBTRACKER_DATA_MANAGER_H__ */
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 333920630..bc1997127 100644
--- a/src/libtracker-data/tracker-db-manager.c
+++ b/src/libtracker-data/tracker-db-manager.c
@@ -1277,3 +1277,43 @@ 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, *escaped;
+       GFile *file;
+
+       filename = g_strdup_printf ("%s.db", name);
+       escaped = g_uri_escape_string (filename, NULL, FALSE);
+       file = g_file_get_child (db_manager->cache_location, escaped);
+       g_free (filename);
+       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_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 06dee6ba4..5ce937773 100644
--- a/src/libtracker-data/tracker-db-manager.h
+++ b/src/libtracker-data/tracker-db-manager.h
@@ -99,6 +99,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]