[tracker/wip/carlosg/iterative-update] libtracker-data: Process Update rule iteratively




commit 2b9b3118549bc3251a5c340cc1d471af513fdc88
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sun Oct 11 18:33:44 2020 +0200

    libtracker-data: Process Update rule iteratively
    
    The Update rule is defined upon itself, we interpret this a bit too
    literally, and do the same thing when interpreting the parse tree. This
    makes the maximum stack size an indirect factor that limits how big a
    series of updates can possibly be. (e.g. the array at
    tracker_sparql_connection_update_array_async)
    
    This is obviously bad, so process the updates iteratively, this will avoid
    hitting stack limits by just concatenating legit updates together.
    
    Fixes: https://gitlab.gnome.org/GNOME/tracker-miners/-/issues/91

 src/libtracker-data/tracker-sparql.c | 45 ++++++++++++++++++++++++------------
 1 file changed, 30 insertions(+), 15 deletions(-)
---
diff --git a/src/libtracker-data/tracker-sparql.c b/src/libtracker-data/tracker-sparql.c
index 2ff43d045..34571e131 100644
--- a/src/libtracker-data/tracker-sparql.c
+++ b/src/libtracker-data/tracker-sparql.c
@@ -2538,32 +2538,47 @@ static gboolean
 translate_Update (TrackerSparql  *sparql,
                   GError        **error)
 {
+       gboolean cont = TRUE;
+
        /* Update ::= Prologue ( Update1 ( ';' Update )? )?
         *
         * TRACKER EXTENSION:
         * ';' separator is made optional.
+        *
+        * Note: Even though the rule is defined recursively, we
+        * process it iteratively here. This is in order to avoid
+        * making maximum update buffer depend on stack size.
         */
-       _call_rule (sparql, NAMED_RULE_Prologue, error);
+       while (cont) {
+               _call_rule (sparql, NAMED_RULE_Prologue, error);
 
-       if (!sparql->current_state->blank_node_map) {
-               sparql->current_state->blank_node_map =
-                       g_hash_table_new_full (g_str_hash, g_str_equal,
-                                              g_free, g_free);
-       }
+               if (!sparql->current_state->blank_node_map) {
+                       sparql->current_state->blank_node_map =
+                               g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                      g_free, g_free);
+               }
 
-       if (_check_in_rule (sparql, NAMED_RULE_Update1)) {
-               if (sparql->blank_nodes)
-                       g_variant_builder_open (sparql->blank_nodes, G_VARIANT_TYPE ("aa{ss}"));
+               if (_check_in_rule (sparql, NAMED_RULE_Update1)) {
+                       if (sparql->blank_nodes)
+                               g_variant_builder_open (sparql->blank_nodes, G_VARIANT_TYPE ("aa{ss}"));
 
-               _call_rule (sparql, NAMED_RULE_Update1, error);
+                       _call_rule (sparql, NAMED_RULE_Update1, error);
 
-               if (sparql->blank_nodes)
-                       g_variant_builder_close (sparql->blank_nodes);
+                       if (sparql->blank_nodes)
+                               g_variant_builder_close (sparql->blank_nodes);
 
-               _optional (sparql, RULE_TYPE_LITERAL, LITERAL_SEMICOLON);
+                       _optional (sparql, RULE_TYPE_LITERAL, LITERAL_SEMICOLON);
 
-               if (_check_in_rule (sparql, NAMED_RULE_Update))
-                       _call_rule (sparql, NAMED_RULE_Update, error);
+                       if (_check_in_rule (sparql, NAMED_RULE_Update)) {
+                               /* Handle the rule inline in the next iteration */
+                               tracker_sparql_iter_next (sparql);
+                               cont = TRUE;
+                       } else {
+                               cont = FALSE;
+                       }
+               } else {
+                       cont = FALSE;
+               }
        }
 
        return TRUE;


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