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




commit bc54d671ed157e16fd45457857a42c99e536ab5d
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.
    
    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 | 48 ++++++++++++++++++++++++++----
 src/libtracker-data/tracker-data-manager.h |  2 ++
 src/libtracker-data/tracker-data-update.c  |  4 +++
 3 files changed, 49 insertions(+), 5 deletions(-)
---
diff --git a/src/libtracker-data/tracker-data-manager.c b/src/libtracker-data/tracker-data-manager.c
index 47d721954..ddd6865d5 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;
@@ -4827,6 +4828,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 +4872,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,10 +4908,10 @@ 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;
 }
@@ -5053,3 +5074,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..378d058ec 100644
--- a/src/libtracker-data/tracker-data-manager.h
+++ b/src/libtracker-data/tracker-data-manager.h
@@ -100,6 +100,8 @@ gint                 tracker_data_manager_find_graph       (TrackerDataManager *
                                                             const gchar        *name);
 
 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..f7413c948 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -2562,6 +2562,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 +2594,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);


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