v16-0010-Template-out-node-insert-functions.patch

text/x-patch

Filename: v16-0010-Template-out-node-insert-functions.patch
Type: text/x-patch
Part: 7
Message: Re: [PoC] Improve dead tuple storage for lazy vacuum

Patch

Format: format-patch
Series: patch v16-0010
Subject: Template out node insert functions
File+
src/backend/lib/radixtree.c 6 363
src/include/lib/radixtree_insert_impl.h 257 0
From 48892a7f66892aeb3346622fd7b26e20811154d8 Mon Sep 17 00:00:00 2001
From: John Naylor <john.naylor@postgresql.org>
Date: Fri, 23 Dec 2022 14:33:49 +0700
Subject: [PATCH v16 10/12] Template out node insert functions

---
 src/backend/lib/radixtree.c             | 369 +-----------------------
 src/include/lib/radixtree_insert_impl.h | 257 +++++++++++++++++
 2 files changed, 263 insertions(+), 363 deletions(-)
 create mode 100644 src/include/lib/radixtree_insert_impl.h

diff --git a/src/backend/lib/radixtree.c b/src/backend/lib/radixtree.c
index 7899e844fb..79d12b27d2 100644
--- a/src/backend/lib/radixtree.c
+++ b/src/backend/lib/radixtree.c
@@ -1290,185 +1290,9 @@ static bool
 rt_node_insert_inner(radix_tree *tree, rt_node *parent, rt_node *node, uint64 key,
 					 rt_node *child)
 {
-	uint8		chunk = RT_GET_KEY_CHUNK(key, node->shift);
-	bool		chunk_exists = false;
-	rt_node		*newnode = NULL;
-
-	Assert(!NODE_IS_LEAF(node));
-
-	switch (node->kind)
-	{
-		case RT_NODE_KIND_4:
-			{
-				rt_node_inner_4 *n4 = (rt_node_inner_4 *) node;
-				int			idx;
-
-				idx = node_4_search_eq(&n4->base, chunk);
-				if (idx != -1)
-				{
-					/* found the existing chunk */
-					chunk_exists = true;
-					n4->children[idx] = child;
-					break;
-				}
-
-				if (unlikely(!VAR_NODE_HAS_FREE_SLOT(n4)))
-				{
-					rt_node_inner_32 *new32;
-
-					/* grow node from 4 to 32 */
-					newnode = rt_grow_node_kind(tree, node, RT_NODE_KIND_32);
-					new32 = (rt_node_inner_32 *) newnode;
-					chunk_children_array_copy(n4->base.chunks, n4->children,
-											  new32->base.chunks, new32->children);
-
-					Assert(parent != NULL);
-					rt_replace_node(tree, parent, node, newnode, key);
-					node = newnode;
-				}
-				else
-				{
-					int			insertpos = node_4_get_insertpos(&n4->base, chunk);
-					uint16		count = n4->base.n.count;
-
-					/* shift chunks and children */
-					if (count != 0 && insertpos < count)
-						chunk_children_array_shift(n4->base.chunks, n4->children,
-												   count, insertpos);
-
-					n4->base.chunks[insertpos] = chunk;
-					n4->children[insertpos] = child;
-					break;
-				}
-			}
-			/* FALLTHROUGH */
-		case RT_NODE_KIND_32:
-			{
-				const rt_size_class_elem minclass = rt_size_class_info[RT_CLASS_32_PARTIAL];
-				const rt_size_class_elem maxclass = rt_size_class_info[RT_CLASS_32_FULL];
-				rt_node_inner_32 *n32 = (rt_node_inner_32 *) node;
-				int			idx;
-
-				idx = node_32_search_eq(&n32->base, chunk);
-				if (idx != -1)
-				{
-					/* found the existing chunk */
-					chunk_exists = true;
-					n32->children[idx] = child;
-					break;
-				}
-
-				if (unlikely(!VAR_NODE_HAS_FREE_SLOT(n32)) &&
-					n32->base.n.count == minclass.fanout)
-				{
-					/* grow to the next size class of this kind */
-					newnode = rt_alloc_node(tree, RT_CLASS_32_FULL, true);
-					memcpy(newnode, node, minclass.inner_size);
-					newnode->fanout = maxclass.fanout;
-
-					Assert(parent != NULL);
-					rt_replace_node(tree, parent, node, newnode, key);
-					node = newnode;
-
-					/* also update pointer for this kind */
-					n32 = (rt_node_inner_32 *) newnode;
-				}
-
-				if (unlikely(!VAR_NODE_HAS_FREE_SLOT(n32)))
-				{
-					rt_node_inner_125 *new125;
-
-					/* grow node from 32 to 125 */
-					newnode = rt_grow_node_kind(tree, node, RT_NODE_KIND_125);
-					new125 = (rt_node_inner_125 *) newnode;
-					for (int i = 0; i < n32->base.n.count; i++)
-						node_inner_125_insert(new125, n32->base.chunks[i], n32->children[i]);
-
-					Assert(parent != NULL);
-					rt_replace_node(tree, parent, node, newnode, key);
-					node = newnode;
-				}
-				else
-				{
-					int	insertpos = node_32_get_insertpos(&n32->base, chunk);
-					int16 count = n32->base.n.count;
-
-					if (insertpos < count)
-					{
-						Assert(count > 0);
-						chunk_children_array_shift(n32->base.chunks, n32->children,
-												   count, insertpos);
-					}
-
-					n32->base.chunks[insertpos] = chunk;
-					n32->children[insertpos] = child;
-					break;
-				}
-			}
-			/* FALLTHROUGH */
-		case RT_NODE_KIND_125:
-			{
-				rt_node_inner_125 *n125 = (rt_node_inner_125 *) node;
-				int			cnt = 0;
-
-				if (node_125_is_chunk_used(&n125->base, chunk))
-				{
-					/* found the existing chunk */
-					chunk_exists = true;
-					node_inner_125_update(n125, chunk, child);
-					break;
-				}
-
-				if (unlikely(!VAR_NODE_HAS_FREE_SLOT(n125)))
-				{
-					rt_node_inner_256 *new256;
-					Assert(parent != NULL);
-
-					/* grow node from 125 to 256 */
-					newnode = rt_grow_node_kind(tree, node, RT_NODE_KIND_256);
-					new256 = (rt_node_inner_256 *) newnode;
-					for (int i = 0; i < RT_NODE_MAX_SLOTS && cnt < n125->base.n.count; i++)
-					{
-						if (!node_125_is_chunk_used(&n125->base, i))
-							continue;
-
-						node_inner_256_set(new256, i, node_inner_125_get_child(n125, i));
-						cnt++;
-					}
-
-					rt_replace_node(tree, parent, node, newnode, key);
-					node = newnode;
-				}
-				else
-				{
-					node_inner_125_insert(n125, chunk, child);
-					break;
-				}
-			}
-			/* FALLTHROUGH */
-		case RT_NODE_KIND_256:
-			{
-				rt_node_inner_256 *n256 = (rt_node_inner_256 *) node;
-
-				chunk_exists = node_inner_256_is_chunk_used(n256, chunk);
-				Assert(chunk_exists || FIXED_NODE_HAS_FREE_SLOT(n256, RT_CLASS_256));
-
-				node_inner_256_set(n256, chunk, child);
-				break;
-			}
-	}
-
-	/* Update statistics */
-	if (!chunk_exists)
-		node->count++;
-
-	/*
-	 * Done. Finally, verify the chunk and value is inserted or replaced
-	 * properly in the node.
-	 */
-	rt_verify_node(node);
-
-	return chunk_exists;
+#define RT_NODE_LEVEL_INNER
+#include "lib/radixtree_insert_impl.h"
+#undef RT_NODE_LEVEL_INNER
 }
 
 /* Insert the value to the leaf node */
@@ -1476,190 +1300,9 @@ static bool
 rt_node_insert_leaf(radix_tree *tree, rt_node *parent, rt_node *node,
 					uint64 key, uint64 value)
 {
-	uint8		chunk = RT_GET_KEY_CHUNK(key, node->shift);
-	bool		chunk_exists = false;
-
-	Assert(NODE_IS_LEAF(node));
-
-	switch (node->kind)
-	{
-		case RT_NODE_KIND_4:
-			{
-				rt_node_leaf_4 *n4 = (rt_node_leaf_4 *) node;
-				int			idx;
-
-				idx = node_4_search_eq((rt_node_base_4 *) n4, chunk);
-				if (idx != -1)
-				{
-					/* found the existing chunk */
-					chunk_exists = true;
-					n4->values[idx] = value;
-					break;
-				}
-
-				if (unlikely(!VAR_NODE_HAS_FREE_SLOT(n4)))
-				{
-					rt_node_leaf_32 *new32;
-					Assert(parent != NULL);
-
-					/* grow node from 4 to 32 */
-					new32 = (rt_node_leaf_32 *) rt_grow_node_kind(tree, (rt_node *) n4,
-																  RT_NODE_KIND_32);
-					chunk_values_array_copy(n4->base.chunks, n4->values,
-											new32->base.chunks, new32->values);
-					rt_replace_node(tree, parent, (rt_node *) n4, (rt_node *) new32, key);
-					node = (rt_node *) new32;
-				}
-				else
-				{
-					int			insertpos = node_4_get_insertpos((rt_node_base_4 *) n4, chunk);
-					int			count = n4->base.n.count;
-
-					/* shift chunks and values */
-					if (count != 0 && insertpos < count)
-						chunk_values_array_shift(n4->base.chunks, n4->values,
-												 count, insertpos);
-
-					n4->base.chunks[insertpos] = chunk;
-					n4->values[insertpos] = value;
-					break;
-				}
-			}
-			/* FALLTHROUGH */
-		case RT_NODE_KIND_32:
-			{
-				rt_node_leaf_32 *n32 = (rt_node_leaf_32 *) node;
-				int			idx;
-
-				idx = node_32_search_eq((rt_node_base_32 *) n32, chunk);
-				if (idx != -1)
-				{
-					/* found the existing chunk */
-					chunk_exists = true;
-					n32->values[idx] = value;
-					break;
-				}
-
-				if (unlikely(!VAR_NODE_HAS_FREE_SLOT(n32)))
-				{
-					Assert(parent != NULL);
-
-					if (n32->base.n.count == rt_size_class_info[RT_CLASS_32_PARTIAL].fanout)
-					{
-						/* use the same node kind, but expand to the next size class */
-						const Size size = rt_size_class_info[RT_CLASS_32_PARTIAL].leaf_size;
-						const int fanout = rt_size_class_info[RT_CLASS_32_FULL].fanout;
-						rt_node_leaf_32 *new32;
-
-						new32 = (rt_node_leaf_32 *) rt_alloc_node(tree, RT_CLASS_32_FULL, false);
-						memcpy(new32, n32, size);
-						new32->base.n.fanout = fanout;
-
-						rt_replace_node(tree, parent, (rt_node *) n32, (rt_node *) new32, key);
-
-						/* must update both pointers here */
-						node = (rt_node *) new32;
-						n32 = new32;
-
-						goto retry_insert_leaf_32;
-					}
-					else
-					{
-						rt_node_leaf_125 *new125;
-
-						/* grow node from 32 to 125 */
-						new125 = (rt_node_leaf_125 *) rt_grow_node_kind(tree, (rt_node *) n32,
-																		RT_NODE_KIND_125);
-						for (int i = 0; i < n32->base.n.count; i++)
-							node_leaf_125_insert(new125, n32->base.chunks[i], n32->values[i]);
-
-						rt_replace_node(tree, parent, (rt_node *) n32, (rt_node *) new125,
-										key);
-						node = (rt_node *) new125;
-					}
-				}
-				else
-				{
-				retry_insert_leaf_32:
-					{
-						int	insertpos = node_32_get_insertpos((rt_node_base_32 *) n32, chunk);
-						int	count = n32->base.n.count;
-
-						if (count != 0 && insertpos < count)
-							chunk_values_array_shift(n32->base.chunks, n32->values,
-													 count, insertpos);
-
-						n32->base.chunks[insertpos] = chunk;
-						n32->values[insertpos] = value;
-						break;
-					}
-				}
-			}
-			/* FALLTHROUGH */
-		case RT_NODE_KIND_125:
-			{
-				rt_node_leaf_125 *n125 = (rt_node_leaf_125 *) node;
-				int			cnt = 0;
-
-				if (node_125_is_chunk_used((rt_node_base_125 *) n125, chunk))
-				{
-					/* found the existing chunk */
-					chunk_exists = true;
-					node_leaf_125_update(n125, chunk, value);
-					break;
-				}
-
-				if (unlikely(!VAR_NODE_HAS_FREE_SLOT(n125)))
-				{
-					rt_node_leaf_256 *new256;
-					Assert(parent != NULL);
-
-					/* grow node from 125 to 256 */
-					new256 = (rt_node_leaf_256 *) rt_grow_node_kind(tree, (rt_node *) n125,
-																	RT_NODE_KIND_256);
-					for (int i = 0; i < RT_NODE_MAX_SLOTS && cnt < n125->base.n.count; i++)
-					{
-						if (!node_125_is_chunk_used((rt_node_base_125 *) n125, i))
-							continue;
-
-						node_leaf_256_set(new256, i, node_leaf_125_get_value(n125, i));
-						cnt++;
-					}
-
-					rt_replace_node(tree, parent, (rt_node *) n125, (rt_node *) new256,
-									key);
-					node = (rt_node *) new256;
-				}
-				else
-				{
-					node_leaf_125_insert(n125, chunk, value);
-					break;
-				}
-			}
-			/* FALLTHROUGH */
-		case RT_NODE_KIND_256:
-			{
-				rt_node_leaf_256 *n256 = (rt_node_leaf_256 *) node;
-
-				chunk_exists = node_leaf_256_is_chunk_used(n256, chunk);
-				Assert(chunk_exists || FIXED_NODE_HAS_FREE_SLOT(n256, RT_CLASS_256));
-
-				node_leaf_256_set(n256, chunk, value);
-				break;
-			}
-	}
-
-	/* Update statistics */
-	if (!chunk_exists)
-		node->count++;
-
-	/*
-	 * Done. Finally, verify the chunk and value is inserted or replaced
-	 * properly in the node.
-	 */
-	rt_verify_node(node);
-
-	return chunk_exists;
+#define RT_NODE_LEVEL_LEAF
+#include "lib/radixtree_insert_impl.h"
+#undef RT_NODE_LEVEL_LEAF
 }
 
 /*
diff --git a/src/include/lib/radixtree_insert_impl.h b/src/include/lib/radixtree_insert_impl.h
new file mode 100644
index 0000000000..8e02c83fc7
--- /dev/null
+++ b/src/include/lib/radixtree_insert_impl.h
@@ -0,0 +1,257 @@
+#if defined(RT_NODE_LEVEL_INNER)
+#define RT_NODE4_TYPE rt_node_inner_4
+#define RT_NODE32_TYPE rt_node_inner_32
+#define RT_NODE125_TYPE rt_node_inner_125
+#define RT_NODE256_TYPE rt_node_inner_256
+#elif defined(RT_NODE_LEVEL_LEAF)
+#define RT_NODE4_TYPE rt_node_leaf_4
+#define RT_NODE32_TYPE rt_node_leaf_32
+#define RT_NODE125_TYPE rt_node_leaf_125
+#define RT_NODE256_TYPE rt_node_leaf_256
+#else
+#error node level must be either inner or leaf
+#endif
+
+	uint8		chunk = RT_GET_KEY_CHUNK(key, node->shift);
+	bool		chunk_exists = false;
+	rt_node		*newnode = NULL;
+
+#ifdef RT_NODE_LEVEL_LEAF
+	Assert(NODE_IS_LEAF(node));
+#else
+	Assert(!NODE_IS_LEAF(node));
+#endif
+
+	switch (node->kind)
+	{
+		case RT_NODE_KIND_4:
+			{
+				RT_NODE4_TYPE *n4 = (RT_NODE4_TYPE *) node;
+				int			idx;
+
+				idx = node_4_search_eq(&n4->base, chunk);
+				if (idx != -1)
+				{
+					/* found the existing chunk */
+					chunk_exists = true;
+#ifdef RT_NODE_LEVEL_LEAF
+					n4->values[idx] = value;
+#else
+					n4->children[idx] = child;
+#endif
+					break;
+				}
+
+				if (unlikely(!VAR_NODE_HAS_FREE_SLOT(n4)))
+				{
+					RT_NODE32_TYPE *new32;
+
+					/* grow node from 4 to 32 */
+					newnode = rt_grow_node_kind(tree, node, RT_NODE_KIND_32);
+					new32 = (RT_NODE32_TYPE *) newnode;
+#ifdef RT_NODE_LEVEL_LEAF
+					chunk_values_array_copy(n4->base.chunks, n4->values,
+											  new32->base.chunks, new32->values);
+#else
+					chunk_children_array_copy(n4->base.chunks, n4->children,
+											  new32->base.chunks, new32->children);
+#endif
+					Assert(parent != NULL);
+					rt_replace_node(tree, parent, node, newnode, key);
+					node = newnode;
+				}
+				else
+				{
+					int			insertpos = node_4_get_insertpos(&n4->base, chunk);
+					int			count = n4->base.n.count;
+
+					/* shift chunks and children */
+					if (insertpos < count)
+					{
+						Assert(count > 0);
+#ifdef RT_NODE_LEVEL_LEAF
+						chunk_values_array_shift(n4->base.chunks, n4->values,
+												   count, insertpos);
+#else
+						chunk_children_array_shift(n4->base.chunks, n4->children,
+												   count, insertpos);
+#endif
+					}
+
+					n4->base.chunks[insertpos] = chunk;
+#ifdef RT_NODE_LEVEL_LEAF
+					n4->values[insertpos] = value;
+#else
+					n4->children[insertpos] = child;
+#endif
+					break;
+				}
+			}
+			/* FALLTHROUGH */
+		case RT_NODE_KIND_32:
+			{
+				const rt_size_class_elem minclass = rt_size_class_info[RT_CLASS_32_PARTIAL];
+				const rt_size_class_elem maxclass = rt_size_class_info[RT_CLASS_32_FULL];
+				RT_NODE32_TYPE *n32 = (RT_NODE32_TYPE *) node;
+				int			idx;
+
+				idx = node_32_search_eq(&n32->base, chunk);
+				if (idx != -1)
+				{
+					/* found the existing chunk */
+					chunk_exists = true;
+#ifdef RT_NODE_LEVEL_LEAF
+					n32->values[idx] = value;
+#else
+					n32->children[idx] = child;
+#endif
+					break;
+				}
+
+				if (unlikely(!VAR_NODE_HAS_FREE_SLOT(n32)) &&
+					n32->base.n.count == minclass.fanout)
+				{
+					/* grow to the next size class of this kind */
+					newnode = rt_alloc_node(tree, RT_CLASS_32_FULL, true);
+					memcpy(newnode, node, minclass.inner_size);
+					newnode->fanout = maxclass.fanout;
+
+					Assert(parent != NULL);
+					rt_replace_node(tree, parent, node, newnode, key);
+					node = newnode;
+
+					/* also update pointer for this kind */
+					n32 = (RT_NODE32_TYPE *) newnode;
+				}
+
+				if (unlikely(!VAR_NODE_HAS_FREE_SLOT(n32)))
+				{
+					RT_NODE125_TYPE *new125;
+
+					/* grow node from 32 to 125 */
+					newnode = rt_grow_node_kind(tree, node, RT_NODE_KIND_125);
+					new125 = (RT_NODE125_TYPE *) newnode;
+					for (int i = 0; i < n32->base.n.count; i++)
+#ifdef RT_NODE_LEVEL_LEAF
+						node_leaf_125_insert(new125, n32->base.chunks[i], n32->values[i]);
+#else
+						node_inner_125_insert(new125, n32->base.chunks[i], n32->children[i]);
+#endif
+					Assert(parent != NULL);
+					rt_replace_node(tree, parent, node, newnode, key);
+					node = newnode;
+				}
+				else
+				{
+					int	insertpos = node_32_get_insertpos(&n32->base, chunk);
+					int count = n32->base.n.count;
+
+					if (insertpos < count)
+					{
+						Assert(count > 0);
+#ifdef RT_NODE_LEVEL_LEAF
+						chunk_values_array_shift(n32->base.chunks, n32->values,
+												   count, insertpos);
+#else
+						chunk_children_array_shift(n32->base.chunks, n32->children,
+												   count, insertpos);
+#endif
+					}
+
+					n32->base.chunks[insertpos] = chunk;
+#ifdef RT_NODE_LEVEL_LEAF
+					n32->values[insertpos] = value;
+#else
+					n32->children[insertpos] = child;
+#endif
+					break;
+				}
+			}
+			/* FALLTHROUGH */
+		case RT_NODE_KIND_125:
+			{
+				RT_NODE125_TYPE *n125 = (RT_NODE125_TYPE *) node;
+				int			cnt = 0;
+
+				if (node_125_is_chunk_used(&n125->base, chunk))
+				{
+					/* found the existing chunk */
+					chunk_exists = true;
+#ifdef RT_NODE_LEVEL_LEAF
+					node_leaf_125_update(n125, chunk, value);
+#else
+					node_inner_125_update(n125, chunk, child);
+#endif
+					break;
+				}
+
+				if (unlikely(!VAR_NODE_HAS_FREE_SLOT(n125)))
+				{
+					RT_NODE256_TYPE *new256;
+
+					/* grow node from 125 to 256 */
+					newnode = rt_grow_node_kind(tree, node, RT_NODE_KIND_256);
+					new256 = (RT_NODE256_TYPE *) newnode;
+					for (int i = 0; i < RT_NODE_MAX_SLOTS && cnt < n125->base.n.count; i++)
+					{
+						if (!node_125_is_chunk_used(&n125->base, i))
+							continue;
+#ifdef RT_NODE_LEVEL_LEAF
+						node_leaf_256_set(new256, i, node_leaf_125_get_value(n125, i));
+#else
+						node_inner_256_set(new256, i, node_inner_125_get_child(n125, i));
+#endif
+						cnt++;
+					}
+
+					Assert(parent != NULL);
+					rt_replace_node(tree, parent, node, newnode, key);
+					node = newnode;
+				}
+				else
+				{
+#ifdef RT_NODE_LEVEL_LEAF
+					node_leaf_125_insert(n125, chunk, value);
+#else
+					node_inner_125_insert(n125, chunk, child);
+#endif
+					break;
+				}
+			}
+			/* FALLTHROUGH */
+		case RT_NODE_KIND_256:
+			{
+				RT_NODE256_TYPE *n256 = (RT_NODE256_TYPE *) node;
+
+#ifdef RT_NODE_LEVEL_LEAF
+				chunk_exists = node_leaf_256_is_chunk_used(n256, chunk);
+#else
+				chunk_exists = node_inner_256_is_chunk_used(n256, chunk);
+#endif
+				Assert(chunk_exists || FIXED_NODE_HAS_FREE_SLOT(n256, RT_CLASS_256));
+
+#ifdef RT_NODE_LEVEL_LEAF
+				node_leaf_256_set(n256, chunk, value);
+#else
+				node_inner_256_set(n256, chunk, child);
+#endif
+				break;
+			}
+	}
+
+	/* Update statistics */
+	if (!chunk_exists)
+		node->count++;
+
+	/*
+	 * Done. Finally, verify the chunk and value is inserted or replaced
+	 * properly in the node.
+	 */
+	rt_verify_node(node);
+
+	return chunk_exists;
+
+#undef RT_NODE4_TYPE
+#undef RT_NODE32_TYPE
+#undef RT_NODE125_TYPE
+#undef RT_NODE256_TYPE
-- 
2.38.1