diff options
author | Carlos Garnacho <carlosg@gnome.org> | 2020-10-11 18:33:44 +0200 |
---|---|---|
committer | Carlos Garnacho <carlosg@gnome.org> | 2020-10-11 19:25:03 +0200 |
commit | 2b9b3118549bc3251a5c340cc1d471af513fdc88 (patch) | |
tree | 64cde76fec60f40c2d1969bfb3ca597370b96a44 | |
parent | ffb2eecda216282ab425ede2a90ed0db8693b4e5 (diff) | |
download | tracker-wip/carlosg/iterative-update.tar.gz |
libtracker-data: Process Update rule iterativelywip/carlosg/iterative-update
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
-rw-r--r-- | src/libtracker-data/tracker-sparql.c | 45 |
1 files 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; |