From dda0e80053d077c0e553fb795f99abecbe27328d Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 13 Dec 2020 16:34:45 +0100 Subject: libtracker-data: Drop "fts" argument from lowlevel database change handling These are no longer involved in the handling of FTS, and can be removed. --- src/libtracker-data/tracker-data-update.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c index ef1ea0510..600789b22 100644 --- a/src/libtracker-data/tracker-data-update.c +++ b/src/libtracker-data/tracker-data-update.c @@ -85,7 +85,6 @@ struct _TrackerDataUpdateBufferProperty { const gchar *name; GValue value; guint date_time : 1; - guint fts : 1; guint delete_all_values : 1; }; @@ -146,7 +145,6 @@ static void cache_insert_value (TrackerData *data, const gchar *field_name, GValue *value, gboolean multiple_values, - gboolean fts, gboolean date_time); static GArray *get_old_property_values (TrackerData *data, TrackerProperty *property, @@ -572,7 +570,7 @@ cache_ensure_table (TrackerData *data, g_value_init (&gvalue, G_TYPE_INT64); g_value_set_int64 (&gvalue, get_transaction_modseq (data)); cache_insert_value (data, "rdfs:Resource", "nrl:modified", - &gvalue, FALSE, FALSE, FALSE); + &gvalue, FALSE, FALSE); } table = g_hash_table_lookup (data->resource_buffer->tables, table_name); @@ -602,7 +600,6 @@ cache_insert_value (TrackerData *data, const gchar *field_name, GValue *value, gboolean multiple_values, - gboolean fts, gboolean date_time) { TrackerDataUpdateBufferTable *table; @@ -614,7 +611,6 @@ cache_insert_value (TrackerData *data, g_value_init (&property.value, G_VALUE_TYPE (value)); g_value_copy (value, &property.value); - property.fts = fts; property.date_time = date_time; table = cache_ensure_table (data, table_name, multiple_values); @@ -637,14 +633,12 @@ static void cache_delete_all_values (TrackerData *data, const gchar *table_name, const gchar *field_name, - gboolean fts, gboolean date_time) { TrackerDataUpdateBufferTable *table; TrackerDataUpdateBufferProperty property = { 0 }; property.name = field_name; - property.fts = fts; property.date_time = date_time; property.delete_all_values = TRUE; @@ -659,7 +653,6 @@ cache_delete_value (TrackerData *data, const gchar *field_name, GValue *value, gboolean multiple_values, - gboolean fts, gboolean date_time) { TrackerDataUpdateBufferTable *table; @@ -669,7 +662,6 @@ cache_delete_value (TrackerData *data, g_value_init (&property.value, G_VALUE_TYPE (value)); g_value_copy (value, &property.value); - property.fts = fts; property.date_time = date_time; table = cache_ensure_table (data, table_name, multiple_values); @@ -1169,7 +1161,7 @@ cache_create_service_decomposed (TrackerData *data, g_value_set_int64 (&gvalue, class_id); cache_insert_value (data, "rdfs:Resource_rdf:type", "rdf:type", - &gvalue, TRUE, FALSE, FALSE); + &gvalue, TRUE, FALSE); tracker_data_dispatch_insert_statement_callbacks (data, tracker_property_get_id (tracker_ontologies_get_rdf_type (ontologies)), @@ -1218,7 +1210,6 @@ cache_create_service_decomposed (TrackerData *data, tracker_property_get_name (*domain_indexes), v, tracker_property_get_multiple_values (*domain_indexes), - tracker_property_get_fulltext_indexed (*domain_indexes), tracker_property_get_data_type (*domain_indexes) == TRACKER_PROPERTY_TYPE_DATETIME); } @@ -1691,7 +1682,6 @@ process_domain_indexes (TrackerData *data, field_name, gvalue, FALSE, - tracker_property_get_fulltext_indexed (property), tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); } domain_index_classes++; @@ -1797,7 +1787,6 @@ cache_insert_metadata_decomposed (TrackerData *data, cache_insert_value (data, table_name, field_name, &value, multiple_values, - tracker_property_get_fulltext_indexed (property), tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); if (!multiple_values) { @@ -1852,7 +1841,6 @@ delete_metadata_decomposed (TrackerData *data, } else { cache_delete_value (data, table_name, field_name, &value, multiple_values, - tracker_property_get_fulltext_indexed (property), tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); if (!multiple_values) { @@ -1866,7 +1854,6 @@ delete_metadata_decomposed (TrackerData *data, tracker_class_get_name (*domain_index_classes), field_name, &value, multiple_values, - tracker_property_get_fulltext_indexed (property), tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); } domain_index_classes++; @@ -2009,7 +1996,6 @@ cache_delete_resource_type_full (TrackerData *data, value_set_remove_value (old_values, old_gvalue); cache_delete_value (data, table_name, field_name, ©, multiple_values, - tracker_property_get_fulltext_indexed (prop), tracker_property_get_data_type (prop) == TRACKER_PROPERTY_TYPE_DATETIME); if (!multiple_values) { @@ -2022,7 +2008,6 @@ cache_delete_resource_type_full (TrackerData *data, tracker_class_get_name (*domain_index_classes), field_name, ©, multiple_values, - tracker_property_get_fulltext_indexed (prop), tracker_property_get_data_type (prop) == TRACKER_PROPERTY_TYPE_DATETIME); } domain_index_classes++; @@ -2260,7 +2245,6 @@ tracker_data_delete_all (TrackerData *data, cache_delete_all_values (data, tracker_property_get_table_name (property), tracker_property_get_name (property), - tracker_property_get_fulltext_indexed (property), tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); } else { cache_delete_value (data, @@ -2268,7 +2252,6 @@ tracker_data_delete_all (TrackerData *data, tracker_property_get_name (property), &g_array_index (old_values, GValue, 0), FALSE, - tracker_property_get_fulltext_indexed (property), tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); } @@ -2296,7 +2279,6 @@ delete_single_valued (TrackerData *data, cache_delete_all_values (data, tracker_property_get_table_name (field), tracker_property_get_name (field), - tracker_property_get_fulltext_indexed (field), tracker_property_get_data_type (field) == TRACKER_PROPERTY_TYPE_DATETIME); } else if (!multiple_values) { GError *inner_error = NULL; @@ -2310,7 +2292,6 @@ delete_single_valued (TrackerData *data, tracker_property_get_name (field), &g_array_index (old_values, GValue, 0), FALSE, - tracker_property_get_fulltext_indexed (field), tracker_property_get_data_type (field) == TRACKER_PROPERTY_TYPE_DATETIME); } else { /* no need to error out if statement does not exist for any reason */ @@ -2550,7 +2531,6 @@ tracker_data_update_statement (TrackerData *data, cache_delete_all_values (data, tracker_property_get_table_name (property), tracker_property_get_name (property), - tracker_property_get_fulltext_indexed (property), tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); } else { if (!resource_buffer_switch (data, graph, subject, error)) -- cgit v1.2.1 From fd9a62d68d43ad65d6d25355b8cbc818322e525b Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 13 Dec 2020 16:37:22 +0100 Subject: libtracker-data: Drop "date_time" argument from lowlevel database change handling These no longer need any special handling (as they no longer consist of 2 database columns). This can be dropped. --- src/libtracker-data/tracker-data-update.c | 56 ++++++++++--------------------- 1 file changed, 18 insertions(+), 38 deletions(-) diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c index 600789b22..5d5f539e7 100644 --- a/src/libtracker-data/tracker-data-update.c +++ b/src/libtracker-data/tracker-data-update.c @@ -84,7 +84,6 @@ struct _TrackerDataUpdateBufferResource { struct _TrackerDataUpdateBufferProperty { const gchar *name; GValue value; - guint date_time : 1; guint delete_all_values : 1; }; @@ -144,8 +143,7 @@ static void cache_insert_value (TrackerData *data, const gchar *table_name, const gchar *field_name, GValue *value, - gboolean multiple_values, - gboolean date_time); + gboolean multiple_values); static GArray *get_old_property_values (TrackerData *data, TrackerProperty *property, GError **error); @@ -570,7 +568,7 @@ cache_ensure_table (TrackerData *data, g_value_init (&gvalue, G_TYPE_INT64); g_value_set_int64 (&gvalue, get_transaction_modseq (data)); cache_insert_value (data, "rdfs:Resource", "nrl:modified", - &gvalue, FALSE, FALSE); + &gvalue, FALSE); } table = g_hash_table_lookup (data->resource_buffer->tables, table_name); @@ -599,8 +597,7 @@ cache_insert_value (TrackerData *data, const gchar *table_name, const gchar *field_name, GValue *value, - gboolean multiple_values, - gboolean date_time) + gboolean multiple_values) { TrackerDataUpdateBufferTable *table; TrackerDataUpdateBufferProperty property = { 0 }; @@ -611,7 +608,6 @@ cache_insert_value (TrackerData *data, g_value_init (&property.value, G_VALUE_TYPE (value)); g_value_copy (value, &property.value); - property.date_time = date_time; table = cache_ensure_table (data, table_name, multiple_values); g_array_append_val (table->properties, property); @@ -632,14 +628,12 @@ cache_delete_row (TrackerData *data, static void cache_delete_all_values (TrackerData *data, const gchar *table_name, - const gchar *field_name, - gboolean date_time) + const gchar *field_name) { TrackerDataUpdateBufferTable *table; TrackerDataUpdateBufferProperty property = { 0 }; property.name = field_name; - property.date_time = date_time; property.delete_all_values = TRUE; table = cache_ensure_table (data, table_name, TRUE); @@ -652,8 +646,7 @@ cache_delete_value (TrackerData *data, const gchar *table_name, const gchar *field_name, GValue *value, - gboolean multiple_values, - gboolean date_time) + gboolean multiple_values) { TrackerDataUpdateBufferTable *table; TrackerDataUpdateBufferProperty property = { 0 }; @@ -662,7 +655,6 @@ cache_delete_value (TrackerData *data, g_value_init (&property.value, G_VALUE_TYPE (value)); g_value_copy (value, &property.value); - property.date_time = date_time; table = cache_ensure_table (data, table_name, multiple_values); table->delete_value = TRUE; @@ -1161,7 +1153,7 @@ cache_create_service_decomposed (TrackerData *data, g_value_set_int64 (&gvalue, class_id); cache_insert_value (data, "rdfs:Resource_rdf:type", "rdf:type", - &gvalue, TRUE, FALSE); + &gvalue, TRUE); tracker_data_dispatch_insert_statement_callbacks (data, tracker_property_get_id (tracker_ontologies_get_rdf_type (ontologies)), @@ -1209,8 +1201,7 @@ cache_create_service_decomposed (TrackerData *data, tracker_class_get_name (cl), tracker_property_get_name (*domain_indexes), v, - tracker_property_get_multiple_values (*domain_indexes), - tracker_property_get_data_type (*domain_indexes) == TRACKER_PROPERTY_TYPE_DATETIME); + tracker_property_get_multiple_values (*domain_indexes)); } domain_indexes++; @@ -1681,8 +1672,7 @@ process_domain_indexes (TrackerData *data, tracker_class_get_name (*domain_index_classes), field_name, gvalue, - FALSE, - tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); + FALSE); } domain_index_classes++; } @@ -1786,8 +1776,7 @@ cache_insert_metadata_decomposed (TrackerData *data, } else { cache_insert_value (data, table_name, field_name, &value, - multiple_values, - tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); + multiple_values); if (!multiple_values) { process_domain_indexes (data, property, &value, field_name); @@ -1840,8 +1829,7 @@ delete_metadata_decomposed (TrackerData *data, /* value not found */ } else { cache_delete_value (data, table_name, field_name, - &value, multiple_values, - tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); + &value, multiple_values); if (!multiple_values) { TrackerClass **domain_index_classes; @@ -1853,8 +1841,7 @@ delete_metadata_decomposed (TrackerData *data, cache_delete_value (data, tracker_class_get_name (*domain_index_classes), field_name, - &value, multiple_values, - tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); + &value, multiple_values); } domain_index_classes++; } @@ -1995,8 +1982,7 @@ cache_delete_resource_type_full (TrackerData *data, value_set_remove_value (old_values, old_gvalue); cache_delete_value (data, table_name, field_name, - ©, multiple_values, - tracker_property_get_data_type (prop) == TRACKER_PROPERTY_TYPE_DATETIME); + ©, multiple_values); if (!multiple_values) { TrackerClass **domain_index_classes; @@ -2007,8 +1993,7 @@ cache_delete_resource_type_full (TrackerData *data, cache_delete_value (data, tracker_class_get_name (*domain_index_classes), field_name, - ©, multiple_values, - tracker_property_get_data_type (prop) == TRACKER_PROPERTY_TYPE_DATETIME); + ©, multiple_values); } domain_index_classes++; } @@ -2244,15 +2229,13 @@ tracker_data_delete_all (TrackerData *data, if (tracker_property_get_multiple_values (property)) { cache_delete_all_values (data, tracker_property_get_table_name (property), - tracker_property_get_name (property), - tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); + tracker_property_get_name (property)); } else { cache_delete_value (data, tracker_property_get_table_name (property), tracker_property_get_name (property), &g_array_index (old_values, GValue, 0), - FALSE, - tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); + FALSE); } return TRUE; @@ -2278,8 +2261,7 @@ delete_single_valued (TrackerData *data, if (super_is_single_valued && multiple_values) { cache_delete_all_values (data, tracker_property_get_table_name (field), - tracker_property_get_name (field), - tracker_property_get_data_type (field) == TRACKER_PROPERTY_TYPE_DATETIME); + tracker_property_get_name (field)); } else if (!multiple_values) { GError *inner_error = NULL; GArray *old_values; @@ -2291,8 +2273,7 @@ delete_single_valued (TrackerData *data, tracker_property_get_table_name (field), tracker_property_get_name (field), &g_array_index (old_values, GValue, 0), - FALSE, - tracker_property_get_data_type (field) == TRACKER_PROPERTY_TYPE_DATETIME); + FALSE); } else { /* no need to error out if statement does not exist for any reason */ g_clear_error (&inner_error); @@ -2530,8 +2511,7 @@ tracker_data_update_statement (TrackerData *data, cache_delete_all_values (data, tracker_property_get_table_name (property), - tracker_property_get_name (property), - tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_DATETIME); + tracker_property_get_name (property)); } else { if (!resource_buffer_switch (data, graph, subject, error)) return; -- cgit v1.2.1 From e2f65f38aa0abe458935a02bed7d575c51e35c36 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sat, 19 Dec 2020 22:55:44 +0100 Subject: libtracker-data: Propagate TrackerResource deletes to subproperties This fast path was missing the propagation to superproperties necessary to be equivalent to the issued SPARQL. Make it sure deleted properties propagate to superproperties. --- src/libtracker-data/tracker-data-update.c | 75 +++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 13 deletions(-) diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c index 5d5f539e7..2ab0f9ef3 100644 --- a/src/libtracker-data/tracker-data-update.c +++ b/src/libtracker-data/tracker-data-update.c @@ -2188,6 +2188,65 @@ tracker_data_delete_statement (TrackerData *data, } } +static gboolean +delete_all_helper (TrackerData *data, + const gchar *graph, + const gchar *subject, + TrackerProperty *subproperty, + TrackerProperty *property, + GArray *old_values, + GError **error) +{ + TrackerProperty **super_properties; + GArray *super_old_values; + GValue *value; + gint i; + + if (subproperty == property) { + if (tracker_property_get_multiple_values (property)) { + cache_delete_all_values (data, + tracker_property_get_table_name (property), + tracker_property_get_name (property)); + } else { + cache_delete_value (data, + tracker_property_get_table_name (property), + tracker_property_get_name (property), + &g_array_index (old_values, GValue, 0), + FALSE); + } + } else { + super_old_values = get_old_property_values (data, property, error); + if (!super_old_values) + return FALSE; + + for (i = 0; i < old_values->len; i++) { + value = &g_array_index (old_values, GValue, i); + + if (!value_set_remove_value (super_old_values, value)) + continue; + + cache_delete_value (data, + tracker_property_get_table_name (property), + tracker_property_get_name (property), + value, + tracker_property_get_multiple_values (property)); + } + } + + /* also delete super property values */ + super_properties = tracker_property_get_super_properties (property); + while (*super_properties) { + if (!delete_all_helper (data, graph, subject, + subproperty, *super_properties, + old_values, error)) + return FALSE; + + super_properties++; + } + + return TRUE; +} + static gboolean tracker_data_delete_all (TrackerData *data, const gchar *graph, @@ -2226,19 +2285,9 @@ tracker_data_delete_all (TrackerData *data, return FALSE; } - if (tracker_property_get_multiple_values (property)) { - cache_delete_all_values (data, - tracker_property_get_table_name (property), - tracker_property_get_name (property)); - } else { - cache_delete_value (data, - tracker_property_get_table_name (property), - tracker_property_get_name (property), - &g_array_index (old_values, GValue, 0), - FALSE); - } - - return TRUE; + return delete_all_helper (data, graph, subject, + property, property, + old_values, error); } static gboolean -- cgit v1.2.1 From c8bc4ee7195f4c430cf2c17e123a591d69ef0a70 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 20 Dec 2020 14:33:18 +0100 Subject: libtracker-data: Reduce internal database change buffer size Once we are done coalescing multiple properties together for a same resource/graph, this stops being a benefit. Reduce this buffer size as those are usually clustered together. This is actually a tiny bit faster, too. --- src/libtracker-data/tracker-data-update.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c index 2ab0f9ef3..633d5130a 100644 --- a/src/libtracker-data/tracker-data-update.c +++ b/src/libtracker-data/tracker-data-update.c @@ -1102,7 +1102,7 @@ tracker_data_update_buffer_might_flush (TrackerData *data, graph = g_ptr_array_index (data->update_buffer.graphs, i); count += g_hash_table_size (graph->resources); - if (count >= 1000) { + if (count >= 50) { tracker_data_update_buffer_flush (data, error); break; } -- cgit v1.2.1 From 4c2246c115e08ca5bde8bee670ec7640b5122da6 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Thu, 31 Dec 2020 12:08:50 +0100 Subject: libtracker-data: Do not implicitly delete rdf:type relation Delete this explicitly before deleting the row, we want things explicit as we'll be managing refcount in code. There is also the slight inconsistence that deleting a "rdfs:Resource" will have the rdf:type deletion go together with the handling of all other rdfs:Resource properties, and then again on each of the subclasses being deleted. Ensure this is done in one place, so refcount does not get messed up. --- src/libtracker-data/tracker-data-update.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c index 633d5130a..e7e1e19d3 100644 --- a/src/libtracker-data/tracker-data-update.c +++ b/src/libtracker-data/tracker-data-update.c @@ -868,23 +868,6 @@ tracker_data_resource_buffer_flush (TrackerData *data, GString *sql, *values_sql; if (table->delete_row) { - /* remove entry from rdf:type table */ - stmt = tracker_db_interface_create_vstatement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, &actual_error, - "DELETE FROM \"%s\".\"rdfs:Resource_rdf:type\" WHERE ID = ? AND \"rdf:type\" = ?", - database); - - if (stmt) { - tracker_db_statement_bind_int (stmt, 0, resource->id); - tracker_db_statement_bind_int (stmt, 1, tracker_class_get_id (table->class)); - tracker_db_statement_execute (stmt, &actual_error); - g_object_unref (stmt); - } - - if (actual_error) { - g_propagate_error (error, actual_error); - return; - } - /* remove row from class table */ stmt = tracker_db_interface_create_vstatement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, &actual_error, "DELETE FROM \"%s\".\"%s\" WHERE ID = ?", @@ -1877,6 +1860,7 @@ cache_delete_resource_type_full (TrackerData *data, GError *error = NULL; TrackerOntologies *ontologies; const gchar *database; + GValue gvalue = G_VALUE_INIT; iface = tracker_data_manager_get_writable_db_interface (data->manager); ontologies = tracker_data_manager_get_ontologies (data->manager); @@ -1963,9 +1947,10 @@ cache_delete_resource_type_full (TrackerData *data, prop = properties[p]; - if (tracker_property_get_domain (prop) != class) { + if (prop == tracker_ontologies_get_rdf_type (ontologies)) + continue; + if (tracker_property_get_domain (prop) != class) continue; - } multiple_values = tracker_property_get_multiple_values (prop); table_name = tracker_property_get_table_name (prop); @@ -2003,6 +1988,11 @@ cache_delete_resource_type_full (TrackerData *data, } } + g_value_init (&gvalue, G_TYPE_INT64); + g_value_set_int64 (&gvalue, tracker_class_get_id (class)); + cache_delete_value (data, "rdfs:Resource_rdf:type", "rdf:type", + &gvalue, TRUE); + cache_delete_row (data, class); tracker_data_dispatch_delete_statement_callbacks (data, -- cgit v1.2.1 From 2dfd2ec1ae1e93a46eeb4133499d51698a59a624 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Sun, 20 Dec 2020 12:09:50 +0100 Subject: libtracker-data: Manage resource refcount in DB via code Triggers take a performance toll, managing the refcount manually does fare a bit better. There's several reasons here: - Triggers added by hundreds as we do takes a performance hit, e.g. adding dumb "SELECT 1" triggers vs. not adding them still has a visible effect. - The updates in the triggers are rather dumb, eg. executing for a property on insertions, even though that property might be null. These queries could be avoided entirely. - Managing refcounts manually means we coalesce many references on a same resource (eg. rdf:type relations) in a single update. Do this refcount maintenance in code, in order to stay ABI compatible and (cross fingers) avoid DB refcount bugs in the future, the rules are the same: - Each row in a class table gets a refcount - Each value in a rdfs:Resource property adds a reference to the resource being pointed to. - In addition, multivalued rdfs:Resource properties also add one reference per value to the resource holding the property. - Not observed: domainIndex properties transferred from superclasses This makes insertions and updates sensibly faster, e.g. up to 25% faster for "INSERT DATA { _:u a rdfs:Resource }" inserted via TrackerBatch/TrackerResource. Bonus points: We don't need to set up those runtime triggers anymore, so TrackerSparqlConnection initialization is also faster. --- src/libtracker-data/tracker-data-manager.c | 231 ++++------------------------- src/libtracker-data/tracker-data-update.c | 199 ++++++++++++++++++++++++- 2 files changed, 228 insertions(+), 202 deletions(-) diff --git a/src/libtracker-data/tracker-data-manager.c b/src/libtracker-data/tracker-data-manager.c index 23291722d..c71d6672f 100644 --- a/src/libtracker-data/tracker-data-manager.c +++ b/src/libtracker-data/tracker-data-manager.c @@ -2762,191 +2762,6 @@ schedule_copy (GPtrArray *schedule, g_ptr_array_add (schedule, sched); } -static void -create_insert_delete_triggers (TrackerDBInterface *iface, - const gchar *database, - const gchar *table_name, - const gchar * const *properties, - gint n_properties, - GError **error) -{ - GError *internal_error = NULL; - GString *trigger_query; - gint i; - - /* Insert trigger */ - tracker_db_interface_execute_query (iface, &internal_error, - "DROP TRIGGER IF EXISTS \"%s\".\"trigger_insert_%s\" ", - database, - table_name); - if (internal_error) { - g_propagate_error (error, internal_error); - return; - } - - trigger_query = g_string_new (NULL); - g_string_append_printf (trigger_query, - "CREATE TRIGGER \"%s\".\"trigger_insert_%s\" " - "AFTER INSERT ON \"%s\" " - "FOR EACH ROW BEGIN ", - database, table_name, - table_name); - for (i = 0; i < n_properties; i++) { - g_string_append_printf (trigger_query, - "INSERT OR IGNORE INTO Refcount (ROWID, Refcount) " - "SELECT NEW.\"%s\", 0 WHERE NEW.\"%s\" IS NOT NULL; " - "UPDATE Refcount SET Refcount = Refcount + 1 WHERE Refcount.ROWID = NEW.\"%s\"; ", - properties[i], - properties[i], - properties[i]); - } - - g_string_append (trigger_query, "END; "); - tracker_db_interface_execute_query (iface, &internal_error, - "%s", trigger_query->str); - g_string_free (trigger_query, TRUE); - - if (internal_error) { - g_propagate_error (error, internal_error); - return; - } - - /* Delete trigger */ - tracker_db_interface_execute_query (iface, &internal_error, - "DROP TRIGGER IF EXISTS \"%s\".\"trigger_delete_%s\" ", - database, - table_name); - if (internal_error) { - g_propagate_error (error, internal_error); - return; - } - - trigger_query = g_string_new (NULL); - g_string_append_printf (trigger_query, - "CREATE TRIGGER \"%s\".\"trigger_delete_%s\" " - "AFTER DELETE ON \"%s\" " - "FOR EACH ROW BEGIN ", - database, table_name, - table_name); - for (i = 0; i < n_properties; i++) { - g_string_append_printf (trigger_query, - "UPDATE Refcount SET Refcount = Refcount - 1 WHERE Refcount.rowid = OLD.\"%s\"; " - "DELETE FROM Refcount WHERE Refcount.ROWID = OLD.\"%s\" AND Refcount.Refcount = 0; ", - properties[i], properties[i]); - } - - g_string_append (trigger_query, "END; "); - tracker_db_interface_execute_query (iface, &internal_error, - "%s", trigger_query->str); - g_string_free (trigger_query, TRUE); - - if (internal_error) { - g_propagate_error (error, internal_error); - return; - } -} - -static void -create_table_triggers (TrackerDataManager *manager, - TrackerDBInterface *iface, - const gchar *database, - TrackerClass *klass, - GError **error) -{ - const gchar *property_name; - TrackerProperty **properties, *property; - GError *internal_error = NULL; - GPtrArray *trigger_properties; - guint i, n_props; - - trigger_properties = g_ptr_array_new (); - g_ptr_array_add (trigger_properties, "ROWID"); - - properties = tracker_ontologies_get_properties (manager->ontologies, &n_props); - - for (i = 0; i < n_props; i++) { - gboolean multivalued; - gchar *table_name; - - property = properties[i]; - - if (tracker_property_get_domain (property) != klass || - tracker_property_get_data_type (property) != TRACKER_PROPERTY_TYPE_RESOURCE) - continue; - - property_name = tracker_property_get_name (property); - multivalued = tracker_property_get_multiple_values (property); - - if (multivalued) { - const gchar * const properties[] = { "ID", property_name }; - - table_name = g_strdup_printf ("%s_%s", - tracker_class_get_name (klass), - property_name); - - create_insert_delete_triggers (iface, database, table_name, properties, - G_N_ELEMENTS (properties), - &internal_error); - if (internal_error) { - g_propagate_error (error, internal_error); - g_ptr_array_unref (trigger_properties); - g_free (table_name); - return; - } - } else { - table_name = g_strdup (tracker_class_get_name (klass)); - g_ptr_array_add (trigger_properties, (gchar *) property_name); - } - - tracker_db_interface_execute_query (iface, &internal_error, - "DROP TRIGGER IF EXISTS \"trigger_update_%s_%s\"", - tracker_class_get_name (klass), - property_name); - if (internal_error) { - g_propagate_error (error, internal_error); - g_ptr_array_unref (trigger_properties); - g_free (table_name); - return; - } - - tracker_db_interface_execute_query (iface, &internal_error, - "CREATE TRIGGER \"%s\".\"trigger_update_%s_%s\" " - "AFTER UPDATE OF \"%s\" ON \"%s\" " - "FOR EACH ROW BEGIN " - "INSERT OR IGNORE INTO Refcount (ROWID, Refcount) " - "SELECT NEW.\"%s\", 0 WHERE NEW.\"%s\" IS NOT NULL; " - "UPDATE Refcount SET Refcount = Refcount + 1 WHERE Refcount.ROWID = NEW.\"%s\"; " - "UPDATE Refcount SET Refcount = Refcount - 1 WHERE Refcount.rowid = OLD.\"%s\";" - "DELETE FROM Refcount WHERE Refcount.ROWID = OLD.\"%s\" AND Refcount.Refcount = 0; " - "END", - database, - tracker_class_get_name (klass), - property_name, - property_name, table_name, - property_name, property_name, - property_name, property_name, property_name); - g_free (table_name); - - if (internal_error) { - g_propagate_error (error, internal_error); - g_ptr_array_unref (trigger_properties); - return; - } - } - - create_insert_delete_triggers (iface, database, - tracker_class_get_name (klass), - (const gchar * const *) trigger_properties->pdata, - trigger_properties->len, - &internal_error); - g_ptr_array_unref (trigger_properties); - - if (internal_error) { - g_propagate_error (error, internal_error); - return; - } -} - static void create_decomposed_metadata_tables (TrackerDataManager *manager, TrackerDBInterface *iface, @@ -3250,18 +3065,10 @@ create_decomposed_metadata_tables (TrackerDataManager *manager, } } - if (!in_update || in_change || tracker_class_get_is_new (service)) { - /* FIXME: We are trusting object refcount will stay intact across - * ontology changes. One situation where this is not true are - * removal or properties with rdfs:Resource range. - */ - create_table_triggers (manager, iface, database, service, &internal_error); - - if (internal_error) { - g_propagate_error (error, internal_error); - goto error_out; - } - } + /* FIXME: We are trusting object refcount will stay intact across + * ontology changes. One situation where this is not true are + * removal or properties with rdfs:Resource range. + */ if (copy_schedule) { guint i; @@ -4924,7 +4731,7 @@ tracker_data_manager_clear_graph (TrackerDataManager *manager, graph, tracker_class_get_name (classes[i])); if (!stmt) - break; + goto out; tracker_db_statement_execute (stmt, &inner_error); g_object_unref (stmt); @@ -4943,12 +4750,18 @@ tracker_data_manager_clear_graph (TrackerDataManager *manager, tracker_class_get_name (service), tracker_property_get_name (properties[i])); if (!stmt) - break; + goto out; tracker_db_statement_execute (stmt, &inner_error); g_object_unref (stmt); } + tracker_db_interface_execute_query (iface, + &inner_error, + "DELETE FROM \"%s\".Refcount", + graph); +out: + if (inner_error) { g_propagate_error (error, inner_error); return FALSE; @@ -5018,12 +4831,30 @@ tracker_data_manager_copy_graph (TrackerDataManager *manager, tracker_class_get_name (service), tracker_property_get_name (properties[i])); if (!stmt) - break; + goto out; tracker_db_statement_execute (stmt, &inner_error); g_object_unref (stmt); } + /* Transfer refcounts */ + tracker_db_interface_execute_query (iface, + &inner_error, + "INSERT OR IGNORE INTO \"%s\".Refcount " + "SELECT ID, 0 from \"%s\".Refcount", + destination, + source); + if (inner_error) + goto out; + + tracker_db_interface_execute_query (iface, + &inner_error, + "UPDATE \"%s\".Refcount AS B " + "SET Refcount = B.Refcount + A.Refcount " + "FROM (SELECT ID, Refcount FROM \"%s\".Refcount) AS A " + "WHERE B.ID = A.ID", + destination, source); +out: if (inner_error) { g_propagate_error (error, inner_error); return FALSE; diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c index e7e1e19d3..a6b6c9665 100644 --- a/src/libtracker-data/tracker-data-update.c +++ b/src/libtracker-data/tracker-data-update.c @@ -63,6 +63,8 @@ struct _TrackerDataUpdateBufferGraph { /* string -> TrackerDataUpdateBufferResource */ GHashTable *resources; + /* id -> integer */ + GHashTable *refcounts; }; struct _TrackerDataUpdateBufferResource { @@ -1025,10 +1027,167 @@ tracker_data_resource_buffer_flush (TrackerData *data, } } +static void +tracker_data_update_refcount (TrackerData *data, + gint id, + gint refcount) +{ + const TrackerDataUpdateBufferGraph *graph; + gint old_refcount; + + g_assert (data->resource_buffer != NULL); + graph = data->resource_buffer->graph; + + old_refcount = GPOINTER_TO_INT (g_hash_table_lookup (graph->refcounts, + GINT_TO_POINTER (id))); + g_hash_table_insert (graph->refcounts, + GINT_TO_POINTER (id), + GINT_TO_POINTER (old_refcount + refcount)); +} + +static void +tracker_data_resource_ref (TrackerData *data, + gint id, + gboolean multivalued) +{ + if (multivalued) + tracker_data_update_refcount (data, data->resource_buffer->id, 1); + + tracker_data_update_refcount (data, id, 1); +} + +static void +tracker_data_resource_unref (TrackerData *data, + gint id, + gboolean multivalued) +{ + if (multivalued) + tracker_data_update_refcount (data, data->resource_buffer->id, -1); + + tracker_data_update_refcount (data, id, -1); +} + +/* Only applies to multivalued properties */ +static void +tracker_data_resource_unref_all (TrackerData *data, + TrackerProperty *property) +{ + GArray *old_values; + gint i; + + g_assert (tracker_property_get_multiple_values (property) == TRUE); + g_assert (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE); + + old_values = get_old_property_values (data, property, NULL); + + for (i = 0; i < old_values->len; i++) { + GValue *value; + + value = &g_array_index (old_values, GValue, i); + tracker_data_resource_unref (data, g_value_get_int64 (value), TRUE); + } +} + +static void +tracker_data_flush_graph_refcounts (TrackerData *data, + TrackerDataUpdateBufferGraph *graph, + GError **error) +{ + TrackerDBInterface *iface; + TrackerDBStatement *stmt; + GHashTableIter iter; + gpointer key, value; + gint id, refcount; + GError *inner_error = NULL; + const gchar *database; + gchar *insert_query; + gchar *update_query; + gchar *delete_query; + + iface = tracker_data_manager_get_writable_db_interface (data->manager); + database = graph->graph ? graph->graph : "main"; + + insert_query = g_strdup_printf ("INSERT OR IGNORE INTO \"%s\".Refcount (ROWID, Refcount) VALUES (?1, 0)", + database); + update_query = g_strdup_printf ("UPDATE \"%s\".Refcount SET Refcount = Refcount + ?2 WHERE Refcount.ROWID = ?1", + database); + delete_query = g_strdup_printf ("DELETE FROM \"%s\".Refcount WHERE Refcount.ROWID = ?1 AND Refcount.Refcount = 0", + database); + + g_hash_table_iter_init (&iter, graph->refcounts); + + while (g_hash_table_iter_next (&iter, &key, &value)) { + id = GPOINTER_TO_INT (key); + refcount = GPOINTER_TO_INT (value); + + if (refcount > 0) { + stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, + &inner_error, insert_query); + if (inner_error) { + g_propagate_error (error, inner_error); + break; + } + + tracker_db_statement_bind_int (stmt, 0, id); + tracker_db_statement_execute (stmt, &inner_error); + g_object_unref (stmt); + + if (inner_error) { + g_propagate_error (error, inner_error); + break; + } + } + + if (refcount != 0) { + stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, + &inner_error, update_query); + if (inner_error) { + g_propagate_error (error, inner_error); + break; + } + + tracker_db_statement_bind_int (stmt, 0, id); + tracker_db_statement_bind_int (stmt, 1, refcount); + tracker_db_statement_execute (stmt, &inner_error); + g_object_unref (stmt); + + if (inner_error) { + g_propagate_error (error, inner_error); + break; + } + } + + if (refcount < 0) { + stmt = tracker_db_interface_create_statement (iface, TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, + &inner_error, delete_query); + if (inner_error) { + g_propagate_error (error, inner_error); + break; + } + + tracker_db_statement_bind_int (stmt, 0, id); + tracker_db_statement_execute (stmt, &inner_error); + g_object_unref (stmt); + + if (inner_error) { + g_propagate_error (error, inner_error); + break; + } + } + + g_hash_table_iter_remove (&iter); + } + + g_free (insert_query); + g_free (update_query); + g_free (delete_query); +} + static void graph_buffer_free (TrackerDataUpdateBufferGraph *graph) { g_hash_table_unref (graph->resources); + g_hash_table_unref (graph->refcounts); g_free (graph->graph); g_slice_free (TrackerDataUpdateBufferGraph, graph); } @@ -1066,6 +1225,12 @@ tracker_data_update_buffer_flush (TrackerData *data, goto out; } } + + tracker_data_flush_graph_refcounts (data, graph, &actual_error); + if (actual_error) { + g_propagate_error (error, actual_error); + goto out; + } } out: @@ -1130,6 +1295,7 @@ cache_create_service_decomposed (TrackerData *data, g_value_init (&gvalue, G_TYPE_INT64); cache_insert_row (data, cl); + tracker_data_resource_ref (data, data->resource_buffer->id, FALSE); class_id = tracker_class_get_id (cl); ontologies = tracker_data_manager_get_ontologies (data->manager); @@ -1137,6 +1303,7 @@ cache_create_service_decomposed (TrackerData *data, g_value_set_int64 (&gvalue, class_id); cache_insert_value (data, "rdfs:Resource_rdf:type", "rdf:type", &gvalue, TRUE); + tracker_data_resource_ref (data, class_id, TRUE); tracker_data_dispatch_insert_statement_callbacks (data, tracker_property_get_id (tracker_ontologies_get_rdf_type (ontologies)), @@ -1761,6 +1928,9 @@ cache_insert_metadata_decomposed (TrackerData *data, &value, multiple_values); + if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE) + tracker_data_resource_ref (data, g_value_get_int64 (&value), multiple_values); + if (!multiple_values) { process_domain_indexes (data, property, &value, field_name); } @@ -1813,6 +1983,8 @@ delete_metadata_decomposed (TrackerData *data, } else { cache_delete_value (data, table_name, field_name, &value, multiple_values); + if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE) + tracker_data_resource_unref (data, g_value_get_int64 (&value), multiple_values); if (!multiple_values) { TrackerClass **domain_index_classes; @@ -1968,6 +2140,8 @@ cache_delete_resource_type_full (TrackerData *data, value_set_remove_value (old_values, old_gvalue); cache_delete_value (data, table_name, field_name, ©, multiple_values); + if (tracker_property_get_data_type (prop) == TRACKER_PROPERTY_TYPE_RESOURCE) + tracker_data_resource_unref (data, g_value_get_int64 (©), multiple_values); if (!multiple_values) { TrackerClass **domain_index_classes; @@ -1992,8 +2166,10 @@ cache_delete_resource_type_full (TrackerData *data, g_value_set_int64 (&gvalue, tracker_class_get_id (class)); cache_delete_value (data, "rdfs:Resource_rdf:type", "rdf:type", &gvalue, TRUE); + tracker_data_resource_unref (data, tracker_class_get_id (class), TRUE); cache_delete_row (data, class); + tracker_data_resource_unref (data, data->resource_buffer->id, FALSE); tracker_data_dispatch_delete_statement_callbacks (data, tracker_property_get_id (tracker_ontologies_get_rdf_type (ontologies)), @@ -2031,6 +2207,7 @@ ensure_graph_buffer (TrackerDataUpdateBuffer *buffer, } graph_buffer = g_slice_new0 (TrackerDataUpdateBufferGraph); + graph_buffer->refcounts = g_hash_table_new (NULL, NULL); graph_buffer->graph = g_strdup (name); if (graph_buffer->graph) { graph_buffer->id = tracker_data_manager_find_graph (data->manager, @@ -2197,12 +2374,17 @@ delete_all_helper (TrackerData *data, cache_delete_all_values (data, tracker_property_get_table_name (property), tracker_property_get_name (property)); + if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE) + tracker_data_resource_unref_all (data, property); } else { + value = &g_array_index (old_values, GValue, 0); cache_delete_value (data, tracker_property_get_table_name (property), tracker_property_get_name (property), - &g_array_index (old_values, GValue, 0), + value, FALSE); + if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE) + tracker_data_resource_unref (data, g_value_get_int64 (value), FALSE); } } else { super_old_values = get_old_property_values (data, property, error); @@ -2220,6 +2402,10 @@ delete_all_helper (TrackerData *data, tracker_property_get_name (property), value, tracker_property_get_multiple_values (property)); + if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE) { + tracker_data_resource_unref (data, g_value_get_int64 (value), + tracker_property_get_multiple_values (property)); + } } } @@ -2301,6 +2487,8 @@ delete_single_valued (TrackerData *data, cache_delete_all_values (data, tracker_property_get_table_name (field), tracker_property_get_name (field)); + if (tracker_property_get_data_type (field) == TRACKER_PROPERTY_TYPE_RESOURCE) + tracker_data_resource_unref_all (data, field); } else if (!multiple_values) { GError *inner_error = NULL; GArray *old_values; @@ -2308,11 +2496,16 @@ delete_single_valued (TrackerData *data, old_values = get_old_property_values (data, field, &inner_error); if (old_values && old_values->len == 1) { + GValue *value; + + value = &g_array_index (old_values, GValue, 0); cache_delete_value (data, tracker_property_get_table_name (field), tracker_property_get_name (field), - &g_array_index (old_values, GValue, 0), + value, FALSE); + if (tracker_property_get_data_type (field) == TRACKER_PROPERTY_TYPE_RESOURCE) + tracker_data_resource_unref (data, g_value_get_int64 (value), multiple_values); } else { /* no need to error out if statement does not exist for any reason */ g_clear_error (&inner_error); @@ -2551,6 +2744,8 @@ tracker_data_update_statement (TrackerData *data, cache_delete_all_values (data, tracker_property_get_table_name (property), tracker_property_get_name (property)); + if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE) + tracker_data_resource_unref_all (data, property); } else { if (!resource_buffer_switch (data, graph, subject, error)) return; -- cgit v1.2.1