v16-0012-Separate-find-and-delete-actions-into-separate-f.patch

text/x-patch

Filename: v16-0012-Separate-find-and-delete-actions-into-separate-f.patch
Type: text/x-patch
Part: 10
Message: Re: [PoC] Improve dead tuple storage for lazy vacuum

Patch

Format: format-patch
Series: patch v16-0012
Subject: Separate find and delete actions into separate functions
File+
src/backend/lib/radixtree.c 48 25
src/include/lib/radixtree_search_impl.h 35 33
From 3637d74416d565e3ca6faff2ad6b6a25b2c50689 Mon Sep 17 00:00:00 2001
From: John Naylor <john.naylor@postgresql.org>
Date: Fri, 23 Dec 2022 17:41:05 +0700
Subject: [PATCH v16 12/12] Separate find and delete actions into separate
 functions

This makes hot paths smaller and less branchy.
---
 src/backend/lib/radixtree.c             | 73 ++++++++++++++++---------
 src/include/lib/radixtree_search_impl.h | 68 ++++++++++++-----------
 2 files changed, 83 insertions(+), 58 deletions(-)

diff --git a/src/backend/lib/radixtree.c b/src/backend/lib/radixtree.c
index 99450c96c8..c934bff693 100644
--- a/src/backend/lib/radixtree.c
+++ b/src/backend/lib/radixtree.c
@@ -96,13 +96,6 @@
 #define BM_IDX(x)	((x) / BITS_PER_BITMAPWORD)
 #define BM_BIT(x)	((x) % BITS_PER_BITMAPWORD)
 
-/* Enum used rt_node_search() */
-typedef enum
-{
-	RT_ACTION_FIND = 0,			/* find the key-value */
-	RT_ACTION_DELETE,			/* delete the key-value */
-} rt_action;
-
 /*
  * Supported radix tree node kinds and size classes.
  *
@@ -422,10 +415,8 @@ static inline void rt_init_node(rt_node *node, uint8 kind, rt_size_class size_cl
 								bool inner);
 static void rt_free_node(radix_tree *tree, rt_node *node);
 static void rt_extend(radix_tree *tree, uint64 key);
-static inline bool rt_node_search_inner(rt_node *node, uint64 key, rt_action action,
-										rt_node **child_p);
-static inline bool rt_node_search_leaf(rt_node *node, uint64 key, rt_action action,
-									   uint64 *value_p);
+static inline bool rt_node_search_inner(rt_node *node, uint64 key, rt_node **child_p);
+static inline bool rt_node_search_leaf(rt_node *node, uint64 key, uint64 *value_p);
 static bool rt_node_insert_inner(radix_tree *tree, rt_node *parent, rt_node *node,
 								 uint64 key, rt_node *child);
 static bool rt_node_insert_leaf(radix_tree *tree, rt_node *parent, rt_node *node,
@@ -1100,33 +1091,65 @@ rt_set_extend(radix_tree *tree, uint64 key, uint64 value, rt_node *parent,
 }
 
 /*
- * Search for the child pointer corresponding to 'key' in the given node, and
- * do the specified 'action'.
+ * Search for the child pointer corresponding to 'key' in the given node.
  *
  * Return true if the key is found, otherwise return false. On success, the child
  * pointer is set to child_p.
  */
 static inline bool
-rt_node_search_inner(rt_node *node, uint64 key, rt_action action, rt_node **child_p)
+rt_node_search_inner(rt_node *node, uint64 key, rt_node **child_p)
 {
+#define RT_ACTION_FIND
 #define RT_NODE_LEVEL_INNER
 #include "lib/radixtree_search_impl.h"
 #undef RT_NODE_LEVEL_INNER
+#undef RT_ACTION_FIND
 }
 
 /*
- * Search for the value corresponding to 'key' in the given node, and do the
- * specified 'action'.
+ * Search for the value corresponding to 'key' in the given node.
  *
  * Return true if the key is found, otherwise return false. On success, the pointer
  * to the value is set to value_p.
  */
 static inline bool
-rt_node_search_leaf(rt_node *node, uint64 key, rt_action action, uint64 *value_p)
+rt_node_search_leaf(rt_node *node, uint64 key, uint64 *value_p)
+{
+#define RT_ACTION_FIND
+#define RT_NODE_LEVEL_LEAF
+#include "lib/radixtree_search_impl.h"
+#undef RT_NODE_LEVEL_LEAF
+#undef RT_ACTION_FIND
+}
+
+/*
+ * Search for the child pointer corresponding to 'key' in the given node.
+ *
+ * Delete the node and return true if the key is found, otherwise return false.
+ */
+static inline bool
+rt_node_delete_inner(rt_node *node, uint64 key)
+{
+#define RT_ACTION_DELETE
+#define RT_NODE_LEVEL_INNER
+#include "lib/radixtree_search_impl.h"
+#undef RT_NODE_LEVEL_INNER
+#undef RT_ACTION_DELETE
+}
+
+/*
+ * Search for the value corresponding to 'key' in the given node.
+ *
+ * Delete the node and return true if the key is found, otherwise return false.
+ */
+static inline bool
+rt_node_delete_leaf(rt_node *node, uint64 key)
 {
+#define RT_ACTION_DELETE
 #define RT_NODE_LEVEL_LEAF
 #include "lib/radixtree_search_impl.h"
 #undef RT_NODE_LEVEL_LEAF
+#undef RT_ACTION_DELETE
 }
 
 /* Insert the child to the inner node */
@@ -1235,7 +1258,7 @@ rt_set(radix_tree *tree, uint64 key, uint64 value)
 		if (NODE_IS_LEAF(node))
 			break;
 
-		if (!rt_node_search_inner(node, key, RT_ACTION_FIND, &child))
+		if (!rt_node_search_inner(node, key, &child))
 		{
 			rt_set_extend(tree, key, value, parent, node);
 			return false;
@@ -1282,14 +1305,14 @@ rt_search(radix_tree *tree, uint64 key, uint64 *value_p)
 		if (NODE_IS_LEAF(node))
 			break;
 
-		if (!rt_node_search_inner(node, key, RT_ACTION_FIND, &child))
+		if (!rt_node_search_inner(node, key, &child))
 			return false;
 
 		node = child;
 		shift -= RT_NODE_SPAN;
 	}
 
-	return rt_node_search_leaf(node, key, RT_ACTION_FIND, value_p);
+	return rt_node_search_leaf(node, key, value_p);
 }
 
 /*
@@ -1322,7 +1345,7 @@ rt_delete(radix_tree *tree, uint64 key)
 		/* Push the current node to the stack */
 		stack[++level] = node;
 
-		if (!rt_node_search_inner(node, key, RT_ACTION_FIND, &child))
+		if (!rt_node_search_inner(node, key, &child))
 			return false;
 
 		node = child;
@@ -1331,7 +1354,7 @@ rt_delete(radix_tree *tree, uint64 key)
 
 	/* Delete the key from the leaf node if exists */
 	Assert(NODE_IS_LEAF(node));
-	deleted = rt_node_search_leaf(node, key, RT_ACTION_DELETE, NULL);
+	deleted = rt_node_delete_leaf(node, key);
 
 	if (!deleted)
 	{
@@ -1357,7 +1380,7 @@ rt_delete(radix_tree *tree, uint64 key)
 	{
 		node = stack[level--];
 
-		deleted = rt_node_search_inner(node, key, RT_ACTION_DELETE, NULL);
+		deleted = rt_node_delete_inner(node, key);
 		Assert(deleted);
 
 		/* If the node didn't become empty, we stop deleting the key */
@@ -1989,12 +2012,12 @@ rt_dump_search(radix_tree *tree, uint64 key)
 			uint64		dummy;
 
 			/* We reached at a leaf node, find the corresponding slot */
-			rt_node_search_leaf(node, key, RT_ACTION_FIND, &dummy);
+			rt_node_search_leaf(node, key, &dummy);
 
 			break;
 		}
 
-		if (!rt_node_search_inner(node, key, RT_ACTION_FIND, &child))
+		if (!rt_node_search_inner(node, key, &child))
 			break;
 
 		node = child;
diff --git a/src/include/lib/radixtree_search_impl.h b/src/include/lib/radixtree_search_impl.h
index 0173d9cb2f..28c02da2bf 100644
--- a/src/include/lib/radixtree_search_impl.h
+++ b/src/include/lib/radixtree_search_impl.h
@@ -10,16 +10,21 @@
 #define RT_NODE256_TYPE rt_node_leaf_256
 #else
 #error node level must be either inner or leaf
+#endif
+
+#if !defined(RT_ACTION_FIND) && !defined(RT_ACTION_DELETE)
+#error search action must be either find or delete
 #endif
 
 	uint8		chunk = RT_GET_KEY_CHUNK(key, node->shift);
-	bool		found = false;
 
+#if defined(RT_ACTION_FIND)
 #ifdef RT_NODE_LEVEL_LEAF
 	uint64		value = 0;
 #else
 	rt_node    *child = NULL;
 #endif
+#endif			/* RT_ACTION_FIND */
 
 	switch (node->kind)
 	{
@@ -29,17 +34,15 @@
 				int			idx = node_4_search_eq((rt_node_base_4 *) n4, chunk);
 
 				if (idx < 0)
-					break;
-
-				found = true;
+					return false;
 
-				if (action == RT_ACTION_FIND)
+#if defined(RT_ACTION_FIND)
 #ifdef RT_NODE_LEVEL_LEAF
 					value = n4->values[idx];
 #else
 					child = n4->children[idx];
 #endif
-				else			/* RT_ACTION_DELETE */
+#elif defined (RT_ACTION_DELETE)
 #ifdef RT_NODE_LEVEL_LEAF
 					chunk_values_array_delete(n4->base.chunks, (uint64 *) n4->values,
 											  n4->base.n.count, idx);
@@ -47,6 +50,8 @@
 					chunk_children_array_delete(n4->base.chunks, n4->children,
 											    n4->base.n.count, idx);
 #endif
+#endif			/* RT_ACTION_FIND */
+
 				break;
 			}
 		case RT_NODE_KIND_32:
@@ -55,17 +60,15 @@
 				int			idx = node_32_search_eq((rt_node_base_32 *) n32, chunk);
 
 				if (idx < 0)
-					break;
-
-				found = true;
+					return false;
 
-				if (action == RT_ACTION_FIND)
+#if defined(RT_ACTION_FIND)
 #ifdef RT_NODE_LEVEL_LEAF
 					value = n32->values[idx];
 #else
 					child = n32->children[idx];
 #endif
-				else			/* RT_ACTION_DELETE */
+#elif defined (RT_ACTION_DELETE)
 #ifdef RT_NODE_LEVEL_LEAF
 					chunk_values_array_delete(n32->base.chunks, (uint64 *) n32->values,
 											  n32->base.n.count, idx);
@@ -73,6 +76,8 @@
 					chunk_children_array_delete(n32->base.chunks, n32->children,
 											    n32->base.n.count, idx);
 #endif
+#endif			/* RT_ACTION_FIND */
+
 				break;
 			}
 		case RT_NODE_KIND_125:
@@ -80,22 +85,22 @@
 				RT_NODE125_TYPE *n125 = (RT_NODE125_TYPE *) node;
 
 				if (!node_125_is_chunk_used((rt_node_base_125 *) n125, chunk))
-					break;
+					return false;
 
-				found = true;
-
-				if (action == RT_ACTION_FIND)
+#if defined(RT_ACTION_FIND)
 #ifdef RT_NODE_LEVEL_LEAF
 					value = node_leaf_125_get_value(n125, chunk);
 #else
 					child = node_inner_125_get_child(n125, chunk);
 #endif
-				else			/* RT_ACTION_DELETE */
+#elif defined (RT_ACTION_DELETE)
 #ifdef RT_NODE_LEVEL_LEAF
 					node_leaf_125_delete(n125, chunk);
 #else
 					node_inner_125_delete(n125, chunk);
 #endif
+#endif			/* RT_ACTION_FIND */
+
 				break;
 			}
 		case RT_NODE_KIND_256:
@@ -107,43 +112,40 @@
 #else
 				if (!node_inner_256_is_chunk_used(n256, chunk))
 #endif
-					break;
-
-				found = true;
+					return false;
 
-				if (action == RT_ACTION_FIND)
+#if defined(RT_ACTION_FIND)
 #ifdef RT_NODE_LEVEL_LEAF
 					value = node_leaf_256_get_value(n256, chunk);
 #else
 					child = node_inner_256_get_child(n256, chunk);
 #endif
-				else			/* RT_ACTION_DELETE */
+#elif defined (RT_ACTION_DELETE)
 #ifdef RT_NODE_LEVEL_LEAF
 					node_leaf_256_delete(n256, chunk);
 #else
 					node_inner_256_delete(n256, chunk);
 #endif
+#endif			/* RT_ACTION_FIND */
 
 				break;
 			}
 	}
 
-	if (found)
-	{
-		/* update statistics */
-		if (action == RT_ACTION_DELETE)
-			node->count--;
-
+#if defined(RT_ACTION_FIND)
 #ifdef RT_NODE_LEVEL_LEAF
-		if (value_p)
-			*value_p = value;
+	Assert(value_p != NULL);
+	*value_p = value;
 #else
-		if (child_p)
-			*child_p = child;
+	Assert(child_p != NULL);
+	*child_p = child;
 #endif
-	}
+#elif defined (RT_ACTION_DELETE)
+	/* update statistics */
+	node->count--;
+#endif			/* RT_ACTION_FIND */
 
-	return found;
+	return true;
 
 #undef RT_NODE4_TYPE
 #undef RT_NODE32_TYPE
-- 
2.38.1