Skip to content

Commit a2ff18e

Browse files
committed
Improve sift up/down code in binaryheap.c and logtape.c.
Borrow the logic that's long been used in tuplesort.c: instead of physically swapping the data in two heap entries, keep the value that's being sifted up or down in a local variable, and just move the other values as necessary. This makes the code shorter as well as faster. It's not clear that any current callers are really time-critical enough to notice, but we might as well code heap maintenance the same way everywhere. Ma Liangzhu and Tom Lane Discussion: https://postgr.es/m/17336-fc4e522d26a750fd@postgresql.org
1 parent 2de3c10 commit a2ff18e

File tree

2 files changed

+63
-61
lines changed

2 files changed

+63
-61
lines changed

src/backend/lib/binaryheap.c

+40-30
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
static void sift_down(binaryheap *heap, int node_off);
2121
static void sift_up(binaryheap *heap, int node_off);
22-
static inline void swap_nodes(binaryheap *heap, int a, int b);
2322

2423
/*
2524
* binaryheap_allocate
@@ -173,24 +172,28 @@ binaryheap_first(binaryheap *heap)
173172
Datum
174173
binaryheap_remove_first(binaryheap *heap)
175174
{
175+
Datum result;
176+
176177
Assert(!binaryheap_empty(heap) && heap->bh_has_heap_property);
177178

179+
/* extract the root node, which will be the result */
180+
result = heap->bh_nodes[0];
181+
182+
/* easy if heap contains one element */
178183
if (heap->bh_size == 1)
179184
{
180185
heap->bh_size--;
181-
return heap->bh_nodes[0];
186+
return result;
182187
}
183188

184189
/*
185-
* Swap the root and last nodes, decrease the size of the heap (i.e.
186-
* remove the former root node) and sift the new root node down to its
187-
* correct position.
190+
* Remove the last node, placing it in the vacated root entry, and sift
191+
* the new root node down to its correct position.
188192
*/
189-
swap_nodes(heap, 0, heap->bh_size - 1);
190-
heap->bh_size--;
193+
heap->bh_nodes[0] = heap->bh_nodes[--heap->bh_size];
191194
sift_down(heap, 0);
192195

193-
return heap->bh_nodes[heap->bh_size];
196+
return result;
194197
}
195198

196199
/*
@@ -211,49 +214,47 @@ binaryheap_replace_first(binaryheap *heap, Datum d)
211214
sift_down(heap, 0);
212215
}
213216

214-
/*
215-
* Swap the contents of two nodes.
216-
*/
217-
static inline void
218-
swap_nodes(binaryheap *heap, int a, int b)
219-
{
220-
Datum swap;
221-
222-
swap = heap->bh_nodes[a];
223-
heap->bh_nodes[a] = heap->bh_nodes[b];
224-
heap->bh_nodes[b] = swap;
225-
}
226-
227217
/*
228218
* Sift a node up to the highest position it can hold according to the
229219
* comparator.
230220
*/
231221
static void
232222
sift_up(binaryheap *heap, int node_off)
233223
{
224+
Datum node_val = heap->bh_nodes[node_off];
225+
226+
/*
227+
* Within the loop, the node_off'th array entry is a "hole" that
228+
* notionally holds node_val, but we don't actually store node_val there
229+
* till the end, saving some unnecessary data copying steps.
230+
*/
234231
while (node_off != 0)
235232
{
236233
int cmp;
237234
int parent_off;
235+
Datum parent_val;
238236

239237
/*
240238
* If this node is smaller than its parent, the heap condition is
241239
* satisfied, and we're done.
242240
*/
243241
parent_off = parent_offset(node_off);
244-
cmp = heap->bh_compare(heap->bh_nodes[node_off],
245-
heap->bh_nodes[parent_off],
242+
parent_val = heap->bh_nodes[parent_off];
243+
cmp = heap->bh_compare(node_val,
244+
parent_val,
246245
heap->bh_arg);
247246
if (cmp <= 0)
248247
break;
249248

250249
/*
251-
* Otherwise, swap the node and its parent and go on to check the
252-
* node's new parent.
250+
* Otherwise, swap the parent value with the hole, and go on to check
251+
* the node's new parent.
253252
*/
254-
swap_nodes(heap, node_off, parent_off);
253+
heap->bh_nodes[node_off] = parent_val;
255254
node_off = parent_off;
256255
}
256+
/* Re-fill the hole */
257+
heap->bh_nodes[node_off] = node_val;
257258
}
258259

259260
/*
@@ -263,6 +264,13 @@ sift_up(binaryheap *heap, int node_off)
263264
static void
264265
sift_down(binaryheap *heap, int node_off)
265266
{
267+
Datum node_val = heap->bh_nodes[node_off];
268+
269+
/*
270+
* Within the loop, the node_off'th array entry is a "hole" that
271+
* notionally holds node_val, but we don't actually store node_val there
272+
* till the end, saving some unnecessary data copying steps.
273+
*/
266274
while (true)
267275
{
268276
int left_off = left_offset(node_off);
@@ -271,14 +279,14 @@ sift_down(binaryheap *heap, int node_off)
271279

272280
/* Is the left child larger than the parent? */
273281
if (left_off < heap->bh_size &&
274-
heap->bh_compare(heap->bh_nodes[node_off],
282+
heap->bh_compare(node_val,
275283
heap->bh_nodes[left_off],
276284
heap->bh_arg) < 0)
277285
swap_off = left_off;
278286

279287
/* Is the right child larger than the parent? */
280288
if (right_off < heap->bh_size &&
281-
heap->bh_compare(heap->bh_nodes[node_off],
289+
heap->bh_compare(node_val,
282290
heap->bh_nodes[right_off],
283291
heap->bh_arg) < 0)
284292
{
@@ -298,10 +306,12 @@ sift_down(binaryheap *heap, int node_off)
298306
break;
299307

300308
/*
301-
* Otherwise, swap the node with the child that violates the heap
309+
* Otherwise, swap the hole with the child that violates the heap
302310
* property; then go on to check its children.
303311
*/
304-
swap_nodes(heap, swap_off, node_off);
312+
heap->bh_nodes[node_off] = heap->bh_nodes[swap_off];
305313
node_off = swap_off;
306314
}
315+
/* Re-fill the hole */
316+
heap->bh_nodes[node_off] = node_val;
307317
}

src/backend/utils/sort/logtape.c

+23-31
Original file line numberDiff line numberDiff line change
@@ -340,16 +340,6 @@ ltsReadFillBuffer(LogicalTape *lt)
340340
return (lt->nbytes > 0);
341341
}
342342

343-
static inline void
344-
swap_nodes(long *heap, unsigned long a, unsigned long b)
345-
{
346-
long swap;
347-
348-
swap = heap[a];
349-
heap[a] = heap[b];
350-
heap[b] = swap;
351-
}
352-
353343
static inline unsigned long
354344
left_offset(unsigned long i)
355345
{
@@ -390,31 +380,33 @@ ltsGetFreeBlock(LogicalTapeSet *lts)
390380
long *heap = lts->freeBlocks;
391381
long blocknum;
392382
int heapsize;
393-
unsigned long pos;
383+
long holeval;
384+
unsigned long holepos;
394385

395386
/* freelist empty; allocate a new block */
396387
if (lts->nFreeBlocks == 0)
397388
return lts->nBlocksAllocated++;
398389

390+
/* easy if heap contains one element */
399391
if (lts->nFreeBlocks == 1)
400392
{
401393
lts->nFreeBlocks--;
402394
return lts->freeBlocks[0];
403395
}
404396

405-
/* take top of minheap */
397+
/* remove top of minheap */
406398
blocknum = heap[0];
407399

408-
/* replace with end of minheap array */
409-
heap[0] = heap[--lts->nFreeBlocks];
400+
/* we'll replace it with end of minheap array */
401+
holeval = heap[--lts->nFreeBlocks];
410402

411403
/* sift down */
412-
pos = 0;
404+
holepos = 0; /* holepos is where the "hole" is */
413405
heapsize = lts->nFreeBlocks;
414406
while (true)
415407
{
416-
unsigned long left = left_offset(pos);
417-
unsigned long right = right_offset(pos);
408+
unsigned long left = left_offset(holepos);
409+
unsigned long right = right_offset(holepos);
418410
unsigned long min_child;
419411

420412
if (left < heapsize && right < heapsize)
@@ -426,12 +418,13 @@ ltsGetFreeBlock(LogicalTapeSet *lts)
426418
else
427419
break;
428420

429-
if (heap[min_child] >= heap[pos])
421+
if (heap[min_child] >= holeval)
430422
break;
431423

432-
swap_nodes(heap, min_child, pos);
433-
pos = min_child;
424+
heap[holepos] = heap[min_child];
425+
holepos = min_child;
434426
}
427+
heap[holepos] = holeval;
435428

436429
return blocknum;
437430
}
@@ -483,7 +476,7 @@ static void
483476
ltsReleaseBlock(LogicalTapeSet *lts, long blocknum)
484477
{
485478
long *heap;
486-
unsigned long pos;
479+
unsigned long holepos;
487480

488481
/*
489482
* Do nothing if we're no longer interested in remembering free space.
@@ -508,24 +501,23 @@ ltsReleaseBlock(LogicalTapeSet *lts, long blocknum)
508501
lts->freeBlocksLen * sizeof(long));
509502
}
510503

504+
/* create a "hole" at end of minheap array */
511505
heap = lts->freeBlocks;
512-
pos = lts->nFreeBlocks;
513-
514-
/* place entry at end of minheap array */
515-
heap[pos] = blocknum;
506+
holepos = lts->nFreeBlocks;
516507
lts->nFreeBlocks++;
517508

518-
/* sift up */
519-
while (pos != 0)
509+
/* sift up to insert blocknum */
510+
while (holepos != 0)
520511
{
521-
unsigned long parent = parent_offset(pos);
512+
unsigned long parent = parent_offset(holepos);
522513

523-
if (heap[parent] < heap[pos])
514+
if (heap[parent] < blocknum)
524515
break;
525516

526-
swap_nodes(heap, parent, pos);
527-
pos = parent;
517+
heap[holepos] = heap[parent];
518+
holepos = parent;
528519
}
520+
heap[holepos] = blocknum;
529521
}
530522

531523
/*

0 commit comments

Comments
 (0)