[tracker/wip/carlosg/test-error-fixes: 4/5] libtracker-data: Check for already visited properties during flush




commit 0f2b8b66f820da677f1cdb73ad1bf44b90246f4c
Author: Carlos Garnacho <carlosg gnome org>
Date:   Tue Jul 13 12:23:40 2021 +0200

    libtracker-data: Check for already visited properties during flush
    
    Due to TrackerResource insertion trying to avoid too frequent flushing,
    we might end up with a single batch containing multiple single-valued
    property delete+insert changes for the same resource/property. These
    currently fail with "multiple values for single-valued property" errors
    but that will be fixed in a followup commit.
    
    If these got through, we would want to avoid telling SQLite about
    these properties several times, e.g.:
    
      INSERT OR REPLACE INTO ... (ID, "nfo:fileSize", "nfo:fileSize")
    
    Since what happens then is unspecified (SQLite chooses to honor the
    first value and ignore the second).
    
    To fix this, check the already visited properties when generating
    the INSERT/UPDATE statement for single-valued properties in a class
    table, and ensure we stick to the last given value.
    
    This avoids having to prematurely flush just to keep these two
    changes separate, and coalesces things the right way (i.e. we end
    up with the good, last value).

 src/libtracker-data/tracker-data-update.c | 30 +++++++++++++++++++++++++-----
 1 file changed, 25 insertions(+), 5 deletions(-)
---
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index cbd2fc46a..2103271b0 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -874,6 +874,8 @@ tracker_data_resource_buffer_flush (TrackerData                      *data,
                        }
                } else {
                        GString *sql, *values_sql;
+                       GHashTable *visited_properties;
+                       gint n;
 
                        if (table->delete_row) {
                                /* remove row from class table */
@@ -917,19 +919,28 @@ tracker_data_resource_buffer_flush (TrackerData                      *data,
                                g_string_append (sql, " SET ");
                        }
 
-                       for (i = 0; i < table->properties->len; i++) {
-                               property = &g_array_index (table->properties, 
TrackerDataUpdateBufferProperty, i);
+                       visited_properties = g_hash_table_new (g_str_hash, g_str_equal);
+
+                       for (n = table->properties->len - 1; n >= 0; n--) {
+                               property = &g_array_index (table->properties, 
TrackerDataUpdateBufferProperty, n);
+                               if (g_hash_table_contains (visited_properties, property->name))
+                                       continue;
+
                                if (table->insert) {
                                        g_string_append_printf (sql, ", \"%s\"", property->name);
                                        g_string_append (values_sql, ", ?");
                                } else {
-                                       if (i > 0) {
+                                       if (n < (int) table->properties->len - 1) {
                                                g_string_append (sql, ", ");
                                        }
                                        g_string_append_printf (sql, "\"%s\" = ?", property->name);
                                }
+
+                               g_hash_table_add (visited_properties, (gpointer) property->name);
                        }
 
+                       g_hash_table_unref (visited_properties);
+
                        if (table->insert) {
                                g_string_append (sql, ")");
                                g_string_append (values_sql, ")");
@@ -966,16 +977,25 @@ tracker_data_resource_buffer_flush (TrackerData                      *data,
                                param = 0;
                        }
 
-                       for (i = 0; i < table->properties->len; i++) {
-                               property = &g_array_index (table->properties, 
TrackerDataUpdateBufferProperty, i);
+                       visited_properties = g_hash_table_new (g_str_hash, g_str_equal);
+
+                       for (n = table->properties->len - 1; n >= 0; n--) {
+                               property = &g_array_index (table->properties, 
TrackerDataUpdateBufferProperty, n);
+                               if (g_hash_table_contains (visited_properties, property->name))
+                                       continue;
+
                                if (property->delete_value) {
                                        /* just set value to NULL for single value properties */
                                        tracker_db_statement_bind_null (stmt, param++);
                                } else {
                                        statement_bind_gvalue (stmt, &param, &property->value);
                                }
+
+                               g_hash_table_add (visited_properties, (gpointer) property->name);
                        }
 
+                       g_hash_table_unref (visited_properties);
+
                        if (!table->insert) {
                                tracker_db_statement_bind_int (stmt, param++, resource->id);
                        }


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