Remove open-coded binary heap in pg_dump_sort.c.

Thanks to commit 5af0263afd, binaryheap is available to frontend
code.  This commit replaces the open-coded heap implementation in
pg_dump_sort.c with a binaryheap, saving a few lines of code.

Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/3612876.1689443232%40sss.pgh.pa.us
This commit is contained in:
Nathan Bossart 2023-09-19 19:18:34 -07:00
parent c868cbfef7
commit 559bc17321

View File

@ -16,6 +16,7 @@
#include "postgres_fe.h" #include "postgres_fe.h"
#include "catalog/pg_class_d.h" #include "catalog/pg_class_d.h"
#include "lib/binaryheap.h"
#include "pg_backup_archiver.h" #include "pg_backup_archiver.h"
#include "pg_backup_utils.h" #include "pg_backup_utils.h"
#include "pg_dump.h" #include "pg_dump.h"
@ -161,8 +162,6 @@ static bool TopoSort(DumpableObject **objs,
int numObjs, int numObjs,
DumpableObject **ordering, DumpableObject **ordering,
int *nOrdering); int *nOrdering);
static void addHeapElement(int val, int *heap, int heapLength);
static int removeHeapElement(int *heap, int heapLength);
static void findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs); static void findDependencyLoops(DumpableObject **objs, int nObjs, int totObjs);
static int findLoop(DumpableObject *obj, static int findLoop(DumpableObject *obj,
DumpId startPoint, DumpId startPoint,
@ -174,6 +173,7 @@ static void repairDependencyLoop(DumpableObject **loop,
int nLoop); int nLoop);
static void describeDumpableObject(DumpableObject *obj, static void describeDumpableObject(DumpableObject *obj,
char *buf, int bufsize); char *buf, int bufsize);
static int int_cmp(void *a, void *b, void *arg);
/* /*
@ -374,11 +374,10 @@ TopoSort(DumpableObject **objs,
int *nOrdering) /* output argument */ int *nOrdering) /* output argument */
{ {
DumpId maxDumpId = getMaxDumpId(); DumpId maxDumpId = getMaxDumpId();
int *pendingHeap; binaryheap *pendingHeap;
int *beforeConstraints; int *beforeConstraints;
int *idMap; int *idMap;
DumpableObject *obj; DumpableObject *obj;
int heapLength;
int i, int i,
j, j,
k; k;
@ -403,7 +402,7 @@ TopoSort(DumpableObject **objs,
return true; return true;
/* Create workspace for the above-described heap */ /* Create workspace for the above-described heap */
pendingHeap = (int *) pg_malloc(numObjs * sizeof(int)); pendingHeap = binaryheap_allocate(numObjs, int_cmp, NULL);
/* /*
* Scan the constraints, and for each item in the input, generate a count * Scan the constraints, and for each item in the input, generate a count
@ -434,19 +433,16 @@ TopoSort(DumpableObject **objs,
* Now initialize the heap of items-ready-to-output by filling it with the * Now initialize the heap of items-ready-to-output by filling it with the
* indexes of items that already have beforeConstraints[id] == 0. * indexes of items that already have beforeConstraints[id] == 0.
* *
* The essential property of a heap is heap[(j-1)/2] >= heap[j] for each j * We enter the indexes into pendingHeap in decreasing order so that the
* in the range 1..heapLength-1 (note we are using 0-based subscripts * heap invariant is satisfied at the completion of this loop. This
* here, while the discussion in Knuth assumes 1-based subscripts). So, if * reduces the amount of work that binaryheap_build() must do.
* we simply enter the indexes into pendingHeap[] in decreasing order, we
* a-fortiori have the heap invariant satisfied at completion of this
* loop, and don't need to do any sift-up comparisons.
*/ */
heapLength = 0;
for (i = numObjs; --i >= 0;) for (i = numObjs; --i >= 0;)
{ {
if (beforeConstraints[objs[i]->dumpId] == 0) if (beforeConstraints[objs[i]->dumpId] == 0)
pendingHeap[heapLength++] = i; binaryheap_add_unordered(pendingHeap, (void *) (intptr_t) i);
} }
binaryheap_build(pendingHeap);
/*-------------------- /*--------------------
* Now emit objects, working backwards in the output list. At each step, * Now emit objects, working backwards in the output list. At each step,
@ -464,10 +460,10 @@ TopoSort(DumpableObject **objs,
*-------------------- *--------------------
*/ */
i = numObjs; i = numObjs;
while (heapLength > 0) while (!binaryheap_empty(pendingHeap))
{ {
/* Select object to output by removing largest heap member */ /* Select object to output by removing largest heap member */
j = removeHeapElement(pendingHeap, heapLength--); j = (int) (intptr_t) binaryheap_remove_first(pendingHeap);
obj = objs[j]; obj = objs[j];
/* Output candidate to ordering[] */ /* Output candidate to ordering[] */
ordering[--i] = obj; ordering[--i] = obj;
@ -477,7 +473,7 @@ TopoSort(DumpableObject **objs,
int id = obj->dependencies[k]; int id = obj->dependencies[k];
if ((--beforeConstraints[id]) == 0) if ((--beforeConstraints[id]) == 0)
addHeapElement(idMap[id], pendingHeap, heapLength++); binaryheap_add(pendingHeap, (void *) (intptr_t) idMap[id]);
} }
} }
@ -497,79 +493,13 @@ TopoSort(DumpableObject **objs,
} }
/* Done */ /* Done */
free(pendingHeap); binaryheap_free(pendingHeap);
free(beforeConstraints); free(beforeConstraints);
free(idMap); free(idMap);
return (i == 0); return (i == 0);
} }
/*
* Add an item to a heap (priority queue)
*
* heapLength is the current heap size; caller is responsible for increasing
* its value after the call. There must be sufficient storage at *heap.
*/
static void
addHeapElement(int val, int *heap, int heapLength)
{
int j;
/*
* Sift-up the new entry, per Knuth 5.2.3 exercise 16. Note that Knuth is
* using 1-based array indexes, not 0-based.
*/
j = heapLength;
while (j > 0)
{
int i = (j - 1) >> 1;
if (val <= heap[i])
break;
heap[j] = heap[i];
j = i;
}
heap[j] = val;
}
/*
* Remove the largest item present in a heap (priority queue)
*
* heapLength is the current heap size; caller is responsible for decreasing
* its value after the call.
*
* We remove and return heap[0], which is always the largest element of
* the heap, and then "sift up" to maintain the heap invariant.
*/
static int
removeHeapElement(int *heap, int heapLength)
{
int result = heap[0];
int val;
int i;
if (--heapLength <= 0)
return result;
val = heap[heapLength]; /* value that must be reinserted */
i = 0; /* i is where the "hole" is */
for (;;)
{
int j = 2 * i + 1;
if (j >= heapLength)
break;
if (j + 1 < heapLength &&
heap[j] < heap[j + 1])
j++;
if (val >= heap[j])
break;
heap[i] = heap[j];
i = j;
}
heap[i] = val;
return result;
}
/* /*
* findDependencyLoops - identify loops in TopoSort's failure output, * findDependencyLoops - identify loops in TopoSort's failure output,
* and pass each such loop to repairDependencyLoop() for action * and pass each such loop to repairDependencyLoop() for action
@ -1559,3 +1489,17 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
(int) obj->objType, (int) obj->objType,
obj->dumpId, obj->catId.oid); obj->dumpId, obj->catId.oid);
} }
/* binaryheap comparator that compares "a" and "b" as integers */
static int
int_cmp(void *a, void *b, void *arg)
{
int ai = (int) (intptr_t) a;
int bi = (int) (intptr_t) b;
if (ai < bi)
return -1;
if (ai > bi)
return 1;
return 0;
}