summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garnacho <carlosg@gnome.org>2020-10-11 18:33:44 +0200
committerCarlos Garnacho <carlosg@gnome.org>2020-10-11 19:25:03 +0200
commit2b9b3118549bc3251a5c340cc1d471af513fdc88 (patch)
tree64cde76fec60f40c2d1969bfb3ca597370b96a44
parentffb2eecda216282ab425ede2a90ed0db8693b4e5 (diff)
downloadtracker-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.c45
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;