Subject: [PATCH 1/1] allow binaryheap to use any type

From: Nathan Bossart <[email-masked]>
Date: Sat, 2 Sep 2023 11:48:36 -0700

---
 src/backend/executor/nodeGatherMerge.c        | 20 +++---
 src/backend/executor/nodeMergeAppend.c        | 20 +++---
 src/backend/lib/binaryheap.c                  | 71 ++++++++++---------
 src/backend/postmaster/pgarch.c               | 37 +++++-----
 .../replication/logical/reorderbuffer.c       | 22 +++---
 src/backend/storage/buffer/bufmgr.c           | 21 +++---
 src/include/lib/binaryheap.h                  | 17 ++---
 7 files changed, 112 insertions(+), 96 deletions(-)

diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c
index 9d5e1a46e9..4c75d224c8 100644
--- a/src/backend/executor/nodeGatherMerge.c
+++ b/src/backend/executor/nodeGatherMerge.c
@@ -52,7 +52,7 @@ typedef struct GMReaderTupleBuffer
 } GMReaderTupleBuffer;
 
 static TupleTableSlot *ExecGatherMerge(PlanState *pstate);
-static int32 heap_compare_slots(Datum a, Datum b, void *arg);
+static int32 heap_compare_slots(void *a, void *b, void *arg);
 static TupleTableSlot *gather_merge_getnext(GatherMergeState *gm_state);
 static MinimalTuple gm_readnext_tuple(GatherMergeState *gm_state, int nreader,
 									  bool nowait, bool *done);
@@ -428,7 +428,7 @@ gather_merge_setup(GatherMergeState *gm_state)
 	}
 
 	/* Allocate the resources for the merge */
-	gm_state->gm_heap = binaryheap_allocate(nreaders + 1,
+	gm_state->gm_heap = binaryheap_allocate(nreaders + 1, sizeof(int),
 											heap_compare_slots,
 											gm_state);
 }
@@ -489,7 +489,7 @@ reread:
 				/* Don't have a tuple yet, try to get one */
 				if (gather_merge_readnext(gm_state, i, nowait))
 					binaryheap_add_unordered(gm_state->gm_heap,
-											 Int32GetDatum(i));
+											 &i);
 			}
 			else
 			{
@@ -565,14 +565,14 @@ gather_merge_getnext(GatherMergeState *gm_state)
 		 * the heap, because it might now compare differently against the
 		 * other elements of the heap.
 		 */
-		i = DatumGetInt32(binaryheap_first(gm_state->gm_heap));
+		binaryheap_first(gm_state->gm_heap, &i);
 
 		if (gather_merge_readnext(gm_state, i, false))
-			binaryheap_replace_first(gm_state->gm_heap, Int32GetDatum(i));
+			binaryheap_replace_first(gm_state->gm_heap, &i);
 		else
 		{
 			/* reader exhausted, remove it from heap */
-			(void) binaryheap_remove_first(gm_state->gm_heap);
+			binaryheap_remove_first(gm_state->gm_heap, &i);
 		}
 	}
 
@@ -585,7 +585,7 @@ gather_merge_getnext(GatherMergeState *gm_state)
 	else
 	{
 		/* Return next tuple from whichever participant has the leading one */
-		i = DatumGetInt32(binaryheap_first(gm_state->gm_heap));
+		binaryheap_first(gm_state->gm_heap, &i);
 		return gm_state->gm_slots[i];
 	}
 }
@@ -750,11 +750,11 @@ typedef int32 SlotNumber;
  * Compare the tuples in the two given slots.
  */
 static int32
-heap_compare_slots(Datum a, Datum b, void *arg)
+heap_compare_slots(void *a, void *b, void *arg)
 {
 	GatherMergeState *node = (GatherMergeState *) arg;
-	SlotNumber	slot1 = DatumGetInt32(a);
-	SlotNumber	slot2 = DatumGetInt32(b);
+	SlotNumber	slot1 = *((int *) a);
+	SlotNumber	slot2 = *((int *) b);
 
 	TupleTableSlot *s1 = node->gm_slots[slot1];
 	TupleTableSlot *s2 = node->gm_slots[slot2];
diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c
index 21b5726e6e..928b4b3719 100644
--- a/src/backend/executor/nodeMergeAppend.c
+++ b/src/backend/executor/nodeMergeAppend.c
@@ -52,7 +52,7 @@
 typedef int32 SlotNumber;
 
 static TupleTableSlot *ExecMergeAppend(PlanState *pstate);
-static int	heap_compare_slots(Datum a, Datum b, void *arg);
+static int	heap_compare_slots(void *a, void *b, void *arg);

 /* ----------------------------------------------------------------
@@ -125,7 +125,7 @@ ExecInitMergeAppend(MergeAppend *node, EState *estate, int eflags)
 	mergestate->ms_nplans = nplans;
 
 	mergestate->ms_slots = (TupleTableSlot **) palloc0(sizeof(TupleTableSlot *) * nplans);
-	mergestate->ms_heap = binaryheap_allocate(nplans, heap_compare_slots,
+	mergestate->ms_heap = binaryheap_allocate(nplans, sizeof(int), heap_compare_slots,
 											  mergestate);
 
 	/*
@@ -229,7 +229,7 @@ ExecMergeAppend(PlanState *pstate)
 		{
 			node->ms_slots[i] = ExecProcNode(node->mergeplans[i]);
 			if (!TupIsNull(node->ms_slots[i]))
-				binaryheap_add_unordered(node->ms_heap, Int32GetDatum(i));
+				binaryheap_add_unordered(node->ms_heap, &i);
 		}
 		binaryheap_build(node->ms_heap);
 		node->ms_initialized = true;
@@ -244,12 +244,12 @@ ExecMergeAppend(PlanState *pstate)
 		 * by doing this before returning from the prior call, but it's better
 		 * to not pull tuples until necessary.)
 		 */
-		i = DatumGetInt32(binaryheap_first(node->ms_heap));
+		binaryheap_first(node->ms_heap, &i);
 		node->ms_slots[i] = ExecProcNode(node->mergeplans[i]);
 		if (!TupIsNull(node->ms_slots[i]))
-			binaryheap_replace_first(node->ms_heap, Int32GetDatum(i));
+			binaryheap_replace_first(node->ms_heap, &i);
 		else
-			(void) binaryheap_remove_first(node->ms_heap);
+			binaryheap_remove_first(node->ms_heap, &i);
 	}
 
 	if (binaryheap_empty(node->ms_heap))
@@ -259,7 +259,7 @@ ExecMergeAppend(PlanState *pstate)
 	}
 	else
 	{
-		i = DatumGetInt32(binaryheap_first(node->ms_heap));
+		binaryheap_first(node->ms_heap, &i);
 		result = node->ms_slots[i];
 	}
 
@@ -270,11 +270,11 @@ ExecMergeAppend(PlanState *pstate)
  * Compare the tuples in the two given slots.
  */
 static int32
-heap_compare_slots(Datum a, Datum b, void *arg)
+heap_compare_slots(void *a, void *b, void *arg)
 {
 	MergeAppendState *node = (MergeAppendState *) arg;
-	SlotNumber	slot1 = DatumGetInt32(a);
-	SlotNumber	slot2 = DatumGetInt32(b);
+	SlotNumber	slot1 = *((int *) a);
+	SlotNumber	slot2 = *((int *) b);
 
 	TupleTableSlot *s1 = node->ms_slots[slot1];
 	TupleTableSlot *s2 = node->ms_slots[slot2];
diff --git a/src/backend/lib/binaryheap.c b/src/backend/lib/binaryheap.c
index 1737546757..0dc0e18f48 100644
--- a/src/backend/lib/binaryheap.c
+++ b/src/backend/lib/binaryheap.c
@@ -20,6 +20,9 @@
 static void sift_down(binaryheap *heap, int node_off);
 static void sift_up(binaryheap *heap, int node_off);
 
+#define bh_node_ptr(n)	(&heap->bh_nodes[(n) * heap->bh_elem_size])
+#define bh_set(n, d)	(memmove(bh_node_ptr((n)), (d), heap->bh_elem_size))
+
 /*
  * binaryheap_allocate
  *
@@ -29,14 +32,16 @@ static void sift_up(binaryheap *heap, int node_off);
  * argument specified by 'arg'.
  */
 binaryheap *
-binaryheap_allocate(int capacity, binaryheap_comparator compare, void *arg)
+binaryheap_allocate(int capacity, size_t elem_size,
+					binaryheap_comparator compare, void *arg)
 {
 	int			sz;
 	binaryheap *heap;
 
-	sz = offsetof(binaryheap, bh_nodes) + sizeof(Datum) * capacity;
+	sz = offsetof(binaryheap, bh_nodes) + elem_size * capacity;
 	heap = (binaryheap *) palloc(sz);
 	heap->bh_space = capacity;
+	heap->bh_elem_size = elem_size;
 	heap->bh_compare = compare;
 	heap->bh_arg = arg;
 
@@ -106,12 +111,12 @@ parent_offset(int i)
  * afterwards.
  */
 void
-binaryheap_add_unordered(binaryheap *heap, Datum d)
+binaryheap_add_unordered(binaryheap *heap, void *d)
 {
 	if (heap->bh_size >= heap->bh_space)
 		elog(ERROR, "out of binary heap slots");
 	heap->bh_has_heap_property = false;
-	heap->bh_nodes[heap->bh_size] = d;
+	bh_set(heap->bh_size, d);
 	heap->bh_size++;
 }
 
@@ -138,11 +143,11 @@ binaryheap_build(binaryheap *heap)
  * the heap property.
  */
 void
-binaryheap_add(binaryheap *heap, Datum d)
+binaryheap_add(binaryheap *heap, void *d)
 {
 	if (heap->bh_size >= heap->bh_space)
 		elog(ERROR, "out of binary heap slots");
-	heap->bh_nodes[heap->bh_size] = d;
+	bh_set(heap->bh_size, d);
 	heap->bh_size++;
 	sift_up(heap, heap->bh_size - 1);
 }
@@ -154,11 +159,11 @@ binaryheap_add(binaryheap *heap, Datum d)
  * without modifying the heap. The caller must ensure that this
  * routine is not used on an empty heap. Always O(1).
  */
-Datum
-binaryheap_first(binaryheap *heap)
+void
+binaryheap_first(binaryheap *heap, void *result)
 {
 	Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
-	return heap->bh_nodes[0];
+	memmove(result, heap->bh_nodes, heap->bh_elem_size);
 }
 
 /*
@@ -169,31 +174,27 @@ binaryheap_first(binaryheap *heap)
  * that this routine is not used on an empty heap. O(log n) worst
  * case.
  */
-Datum
-binaryheap_remove_first(binaryheap *heap)
+void
+binaryheap_remove_first(binaryheap *heap, void *result)
 {
-	Datum		result;
-
 	Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
 
 	/* extract the root node, which will be the result */
-	result = heap->bh_nodes[0];
+	memmove(result, heap->bh_nodes, heap->bh_elem_size);
 
 	/* easy if heap contains one element */
 	if (heap->bh_size == 1)
 	{
 		heap->bh_size--;
-		return result;
+		return;
 	}
 
 	/*
 	 * Remove the last node, placing it in the vacated root entry, and sift
 	 * the new root node down to its correct position.
 	 */
-	heap->bh_nodes[0] = heap->bh_nodes[--heap->bh_size];
+	bh_set(0, bh_node_ptr(--heap->bh_size));
 	sift_down(heap, 0);
-
-	return result;
 }
 
 /*
@@ -204,11 +205,11 @@ binaryheap_remove_first(binaryheap *heap)
  * sifting the new node down.
  */
 void
-binaryheap_replace_first(binaryheap *heap, Datum d)
+binaryheap_replace_first(binaryheap *heap, void *d)
 {
 	Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
 
-	heap->bh_nodes[0] = d;
+	bh_set(0, d);
 
 	if (heap->bh_size > 1)
 		sift_down(heap, 0);
@@ -221,7 +222,9 @@ binaryheap_replace_first(binaryheap *heap, Datum d)
 static void
 sift_up(binaryheap *heap, int node_off)
 {
-	Datum		node_val = heap->bh_nodes[node_off];
+	char	   *node_val = palloc(heap->bh_elem_size);
+
+	memmove(node_val, bh_node_ptr(node_off), heap->bh_elem_size);
 
 	/*
 	 * Within the loop, the node_off'th array entry is a "hole" that
@@ -232,14 +235,14 @@ sift_up(binaryheap *heap, int node_off)
 	{
 		int			cmp;
 		int			parent_off;
-		Datum		parent_val;
+		void	   *parent_val;
 
 		/*
 		 * If this node is smaller than its parent, the heap condition is
 		 * satisfied, and we're done.
 		 */
 		parent_off = parent_offset(node_off);
-		parent_val = heap->bh_nodes[parent_off];
+		parent_val = bh_node_ptr(parent_off);
 		cmp = heap->bh_compare(node_val,
 							   parent_val,
 							   heap->bh_arg);
@@ -250,11 +253,12 @@ sift_up(binaryheap *heap, int node_off)
 		 * Otherwise, swap the parent value with the hole, and go on to check
 		 * the node's new parent.
 		 */
-		heap->bh_nodes[node_off] = parent_val;
+		bh_set(node_off, parent_val);
 		node_off = parent_off;
 	}
 	/* Re-fill the hole */
-	heap->bh_nodes[node_off] = node_val;
+	bh_set(node_off, node_val);
+	pfree(node_val);
 }
 
 /*
@@ -264,7 +268,9 @@ sift_up(binaryheap *heap, int node_off)
 static void
 sift_down(binaryheap *heap, int node_off)
 {
-	Datum		node_val = heap->bh_nodes[node_off];
+	char	   *node_val = palloc(heap->bh_elem_size);
+
+	memmove(node_val, bh_node_ptr(node_off), heap->bh_elem_size);
 
 	/*
 	 * Within the loop, the node_off'th array entry is a "hole" that
@@ -280,20 +286,20 @@ sift_down(binaryheap *heap, int node_off)
 		/* Is the left child larger than the parent? */
 		if (left_off < heap->bh_size &&
 			heap->bh_compare(node_val,
-							 heap->bh_nodes[left_off],
+							 bh_node_ptr(left_off),
 							 heap->bh_arg) < 0)
 			swap_off = left_off;
 
 		/* Is the right child larger than the parent? */
 		if (right_off < heap->bh_size &&
 			heap->bh_compare(node_val,
-							 heap->bh_nodes[right_off],
+							 bh_node_ptr(right_off),
 							 heap->bh_arg) < 0)
 		{
 			/* swap with the larger child */
 			if (!swap_off ||
-				heap->bh_compare(heap->bh_nodes[left_off],
-								 heap->bh_nodes[right_off],
+				heap->bh_compare(bh_node_ptr(left_off),
+								 bh_node_ptr(right_off),
 								 heap->bh_arg) < 0)
 				swap_off = right_off;
 		}
@@ -309,9 +315,10 @@ sift_down(binaryheap *heap, int node_off)
 		 * Otherwise, swap the hole with the child that violates the heap
 		 * property; then go on to check its children.
 		 */
-		heap->bh_nodes[node_off] = heap->bh_nodes[swap_off];
+		bh_set(node_off, bh_node_ptr(swap_off));
 		node_off = swap_off;
 	}
 	/* Re-fill the hole */
-	heap->bh_nodes[node_off] = node_val;
+	bh_set(node_off, node_val);
+	pfree(node_val);
 }
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 46af349564..a11005708a 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -145,7 +145,7 @@ static bool pgarch_readyXlog(char *xlog);
 static void pgarch_archiveDone(char *xlog);
 static void pgarch_die(int code, Datum arg);
 static void HandlePgArchInterrupts(void);
-static int	ready_file_comparator(Datum a, Datum b, void *arg);
+static int	ready_file_comparator(void *a, void *b, void *arg);
 static void LoadArchiveLibrary(void);
 static void pgarch_call_module_shutdown_cb(int code, Datum arg);
 
@@ -249,7 +249,7 @@ PgArchiverMain(void)
 	arch_files->arch_files_size = 0;
 
 	/* Initialize our max-heap for prioritizing files to archive. */
-	arch_files->arch_heap = binaryheap_allocate(NUM_FILES_PER_DIRECTORY_SCAN,
+	arch_files->arch_heap = binaryheap_allocate(NUM_FILES_PER_DIRECTORY_SCAN, sizeof(char *),
 												ready_file_comparator, NULL);
 
 	/* Load the archive_library. */
@@ -631,22 +631,27 @@ pgarch_readyXlog(char *xlog)
 			/* If the heap isn't full yet, quickly add it. */
 			arch_file = arch_files->arch_filenames[arch_files->arch_heap->bh_size];
 			strcpy(arch_file, basename);
-			binaryheap_add_unordered(arch_files->arch_heap, CStringGetDatum(arch_file));
+			binaryheap_add_unordered(arch_files->arch_heap, &arch_file);
 
 			/* If we just filled the heap, make it a valid one. */
 			if (arch_files->arch_heap->bh_size == NUM_FILES_PER_DIRECTORY_SCAN)
 				binaryheap_build(arch_files->arch_heap);
 		}
-		else if (ready_file_comparator(binaryheap_first(arch_files->arch_heap),
-									   CStringGetDatum(basename), NULL) > 0)
+		else
 		{
-			/*
-			 * Remove the lowest priority file and add the current one to the
-			 * heap.
-			 */
-			arch_file = DatumGetCString(binaryheap_remove_first(arch_files->arch_heap));
-			strcpy(arch_file, basename);
-			binaryheap_add(arch_files->arch_heap, CStringGetDatum(arch_file));
+			char	   *result;
+
+			binaryheap_first(arch_files->arch_heap, &result);
+			if (ready_file_comparator(&result, &basename, NULL) > 0)
+			{
+				/*
+				 * Remove the lowest priority file and add the current one to
+				 * the heap.
+				 */
+				binaryheap_remove_first(arch_files->arch_heap, &arch_file);
+				strcpy(arch_file, basename);
+				binaryheap_add(arch_files->arch_heap, &arch_file);
+			}
 		}
 	}
 	FreeDir(rldir);
@@ -668,7 +673,7 @@ pgarch_readyXlog(char *xlog)
 	 */
 	arch_files->arch_files_size = arch_files->arch_heap->bh_size;
 	for (int i = 0; i < arch_files->arch_files_size; i++)
-		arch_files->arch_files[i] = DatumGetCString(binaryheap_remove_first(arch_files->arch_heap));
+		binaryheap_remove_first(arch_files->arch_heap, &arch_files->arch_files[i]);
 
 	/* Return the highest priority file. */
 	arch_files->arch_files_size--;
@@ -686,10 +691,10 @@ pgarch_readyXlog(char *xlog)
  * If "a" and "b" have equivalent values, 0 will be returned.
  */
 static int
-ready_file_comparator(Datum a, Datum b, void *arg)
+ready_file_comparator(void *a, void *b, void *arg)
 {
-	char	   *a_str = DatumGetCString(a);
-	char	   *b_str = DatumGetCString(b);
+	char	   *a_str = *((char **) a);
+	char	   *b_str = *((char **) b);
 	bool		a_history = IsTLHistoryFileName(a_str);
 	bool		b_history = IsTLHistoryFileName(b_str);
 
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 12edc5772a..b0a84c5ed1 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -1223,11 +1223,11 @@ ReorderBufferCommitChild(ReorderBuffer *rb, TransactionId xid,
  * Binary heap comparison function.
  */
 static int
-ReorderBufferIterCompare(Datum a, Datum b, void *arg)
+ReorderBufferIterCompare(void *a, void *b, void *arg)
 {
 	ReorderBufferIterTXNState *state = (ReorderBufferIterTXNState *) arg;
-	XLogRecPtr	pos_a = state->entries[DatumGetInt32(a)].lsn;
-	XLogRecPtr	pos_b = state->entries[DatumGetInt32(b)].lsn;
+	XLogRecPtr	pos_a = state->entries[*((int *) a)].lsn;
+	XLogRecPtr	pos_b = state->entries[*((int *) b)].lsn;
 
 	if (pos_a < pos_b)
 		return 1;
@@ -1296,7 +1296,7 @@ ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn,
 	}
 
 	/* allocate heap */
-	state->heap = binaryheap_allocate(state->nr_txns,
+	state->heap = binaryheap_allocate(state->nr_txns, sizeof(int),
 									  ReorderBufferIterCompare,
 									  state);
 
@@ -1330,7 +1330,8 @@ ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn,
 		state->entries[off].change = cur_change;
 		state->entries[off].txn = txn;
 
-		binaryheap_add_unordered(state->heap, Int32GetDatum(off++));
+		binaryheap_add_unordered(state->heap, &off);
+		off++;
 	}
 
 	/* add subtransactions if they contain changes */
@@ -1359,7 +1360,8 @@ ReorderBufferIterTXNInit(ReorderBuffer *rb, ReorderBufferTXN *txn,
 			state->entries[off].change = cur_change;
 			state->entries[off].txn = cur_txn;
 
-			binaryheap_add_unordered(state->heap, Int32GetDatum(off++));
+			binaryheap_add_unordered(state->heap, &off);
+			off++;
 		}
 	}
 
@@ -1384,7 +1386,7 @@ ReorderBufferIterTXNNext(ReorderBuffer *rb, ReorderBufferIterTXNState *state)
 	if (state->heap->bh_size == 0)
 		return NULL;
 
-	off = DatumGetInt32(binaryheap_first(state->heap));
+	binaryheap_first(state->heap, &off);
 	entry = &state->entries[off];
 
 	/* free memory we might have "leaked" in the previous *Next call */
@@ -1414,7 +1416,7 @@ ReorderBufferIterTXNNext(ReorderBuffer *rb, ReorderBufferIterTXNState *state)
 		state->entries[off].lsn = next_change->lsn;
 		state->entries[off].change = next_change;
 
-		binaryheap_replace_first(state->heap, Int32GetDatum(off));
+		binaryheap_replace_first(state->heap, &off);
 		return change;
 	}
 
@@ -1450,14 +1452,14 @@ ReorderBufferIterTXNNext(ReorderBuffer *rb, ReorderBufferIterTXNState *state)
 			/* txn stays the same */
 			state->entries[off].lsn = next_change->lsn;
 			state->entries[off].change = next_change;
-			binaryheap_replace_first(state->heap, Int32GetDatum(off));
+			binaryheap_replace_first(state->heap, &off);
 
 			return change;
 		}
 	}
 
 	/* ok, no changes there anymore, remove */
-	binaryheap_remove_first(state->heap);
+	binaryheap_remove_first(state->heap, &off);
 
 	return change;
 }
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 3bd82dbfca..5bd7176b3c 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -501,7 +501,7 @@ static void CheckForBufferLeaks(void);
 static int	rlocator_comparator(const void *p1, const void *p2);
 static inline int buffertag_comparator(const BufferTag *ba, const BufferTag *bb);
 static inline int ckpt_buforder_comparator(const CkptSortItem *a, const CkptSortItem *b);
-static int	ts_ckpt_progress_comparator(Datum a, Datum b, void *arg);
+static int	ts_ckpt_progress_comparator(void *a, void *b, void *arg);

 /*
@@ -2639,7 +2639,7 @@ BufferSync(int flags)
 	 * and compute how large a portion of the total progress a single
 	 * processed buffer is.
 	 */
-	ts_heap = binaryheap_allocate(num_spaces,
+	ts_heap = binaryheap_allocate(num_spaces, sizeof(CkptTsStatus *),
 								  ts_ckpt_progress_comparator,
 								  NULL);
 
@@ -2649,7 +2649,7 @@ BufferSync(int flags)
 
 		ts_stat->progress_slice = (float8) num_to_scan / ts_stat->num_to_scan;
 
-		binaryheap_add_unordered(ts_heap, PointerGetDatum(ts_stat));
+		binaryheap_add_unordered(ts_heap, &ts_stat);
 	}
 
 	binaryheap_build(ts_heap);
@@ -2665,8 +2665,9 @@ BufferSync(int flags)
 	while (!binaryheap_empty(ts_heap))
 	{
 		BufferDesc *bufHdr = NULL;
-		CkptTsStatus *ts_stat = (CkptTsStatus *)
-			DatumGetPointer(binaryheap_first(ts_heap));
+		CkptTsStatus *ts_stat;
+
+		binaryheap_first(ts_heap, &ts_stat);
 
 		buf_id = CkptBufferIds[ts_stat->index].buf_id;
 		Assert(buf_id != -1);
@@ -2708,12 +2709,12 @@ BufferSync(int flags)
 		/* Have all the buffers from the tablespace been processed? */
 		if (ts_stat->num_scanned == ts_stat->num_to_scan)
 		{
-			binaryheap_remove_first(ts_heap);
+			binaryheap_remove_first(ts_heap, &ts_stat);
 		}
 		else
 		{
 			/* update heap with the new progress */
-			binaryheap_replace_first(ts_heap, PointerGetDatum(ts_stat));
+			binaryheap_replace_first(ts_heap, &ts_stat);
 		}
 
 		/*
@@ -5416,10 +5417,10 @@ ckpt_buforder_comparator(const CkptSortItem *a, const CkptSortItem *b)
  * progress.
  */
 static int
-ts_ckpt_progress_comparator(Datum a, Datum b, void *arg)
+ts_ckpt_progress_comparator(void *a, void *b, void *arg)
 {
-	CkptTsStatus *sa = (CkptTsStatus *) a;
-	CkptTsStatus *sb = (CkptTsStatus *) b;
+	CkptTsStatus *sa = *((CkptTsStatus **) a);
+	CkptTsStatus *sb = *((CkptTsStatus **) b);
 
 	/* we want a min-heap, so return 1 for the a < b */
 	if (sa->progress < sb->progress)
diff --git a/src/include/lib/binaryheap.h b/src/include/lib/binaryheap.h
index 52f7b06b25..24228e5b4b 100644
--- a/src/include/lib/binaryheap.h
+++ b/src/include/lib/binaryheap.h
@@ -15,7 +15,7 @@
  * For a max-heap, the comparator must return <0 iff a < b, 0 iff a == b,
  * and >0 iff a > b.  For a min-heap, the conditions are reversed.
  */
-typedef int (*binaryheap_comparator) (Datum a, Datum b, void *arg);
+typedef int (*binaryheap_comparator) (void *a, void *b, void *arg);
 
 /*
  * binaryheap
@@ -31,23 +31,24 @@ typedef struct binaryheap
 {
 	int			bh_size;
 	int			bh_space;
+	size_t		bh_elem_size;
 	bool		bh_has_heap_property;	/* debugging cross-check */
 	binaryheap_comparator bh_compare;
 	void	   *bh_arg;
-	Datum		bh_nodes[FLEXIBLE_ARRAY_MEMBER];
+	char		bh_nodes[FLEXIBLE_ARRAY_MEMBER];
 } binaryheap;
 
-extern binaryheap *binaryheap_allocate(int capacity,
+extern binaryheap *binaryheap_allocate(int capacity, size_t elem_size,
 									   binaryheap_comparator compare,
 									   void *arg);
 extern void binaryheap_reset(binaryheap *heap);
 extern void binaryheap_free(binaryheap *heap);
-extern void binaryheap_add_unordered(binaryheap *heap, Datum d);
+extern void binaryheap_add_unordered(binaryheap *heap, void *d);
 extern void binaryheap_build(binaryheap *heap);
-extern void binaryheap_add(binaryheap *heap, Datum d);
-extern Datum binaryheap_first(binaryheap *heap);
-extern Datum binaryheap_remove_first(binaryheap *heap);
-extern void binaryheap_replace_first(binaryheap *heap, Datum d);
+extern void binaryheap_add(binaryheap *heap, void *d);
+extern void binaryheap_first(binaryheap *heap, void *result);
+extern void binaryheap_remove_first(binaryheap *heap, void *result);
+extern void binaryheap_replace_first(binaryheap *heap, void *d);
 
 #define binaryheap_empty(h)			((h)->bh_size == 0)
 
-- 
2.25.1

--fUYQa+Pmc3FrFX/N--