Blame SOURCES/0005-intervals-Do-not-sort-cached-set-elements-over-and-o.patch

e34dd0
From 013a3b226a0fa5f7a8469bae736150cbf2d092c4 Mon Sep 17 00:00:00 2001
e34dd0
From: Phil Sutter <psutter@redhat.com>
e34dd0
Date: Fri, 24 Jun 2022 16:02:59 +0200
e34dd0
Subject: [PATCH] intervals: Do not sort cached set elements over and over
e34dd0
 again
e34dd0
e34dd0
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1917398
e34dd0
Upstream Status: nftables commit 59e3a59221fb8
e34dd0
e34dd0
commit 59e3a59221fb81c289a0868a85140dd452fb1c30
e34dd0
Author: Phil Sutter <phil@nwl.cc>
e34dd0
Date:   Thu Jun 16 10:56:12 2022 +0200
e34dd0
e34dd0
    intervals: Do not sort cached set elements over and over again
e34dd0
e34dd0
    When adding element(s) to a non-empty set, code merged the two lists and
e34dd0
    sorted the result. With many individual 'add element' commands this
e34dd0
    causes substantial overhead. Make use of the fact that
e34dd0
    existing_set->init is sorted already, sort only the list of new elements
e34dd0
    and use list_splice_sorted() to merge the two sorted lists.
e34dd0
e34dd0
    Add set_sort_splice() and use it for set element overlap detection and
e34dd0
    automerge.
e34dd0
e34dd0
    A test case adding ~25k elements in individual commands completes in
e34dd0
    about 1/4th of the time with this patch applied.
e34dd0
e34dd0
    Joint work with Pablo.
e34dd0
e34dd0
    Fixes: 3da9643fb9ff9 ("intervals: add support to automerge with kernel elements")
e34dd0
    Signed-off-by: Phil Sutter <phil@nwl.cc>
e34dd0
    Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
e34dd0
e34dd0
Signed-off-by: Phil Sutter <psutter@redhat.com>
e34dd0
---
e34dd0
 include/expression.h |  1 +
e34dd0
 src/intervals.c      | 46 +++++++++++++++++++++-----------------------
e34dd0
 src/mergesort.c      |  2 +-
e34dd0
 3 files changed, 24 insertions(+), 25 deletions(-)
e34dd0
e34dd0
diff --git a/include/expression.h b/include/expression.h
e34dd0
index 53194c9..cf7319b 100644
e34dd0
--- a/include/expression.h
e34dd0
+++ b/include/expression.h
e34dd0
@@ -481,6 +481,7 @@ extern struct expr *compound_expr_alloc(const struct location *loc,
e34dd0
 extern void compound_expr_add(struct expr *compound, struct expr *expr);
e34dd0
 extern void compound_expr_remove(struct expr *compound, struct expr *expr);
e34dd0
 extern void list_expr_sort(struct list_head *head);
e34dd0
+extern void list_splice_sorted(struct list_head *list, struct list_head *head);
e34dd0
 
e34dd0
 extern struct expr *concat_expr_alloc(const struct location *loc);
e34dd0
 
e34dd0
diff --git a/src/intervals.c b/src/intervals.c
e34dd0
index e203413..dcc06d1 100644
e34dd0
--- a/src/intervals.c
e34dd0
+++ b/src/intervals.c
e34dd0
@@ -118,6 +118,26 @@ static bool merge_ranges(struct set_automerge_ctx *ctx,
e34dd0
 	return false;
e34dd0
 }
e34dd0
 
e34dd0
+static void set_sort_splice(struct expr *init, struct set *set)
e34dd0
+{
e34dd0
+	struct set *existing_set = set->existing_set;
e34dd0
+
e34dd0
+	set_to_range(init);
e34dd0
+	list_expr_sort(&init->expressions);
e34dd0
+
e34dd0
+	if (!existing_set)
e34dd0
+		return;
e34dd0
+
e34dd0
+	if (existing_set->init) {
e34dd0
+		set_to_range(existing_set->init);
e34dd0
+		list_splice_sorted(&existing_set->init->expressions,
e34dd0
+				   &init->expressions);
e34dd0
+		init_list_head(&existing_set->init->expressions);
e34dd0
+	} else {
e34dd0
+		existing_set->init = set_expr_alloc(&internal_location, set);
e34dd0
+	}
e34dd0
+}
e34dd0
+
e34dd0
 static void setelem_automerge(struct set_automerge_ctx *ctx)
e34dd0
 {
e34dd0
 	struct expr *i, *next, *prev = NULL;
e34dd0
@@ -222,18 +242,7 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
e34dd0
 		return 0;
e34dd0
 	}
e34dd0
 
e34dd0
-	if (existing_set) {
e34dd0
-		if (existing_set->init) {
e34dd0
-			list_splice_init(&existing_set->init->expressions,
e34dd0
-					 &init->expressions);
e34dd0
-		} else {
e34dd0
-			existing_set->init = set_expr_alloc(&internal_location,
e34dd0
-							    set);
e34dd0
-		}
e34dd0
-	}
e34dd0
-
e34dd0
-	set_to_range(init);
e34dd0
-	list_expr_sort(&init->expressions);
e34dd0
+	set_sort_splice(init, set);
e34dd0
 
e34dd0
 	ctx.purge = set_expr_alloc(&internal_location, set);
e34dd0
 
e34dd0
@@ -591,18 +600,7 @@ int set_overlap(struct list_head *msgs, struct set *set, struct expr *init)
e34dd0
 	struct expr *i, *n, *clone;
e34dd0
 	int err;
e34dd0
 
e34dd0
-	if (existing_set) {
e34dd0
-		if (existing_set->init) {
e34dd0
-			list_splice_init(&existing_set->init->expressions,
e34dd0
-					 &init->expressions);
e34dd0
-		} else {
e34dd0
-			existing_set->init = set_expr_alloc(&internal_location,
e34dd0
-							    set);
e34dd0
-		}
e34dd0
-	}
e34dd0
-
e34dd0
-	set_to_range(init);
e34dd0
-	list_expr_sort(&init->expressions);
e34dd0
+	set_sort_splice(init, set);
e34dd0
 
e34dd0
 	err = setelem_overlap(msgs, set, init);
e34dd0
 
e34dd0
diff --git a/src/mergesort.c b/src/mergesort.c
e34dd0
index 8e6aac5..dca7142 100644
e34dd0
--- a/src/mergesort.c
e34dd0
+++ b/src/mergesort.c
e34dd0
@@ -70,7 +70,7 @@ static int expr_msort_cmp(const struct expr *e1, const struct expr *e2)
e34dd0
 	return ret;
e34dd0
 }
e34dd0
 
e34dd0
-static void list_splice_sorted(struct list_head *list, struct list_head *head)
e34dd0
+void list_splice_sorted(struct list_head *list, struct list_head *head)
e34dd0
 {
e34dd0
 	struct list_head *h = head->next;
e34dd0
 	struct list_head *l = list->next;
e34dd0
-- 
e34dd0
2.36.1
e34dd0