[tracker/wip/carlosg/transact-graphs: 4/4] libtracker-data: Handle graph updates after commit as a transaction




commit 93951368fc7878b21284722bd17269ceea325404
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sun Aug 23 21:47:15 2020 +0200

    libtracker-data: Handle graph updates after commit as a transaction
    
    After a graph is created/deleted, we update immediately our graph
    accounting. This however didn't take into account that graph operations
    may happen within a transaction, so a readonly interface being spawned
    at the right time might consider those graphs as existing its query even
    though they are not attached yet.
    
    This situation would resolve itself after the last graph is processed,
    and the transaction committed, but for that query it would fail like:
    
      In service 'dbus:org.freedesktop.Tracker3.Miner.Files': no such table: 
http://tracker.api.gnome.org/ontology/v3/tracker#Audio.nfo:Audio
    
    In order to fix that, handle changes to the known graphs as part of the
    transaction, only making it effective after the change is committed, and
    database interfaces would correctly find the graph databases when updated.
    This makes readonly interfaces aware of the graph changes after the
    transaction is committed, not before.
    
    When looking up graphs, it depends on whether the sparql is being executed
    on the update queue or not that it makes sense to return results from the
    graph state mid-transaction or not. Do this based on the TrackerSparql query
    type.
    
    Of course, this means the operation should be rolled back if the
    transaction failed. Also do that.
    
    Fixes: https://gitlab.gnome.org/GNOME/tracker/-/issues/231

 src/libtracker-data/tracker-data-manager.c | 63 ++++++++++++++++++++++++++----
 src/libtracker-data/tracker-data-manager.h |  8 +++-
 src/libtracker-data/tracker-data-update.c  |  9 ++++-
 src/libtracker-data/tracker-sparql.c       | 11 +++++-
 4 files changed, 78 insertions(+), 13 deletions(-)
---
diff --git a/src/libtracker-data/tracker-data-manager.c b/src/libtracker-data/tracker-data-manager.c
index 47d721954..fd02de2a8 100644
--- a/src/libtracker-data/tracker-data-manager.c
+++ b/src/libtracker-data/tracker-data-manager.c
@@ -80,6 +80,7 @@ struct _TrackerDataManager {
        TrackerOntologies *ontologies;
        TrackerData *data_update;
 
+       GHashTable *transaction_graphs;
        GHashTable *graphs;
 
        gchar *status;
@@ -198,8 +199,12 @@ tracker_data_manager_ensure_graphs (TrackerDataManager  *manager,
 }
 
 GHashTable *
-tracker_data_manager_get_graphs (TrackerDataManager *manager)
+tracker_data_manager_get_graphs (TrackerDataManager *manager,
+                                 gboolean            in_transaction)
 {
+       if (manager->transaction_graphs && in_transaction)
+               return manager->transaction_graphs;
+
        return manager->graphs;
 }
 
@@ -4827,6 +4832,25 @@ tracker_data_manager_get_namespaces (TrackerDataManager *manager)
        return ht;
 }
 
+static GHashTable *
+copy_graphs (GHashTable *graphs)
+{
+       GHashTable *copy;
+       GHashTableIter iter;
+       gpointer key, value;
+
+       copy = g_hash_table_new_full (g_str_hash,
+                                     g_str_equal,
+                                     g_free,
+                                     NULL);
+       g_hash_table_iter_init (&iter, graphs);
+
+       while (g_hash_table_iter_next (&iter, &key, &value))
+               g_hash_table_insert (copy, g_strdup (key), value);
+
+       return copy;
+}
+
 gboolean
 tracker_data_manager_create_graph (TrackerDataManager  *manager,
                                    const gchar         *name,
@@ -4852,9 +4876,10 @@ tracker_data_manager_create_graph (TrackerDataManager  *manager,
        if (id == 0)
                goto detach;
 
-       g_hash_table_insert (manager->graphs, g_strdup (name), GINT_TO_POINTER (id));
+       if (!manager->transaction_graphs)
+               manager->transaction_graphs = copy_graphs (manager->graphs);
 
-       manager->generation++;
+       g_hash_table_insert (manager->transaction_graphs, g_strdup (name), GINT_TO_POINTER (id));
 
        return TRUE;
 
@@ -4887,22 +4912,29 @@ tracker_data_manager_drop_graph (TrackerDataManager  *manager,
        if (!tracker_data_delete_graph (manager->data_update, name, error))
                return FALSE;
 
-       manager->generation++;
+       if (!manager->transaction_graphs)
+               manager->transaction_graphs = copy_graphs (manager->graphs);
 
-       if (manager->graphs)
-               g_hash_table_remove (manager->graphs, name);
+       g_hash_table_remove (manager->transaction_graphs, name);
 
        return TRUE;
 }
 
 gint
 tracker_data_manager_find_graph (TrackerDataManager *manager,
-                                 const gchar        *name)
+                                 const gchar        *name,
+                                 gboolean            in_transaction)
 {
        TrackerDBInterface *iface;
        GHashTable *graphs;
 
        iface = tracker_db_manager_get_writable_db_interface (manager->db_manager);
+
+       if (in_transaction && manager->transaction_graphs) {
+               return GPOINTER_TO_INT (g_hash_table_lookup (manager->transaction_graphs,
+                                                            name));
+       }
+
        graphs = tracker_data_manager_ensure_graphs (manager, iface, NULL);
 
        if (!graphs)
@@ -5053,3 +5085,20 @@ tracker_data_manager_get_generation (TrackerDataManager *manager)
 {
        return manager->generation;
 }
+
+void
+tracker_data_manager_commit_graphs (TrackerDataManager *manager)
+{
+       if (manager->transaction_graphs) {
+               g_clear_pointer (&manager->graphs, g_hash_table_unref);
+               manager->graphs = manager->transaction_graphs;
+               manager->transaction_graphs = NULL;
+               manager->generation++;
+       }
+}
+
+void
+tracker_data_manager_rollback_graphs (TrackerDataManager *manager)
+{
+       g_clear_pointer (&manager->transaction_graphs, g_hash_table_unref);
+}
diff --git a/src/libtracker-data/tracker-data-manager.h b/src/libtracker-data/tracker-data-manager.h
index b7572e6d4..dbd4d86fc 100644
--- a/src/libtracker-data/tracker-data-manager.h
+++ b/src/libtracker-data/tracker-data-manager.h
@@ -94,12 +94,16 @@ gboolean             tracker_data_manager_copy_graph  (TrackerDataManager  *mana
                                                        const gchar         *destination,
                                                        GError             **error);
 
-GHashTable *         tracker_data_manager_get_graphs       (TrackerDataManager *manager);
+GHashTable *         tracker_data_manager_get_graphs       (TrackerDataManager *manager,
+                                                            gboolean            in_transaction);
 
 gint                 tracker_data_manager_find_graph       (TrackerDataManager *manager,
-                                                            const gchar        *name);
+                                                            const gchar        *name,
+                                                            gboolean            in_transaction);
 
 guint                tracker_data_manager_get_generation   (TrackerDataManager *manager);
+void                 tracker_data_manager_rollback_graphs (TrackerDataManager *manager);
+void                 tracker_data_manager_commit_graphs (TrackerDataManager *manager);
 
 G_END_DECLS
 
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index abc51860a..86a707dde 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -2014,7 +2014,7 @@ ensure_graph_buffer (TrackerDataUpdateBuffer  *buffer,
                        return graph_buffer;
        }
 
-       if (name && !tracker_data_manager_find_graph (data->manager, name)) {
+       if (name && !tracker_data_manager_find_graph (data->manager, name, TRUE)) {
                if (!tracker_data_manager_create_graph (data->manager, name, error))
                        return NULL;
        }
@@ -2023,7 +2023,8 @@ ensure_graph_buffer (TrackerDataUpdateBuffer  *buffer,
        graph_buffer->graph = g_strdup (name);
        if (graph_buffer->graph) {
                graph_buffer->id = tracker_data_manager_find_graph (data->manager,
-                                                                   graph_buffer->graph);
+                                                                   graph_buffer->graph,
+                                                                   TRUE);
        }
 
        graph_buffer->resources =
@@ -2562,6 +2563,8 @@ tracker_data_commit_transaction (TrackerData  *data,
                data->update_buffer.fts_ever_updated = FALSE;
        }
 
+       tracker_data_manager_commit_graphs (data->manager);
+
        tracker_db_interface_execute_query (iface, NULL, "PRAGMA cache_size = %d", 
TRACKER_DB_CACHE_SIZE_DEFAULT);
 
        g_ptr_array_set_size (data->update_buffer.graphs, 0);
@@ -2592,6 +2595,8 @@ tracker_data_rollback_transaction (TrackerData *data)
                g_clear_error (&ignorable);
        }
 
+       tracker_data_manager_rollback_graphs (data->manager);
+
        tracker_db_interface_execute_query (iface, NULL, "PRAGMA cache_size = %d", 
TRACKER_DB_CACHE_SIZE_DEFAULT);
 
        tracker_data_dispatch_rollback_statement_callbacks (data);
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index 4b8e16534..01515849e 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -688,8 +688,11 @@ static GHashTable *
 tracker_sparql_get_effective_graphs (TrackerSparql *sparql)
 {
        GHashTable *graphs;
+       gboolean in_transaction;
 
-       graphs = tracker_data_manager_get_graphs (sparql->data_manager);
+       in_transaction = sparql->query_type == TRACKER_SPARQL_QUERY_UPDATE;
+       graphs = tracker_data_manager_get_graphs (sparql->data_manager,
+                                                 in_transaction);
 
        if (graphs && sparql->policy.graphs) {
                if (!sparql->policy.filtered_graphs) {
@@ -835,6 +838,7 @@ tracker_sparql_find_graph (TrackerSparql *sparql,
                            const gchar   *name)
 {
        GHashTable *effective_graphs;
+       gboolean in_transaction;
 
        effective_graphs = tracker_sparql_get_effective_graphs (sparql);
        if (!effective_graphs ||
@@ -842,7 +846,10 @@ tracker_sparql_find_graph (TrackerSparql *sparql,
                return 0;
        }
 
-       return tracker_data_manager_find_graph (sparql->data_manager, name);
+       in_transaction = sparql->query_type == TRACKER_SPARQL_QUERY_UPDATE;
+
+       return tracker_data_manager_find_graph (sparql->data_manager, name,
+                                               in_transaction);
 }
 
 static void


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