From d13da75dfe46d9ea7776751134fe4c22f83cd15d Mon Sep 17 00:00:00 2001
From: Masahiko Sawada <sawada.mshk@gmail.com>
Date: Wed, 25 Jan 2023 16:52:41 +0900
Subject: [PATCH v23 14/18] Improve RT_DUMP() and RT_DUMP_SEARCH() output.

We don't display values since these might not be integers.
---
 src/include/lib/radixtree.h | 201 +++++++++++++++++++++---------------
 1 file changed, 118 insertions(+), 83 deletions(-)

diff --git a/src/include/lib/radixtree.h b/src/include/lib/radixtree.h
index dbf9df604f..11716fbfca 100644
--- a/src/include/lib/radixtree.h
+++ b/src/include/lib/radixtree.h
@@ -2023,32 +2023,46 @@ RT_VERIFY_NODE(RT_PTR_LOCAL node)
 RT_SCOPE void
 RT_STATS(RT_RADIX_TREE *tree)
 {
-	ereport(NOTICE, (errmsg("num_keys = " UINT64_FORMAT ", height = %d, n3 = %u, n15 = %u, n32 = %u, n125 = %u, n256 = %u",
-						 tree->ctl->num_keys,
-						 tree->ctl->root->shift / RT_NODE_SPAN,
-						 tree->ctl->cnt[RT_CLASS_3],
-						 tree->ctl->cnt[RT_CLASS_32_MIN],
-						 tree->ctl->cnt[RT_CLASS_32_MAX],
-						 tree->ctl->cnt[RT_CLASS_125],
-						 tree->ctl->cnt[RT_CLASS_256])));
+	fprintf(stderr, "max_val = " UINT64_FORMAT "\n", tree->ctl->max_val);
+	fprintf(stderr, "num_keys = " UINT64_FORMAT "\n", tree->ctl->num_keys);
+
+#ifdef RT_SHMEM
+	fprintf(stderr, "handle = " UINT64_FORMAT "\n", tree->ctl->handle);
+#endif
+
+	if (RT_PTR_ALLOC_IS_VALID(tree->ctl->root))
+	{
+		RT_PTR_LOCAL root = RT_PTR_GET_LOCAL(tree, tree->ctl->root);
+
+		fprintf(stderr, "height = %d, n3 = %u, n15 = %u, n32 = %u, n125 = %u, n256 = %u\n",
+				root->shift / RT_NODE_SPAN,
+				tree->ctl->cnt[RT_CLASS_3],
+				tree->ctl->cnt[RT_CLASS_32_MIN],
+				tree->ctl->cnt[RT_CLASS_32_MAX],
+				tree->ctl->cnt[RT_CLASS_125],
+				tree->ctl->cnt[RT_CLASS_256]);
+	}
 }
 
-/* XXX For display, assumes value type is numeric */
 static void
-RT_DUMP_NODE(RT_PTR_LOCAL node, int level, bool recurse)
+RT_DUMP_NODE(RT_RADIX_TREE *tree, RT_PTR_ALLOC allocnode, int level,
+			 bool recurse, StringInfo buf)
 {
-	char		space[125] = {0};
+	RT_PTR_LOCAL node = RT_PTR_GET_LOCAL(tree, allocnode);
+	StringInfoData spaces;
 
-	fprintf(stderr, "[%s] kind %d, fanout %d, count %u, shift %u:\n",
-			RT_NODE_IS_LEAF(node) ? "LEAF" : "INNR",
-			(node->kind == RT_NODE_KIND_3) ? 3 :
-			(node->kind == RT_NODE_KIND_32) ? 32 :
-			(node->kind == RT_NODE_KIND_125) ? 125 : 256,
-			node->fanout == 0 ? 256 : node->fanout,
-			node->count, node->shift);
+	initStringInfo(&spaces);
+	appendStringInfoSpaces(&spaces, (level * 4) + 1);
 
-	if (level > 0)
-		sprintf(space, "%*c", level * 4, ' ');
+	appendStringInfo(buf, "%s%s[%s] kind %d, fanout %d, count %u, shift %u:\n",
+					 spaces.data,
+					 level == 0 ? "" : "-> ",
+					 RT_NODE_IS_LEAF(node) ? "LEAF" : "INNR",
+					 (node->kind == RT_NODE_KIND_3) ? 3 :
+					 (node->kind == RT_NODE_KIND_32) ? 32 :
+					 (node->kind == RT_NODE_KIND_125) ? 125 : 256,
+					 node->fanout == 0 ? 256 : node->fanout,
+					 node->count, node->shift);
 
 	switch (node->kind)
 	{
@@ -2060,20 +2074,24 @@ RT_DUMP_NODE(RT_PTR_LOCAL node, int level, bool recurse)
 					{
 						RT_NODE_LEAF_3 *n3 = (RT_NODE_LEAF_3 *) node;
 
-						fprintf(stderr, "%schunk 0x%X value 0x" RT_UINT64_FORMAT_HEX "\n",
-								space, n3->base.chunks[i], (uint64) n3->values[i]);
+						appendStringInfo(buf, "%schunk[%d] 0x%X\n",
+										 spaces.data, i, n3->base.chunks[i]);
 					}
 					else
 					{
 						RT_NODE_INNER_3 *n3 = (RT_NODE_INNER_3 *) node;
 
-						fprintf(stderr, "%schunk 0x%X ->",
-								space, n3->base.chunks[i]);
+						appendStringInfo(buf, "%schunk[%d] 0x%X",
+										 spaces.data, i, n3->base.chunks[i]);
 
 						if (recurse)
-							RT_DUMP_NODE(n3->children[i], level + 1, recurse);
+						{
+							appendStringInfo(buf, "\n");
+							RT_DUMP_NODE(tree, n3->children[i], level + 1,
+										 recurse, buf);
+						}
 						else
-							fprintf(stderr, "\n");
+							appendStringInfo(buf, " (skipped)\n");
 					}
 				}
 				break;
@@ -2086,22 +2104,25 @@ RT_DUMP_NODE(RT_PTR_LOCAL node, int level, bool recurse)
 					{
 						RT_NODE_LEAF_32 *n32 = (RT_NODE_LEAF_32 *) node;
 
-						fprintf(stderr, "%schunk 0x%X value 0x" RT_UINT64_FORMAT_HEX "\n",
-								space, n32->base.chunks[i], (uint64) n32->values[i]);
+						appendStringInfo(buf, "%schunk[%d] 0x%X\n",
+										 spaces.data, i, n32->base.chunks[i]);
 					}
 					else
 					{
 						RT_NODE_INNER_32 *n32 = (RT_NODE_INNER_32 *) node;
 
-						fprintf(stderr, "%schunk 0x%X ->",
-								space, n32->base.chunks[i]);
+						appendStringInfo(buf, "%schunk[%d] 0x%X",
+										 spaces.data, i, n32->base.chunks[i]);
 
 						if (recurse)
 						{
-							RT_DUMP_NODE(n32->children[i], level + 1, recurse);
+							appendStringInfo(buf, "\n");
+							RT_DUMP_NODE(tree, n32->children[i], level + 1,
+										 recurse, buf);
 						}
 						else
-							fprintf(stderr, "\n");
+							appendStringInfo(buf, " (skipped)\n");
+
 					}
 				}
 				break;
@@ -2109,26 +2130,23 @@ RT_DUMP_NODE(RT_PTR_LOCAL node, int level, bool recurse)
 		case RT_NODE_KIND_125:
 			{
 				RT_NODE_BASE_125 *b125 = (RT_NODE_BASE_125 *) node;
+				char *sep = "";
 
-				fprintf(stderr, "slot_idxs ");
+				appendStringInfo(buf, "%sslot_idxs: ", spaces.data);
 				for (int i = 0; i < RT_NODE_MAX_SLOTS; i++)
 				{
 					if (!RT_NODE_125_IS_CHUNK_USED(b125, i))
 						continue;
 
-					fprintf(stderr, " [%d]=%d, ", i, b125->slot_idxs[i]);
+					appendStringInfo(buf, "%s[%d]=%d ",
+									 sep, i, b125->slot_idxs[i]);
+					sep = ",";
 				}
-				if (RT_NODE_IS_LEAF(node))
-				{
-					RT_NODE_LEAF_125 *n = (RT_NODE_LEAF_125 *) node;
 
-					fprintf(stderr, ", isset-bitmap:");
-					for (int i = 0; i < BM_IDX(RT_SLOT_IDX_LIMIT); i++)
-					{
-						fprintf(stderr, RT_UINT64_FORMAT_HEX " ", (uint64) n->base.isset[i]);
-					}
-					fprintf(stderr, "\n");
-				}
+				appendStringInfo(buf, "\n%sisset-bitmap: ", spaces.data);
+				for (int i = 0; i < (RT_SLOT_IDX_LIMIT / BITS_PER_BYTE); i++)
+					appendStringInfo(buf, "%X ", ((uint8 *) b125->isset)[i]);
+				appendStringInfo(buf, "\n");
 
 				for (int i = 0; i < RT_NODE_MAX_SLOTS; i++)
 				{
@@ -2136,30 +2154,39 @@ RT_DUMP_NODE(RT_PTR_LOCAL node, int level, bool recurse)
 						continue;
 
 					if (RT_NODE_IS_LEAF(node))
-					{
-						RT_NODE_LEAF_125 *n125 = (RT_NODE_LEAF_125 *) b125;
-
-						fprintf(stderr, "%schunk 0x%X value 0x" RT_UINT64_FORMAT_HEX "\n",
-								space, i, (uint64) RT_NODE_LEAF_125_GET_VALUE(n125, i));
-					}
+						appendStringInfo(buf, "%schunk 0x%X\n",
+										 spaces.data, i);
 					else
 					{
 						RT_NODE_INNER_125 *n125 = (RT_NODE_INNER_125 *) b125;
 
-						fprintf(stderr, "%schunk 0x%X ->",
-								space, i);
+						appendStringInfo(buf, "%schunk 0x%X",
+										 spaces.data, i);
 
 						if (recurse)
-							RT_DUMP_NODE(RT_NODE_INNER_125_GET_CHILD(n125, i),
-										 level + 1, recurse);
+						{
+							appendStringInfo(buf, "\n");
+							RT_DUMP_NODE(tree, RT_NODE_INNER_125_GET_CHILD(n125, i),
+										 level + 1, recurse, buf);
+						}
 						else
-							fprintf(stderr, "\n");
+							appendStringInfo(buf, " (skipped)\n");
 					}
 				}
 				break;
 			}
 		case RT_NODE_KIND_256:
 			{
+				if (RT_NODE_IS_LEAF(node))
+				{
+					RT_NODE_LEAF_256 *n256 = (RT_NODE_LEAF_256 *) node;
+
+					appendStringInfo(buf, "%sisset-bitmap: ", spaces.data);
+					for (int i = 0; i < (RT_SLOT_IDX_LIMIT / BITS_PER_BYTE); i++)
+						appendStringInfo(buf, "%X ", ((uint8 *) n256->isset)[i]);
+					appendStringInfo(buf, "\n");
+				}
+
 				for (int i = 0; i < RT_NODE_MAX_SLOTS; i++)
 				{
 					if (RT_NODE_IS_LEAF(node))
@@ -2169,8 +2196,8 @@ RT_DUMP_NODE(RT_PTR_LOCAL node, int level, bool recurse)
 						if (!RT_NODE_LEAF_256_IS_CHUNK_USED(n256, i))
 							continue;
 
-						fprintf(stderr, "%schunk 0x%X value 0x" RT_UINT64_FORMAT_HEX "\n",
-								space, i, (uint64) RT_NODE_LEAF_256_GET_VALUE(n256, i));
+						appendStringInfo(buf, "%schunk 0x%X\n",
+										 spaces.data, i);
 					}
 					else
 					{
@@ -2179,14 +2206,17 @@ RT_DUMP_NODE(RT_PTR_LOCAL node, int level, bool recurse)
 						if (!RT_NODE_INNER_256_IS_CHUNK_USED(n256, i))
 							continue;
 
-						fprintf(stderr, "%schunk 0x%X ->",
-								space, i);
+						appendStringInfo(buf, "%schunk 0x%X",
+										 spaces.data, i);
 
 						if (recurse)
-							RT_DUMP_NODE(RT_NODE_INNER_256_GET_CHILD(n256, i), level + 1,
-										 recurse);
+						{
+							appendStringInfo(buf, "\n");
+							RT_DUMP_NODE(tree, RT_NODE_INNER_256_GET_CHILD(n256, i),
+										 level + 1, recurse, buf);
+						}
 						else
-							fprintf(stderr, "\n");
+							appendStringInfo(buf, " (skipped)\n");
 					}
 				}
 				break;
@@ -2197,38 +2227,40 @@ RT_DUMP_NODE(RT_PTR_LOCAL node, int level, bool recurse)
 RT_SCOPE void
 RT_DUMP_SEARCH(RT_RADIX_TREE *tree, uint64 key)
 {
+	RT_PTR_ALLOC allocnode;
 	RT_PTR_LOCAL node;
+	StringInfoData buf;
 	int			shift;
 	int			level = 0;
 
-	elog(NOTICE, "-----------------------------------------------------------");
-	elog(NOTICE, "max_val = " UINT64_FORMAT "(0x" RT_UINT64_FORMAT_HEX ")",
-		 tree->ctl->max_val, tree->ctl->max_val);
+	RT_STATS(tree);
 
-	if (!tree->ctl->root)
+	if (!RT_PTR_ALLOC_IS_VALID(tree->ctl->root))
 	{
-		elog(NOTICE, "tree is empty");
+		fprintf(stderr, "empty tree\n");
 		return;
 	}
 
 	if (key > tree->ctl->max_val)
 	{
-		elog(NOTICE, "key " UINT64_FORMAT "(0x" RT_UINT64_FORMAT_HEX ") is larger than max val",
-			 key, key);
+		fprintf(stderr, "key " UINT64_FORMAT "(0x" RT_UINT64_FORMAT_HEX ") is larger than max val\n",
+				key, key);
 		return;
 	}
 
-	node = tree->ctl->root;
-	shift = tree->ctl->root->shift;
+	initStringInfo(&buf);
+	allocnode = tree->ctl->root;
+	node = RT_PTR_GET_LOCAL(tree, allocnode);
+	shift = node->shift;
 	while (shift >= 0)
 	{
-		RT_PTR_LOCAL child;
+		RT_PTR_ALLOC child;
 
-		RT_DUMP_NODE(node, level, false);
+		RT_DUMP_NODE(tree, allocnode, level, false, &buf);
 
 		if (RT_NODE_IS_LEAF(node))
 		{
-			uint64		dummy;
+			RT_VALUE_TYPE	dummy;
 
 			/* We reached at a leaf node, find the corresponding slot */
 			RT_NODE_SEARCH_LEAF(node, key, &dummy);
@@ -2239,30 +2271,33 @@ RT_DUMP_SEARCH(RT_RADIX_TREE *tree, uint64 key)
 		if (!RT_NODE_SEARCH_INNER(node, key, &child))
 			break;
 
-		node = child;
+		allocnode = child;
+		node = RT_PTR_GET_LOCAL(tree, allocnode);
 		shift -= RT_NODE_SPAN;
 		level++;
 	}
+
+	fprintf(stderr, "%s", buf.data);
 }
 
 RT_SCOPE void
 RT_DUMP(RT_RADIX_TREE *tree)
 {
+	StringInfoData buf;
 
-	for (int i = 0; i < RT_SIZE_CLASS_COUNT; i++)
-		fprintf(stderr, "%s\tinner_size %zu\tleaf_size %zu\n",
-				RT_SIZE_CLASS_INFO[i].name,
-				RT_SIZE_CLASS_INFO[i].inner_size,
-				RT_SIZE_CLASS_INFO[i].leaf_size);
-	fprintf(stderr, "max_val = " UINT64_FORMAT "\n", tree->ctl->max_val);
+	RT_STATS(tree);
 
-	if (!tree->ctl->root)
+	if (!RT_PTR_ALLOC_IS_VALID(tree->ctl->root))
 	{
 		fprintf(stderr, "empty tree\n");
 		return;
 	}
 
-	RT_DUMP_NODE(tree->ctl->root, 0, true);
+	initStringInfo(&buf);
+
+	RT_DUMP_NODE(tree, tree->ctl->root, 0, true, &buf);
+
+	fprintf(stderr, "%s",buf.data);
 }
 #endif
 
-- 
2.31.1

