Skip to content

Commit fb1a59d

Browse files
committed
Refactor heapam.c adding heapgettup_initial_block function
Here we adjust heapgettup() and heapgettup_pagemode() to move the code that fetches the first block number to scan out into a helper function. This removes some code duplication. Author: Melanie Plageman Reviewed-by: David Rowley Discussion: https://postgr.es/m/CAAKRu_bvkhka0CZQun28KTqhuUh5ZqY=_T8QEqZqOL02rpi2bw@mail.gmail.com
1 parent 253432f commit fb1a59d

File tree

1 file changed

+102
-121
lines changed

1 file changed

+102
-121
lines changed

src/backend/access/heap/heapam.c

Lines changed: 102 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,67 @@ heapgetpage(TableScanDesc sscan, BlockNumber block)
483483
scan->rs_ntuples = ntup;
484484
}
485485

486+
/*
487+
* heapgettup_initial_block - return the first BlockNumber to scan
488+
*
489+
* Returns InvalidBlockNumber when there are no blocks to scan. This can
490+
* occur with empty tables and in parallel scans when parallel workers get all
491+
* of the pages before we can get a chance to get our first page.
492+
*/
493+
static BlockNumber
494+
heapgettup_initial_block(HeapScanDesc scan, ScanDirection dir)
495+
{
496+
Assert(!scan->rs_inited);
497+
498+
/* When there are no pages to scan, return InvalidBlockNumber */
499+
if (scan->rs_nblocks == 0 || scan->rs_numblocks == 0)
500+
return InvalidBlockNumber;
501+
502+
if (ScanDirectionIsForward(dir))
503+
{
504+
/* serial scan */
505+
if (scan->rs_base.rs_parallel == NULL)
506+
return scan->rs_startblock;
507+
else
508+
{
509+
/* parallel scan */
510+
table_block_parallelscan_startblock_init(scan->rs_base.rs_rd,
511+
scan->rs_parallelworkerdata,
512+
(ParallelBlockTableScanDesc) scan->rs_base.rs_parallel);
513+
514+
/* may return InvalidBlockNumber if there are no more blocks */
515+
return table_block_parallelscan_nextpage(scan->rs_base.rs_rd,
516+
scan->rs_parallelworkerdata,
517+
(ParallelBlockTableScanDesc) scan->rs_base.rs_parallel);
518+
}
519+
}
520+
else
521+
{
522+
/* backward parallel scan not supported */
523+
Assert(scan->rs_base.rs_parallel == NULL);
524+
525+
/*
526+
* Disable reporting to syncscan logic in a backwards scan; it's not
527+
* very likely anyone else is doing the same thing at the same time,
528+
* and much more likely that we'll just bollix things for forward
529+
* scanners.
530+
*/
531+
scan->rs_base.rs_flags &= ~SO_ALLOW_SYNC;
532+
533+
/*
534+
* Start from last page of the scan. Ensure we take into account
535+
* rs_numblocks if it's been adjusted by heap_setscanlimits().
536+
*/
537+
if (scan->rs_numblocks != InvalidBlockNumber)
538+
return (scan->rs_startblock + scan->rs_numblocks - 1) % scan->rs_nblocks;
539+
540+
if (scan->rs_startblock > 0)
541+
return scan->rs_startblock - 1;
542+
543+
return scan->rs_nblocks - 1;
544+
}
545+
}
546+
486547
/* ----------------
487548
* heapgettup - fetch next heap tuple
488549
*
@@ -527,38 +588,19 @@ heapgettup(HeapScanDesc scan,
527588
{
528589
if (!scan->rs_inited)
529590
{
591+
block = heapgettup_initial_block(scan, dir);
592+
530593
/*
531-
* return null immediately if relation is empty
594+
* Check if we have reached the end of the scan already. This
595+
* could happen if the table is empty or if the parallel workers
596+
* have already finished the scan before we did anything ourselves
532597
*/
533-
if (scan->rs_nblocks == 0 || scan->rs_numblocks == 0)
598+
if (block == InvalidBlockNumber)
534599
{
535600
Assert(!BufferIsValid(scan->rs_cbuf));
536601
tuple->t_data = NULL;
537602
return;
538603
}
539-
if (scan->rs_base.rs_parallel != NULL)
540-
{
541-
ParallelBlockTableScanDesc pbscan =
542-
(ParallelBlockTableScanDesc) scan->rs_base.rs_parallel;
543-
ParallelBlockTableScanWorker pbscanwork =
544-
scan->rs_parallelworkerdata;
545-
546-
table_block_parallelscan_startblock_init(scan->rs_base.rs_rd,
547-
pbscanwork, pbscan);
548-
549-
block = table_block_parallelscan_nextpage(scan->rs_base.rs_rd,
550-
pbscanwork, pbscan);
551-
552-
/* Other processes might have already finished the scan. */
553-
if (block == InvalidBlockNumber)
554-
{
555-
Assert(!BufferIsValid(scan->rs_cbuf));
556-
tuple->t_data = NULL;
557-
return;
558-
}
559-
}
560-
else
561-
block = scan->rs_startblock; /* first page */
562604
heapgetpage((TableScanDesc) scan, block);
563605
lineoff = FirstOffsetNumber; /* first offnum */
564606
scan->rs_inited = true;
@@ -582,60 +624,40 @@ heapgettup(HeapScanDesc scan,
582624
}
583625
else
584626
{
585-
/* backward parallel scan not supported */
586-
Assert(scan->rs_base.rs_parallel == NULL);
587-
588627
if (!scan->rs_inited)
589628
{
629+
block = heapgettup_initial_block(scan, dir);
630+
590631
/*
591-
* return null immediately if relation is empty
632+
* Check if we have reached the end of the scan already. This
633+
* could happen if the table is empty.
592634
*/
593-
if (scan->rs_nblocks == 0 || scan->rs_numblocks == 0)
635+
if (block == InvalidBlockNumber)
594636
{
595637
Assert(!BufferIsValid(scan->rs_cbuf));
596638
tuple->t_data = NULL;
597639
return;
598640
}
599641

600-
/*
601-
* Disable reporting to syncscan logic in a backwards scan; it's
602-
* not very likely anyone else is doing the same thing at the same
603-
* time, and much more likely that we'll just bollix things for
604-
* forward scanners.
605-
*/
606-
scan->rs_base.rs_flags &= ~SO_ALLOW_SYNC;
607-
608-
/*
609-
* Start from last page of the scan. Ensure we take into account
610-
* rs_numblocks if it's been adjusted by heap_setscanlimits().
611-
*/
612-
if (scan->rs_numblocks != InvalidBlockNumber)
613-
block = (scan->rs_startblock + scan->rs_numblocks - 1) % scan->rs_nblocks;
614-
else if (scan->rs_startblock > 0)
615-
block = scan->rs_startblock - 1;
616-
else
617-
block = scan->rs_nblocks - 1;
618642
heapgetpage((TableScanDesc) scan, block);
643+
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
644+
645+
page = BufferGetPage(scan->rs_cbuf);
646+
TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page);
647+
lines = PageGetMaxOffsetNumber(page);
648+
lineoff = lines; /* final offnum */
649+
scan->rs_inited = true;
619650
}
620651
else
621652
{
622653
/* continue from previously returned page/tuple */
623654
block = scan->rs_cblock; /* current page */
624-
}
655+
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
625656

626-
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
657+
page = BufferGetPage(scan->rs_cbuf);
658+
TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page);
659+
lines = PageGetMaxOffsetNumber(page);
627660

628-
page = BufferGetPage(scan->rs_cbuf);
629-
TestForOldSnapshot(snapshot, scan->rs_base.rs_rd, page);
630-
lines = PageGetMaxOffsetNumber(page);
631-
632-
if (!scan->rs_inited)
633-
{
634-
lineoff = lines; /* final offnum */
635-
scan->rs_inited = true;
636-
}
637-
else
638-
{
639661
/*
640662
* The previous returned tuple may have been vacuumed since the
641663
* previous scan when we use a non-MVCC snapshot, so we must
@@ -837,38 +859,19 @@ heapgettup_pagemode(HeapScanDesc scan,
837859
{
838860
if (!scan->rs_inited)
839861
{
862+
block = heapgettup_initial_block(scan, dir);
863+
840864
/*
841-
* return null immediately if relation is empty
865+
* Check if we have reached the end of the scan already. This
866+
* could happen if the table is empty or if the parallel workers
867+
* have already finished the scan before we did anything ourselves
842868
*/
843-
if (scan->rs_nblocks == 0 || scan->rs_numblocks == 0)
869+
if (block == InvalidBlockNumber)
844870
{
845871
Assert(!BufferIsValid(scan->rs_cbuf));
846872
tuple->t_data = NULL;
847873
return;
848874
}
849-
if (scan->rs_base.rs_parallel != NULL)
850-
{
851-
ParallelBlockTableScanDesc pbscan =
852-
(ParallelBlockTableScanDesc) scan->rs_base.rs_parallel;
853-
ParallelBlockTableScanWorker pbscanwork =
854-
scan->rs_parallelworkerdata;
855-
856-
table_block_parallelscan_startblock_init(scan->rs_base.rs_rd,
857-
pbscanwork, pbscan);
858-
859-
block = table_block_parallelscan_nextpage(scan->rs_base.rs_rd,
860-
pbscanwork, pbscan);
861-
862-
/* Other processes might have already finished the scan. */
863-
if (block == InvalidBlockNumber)
864-
{
865-
Assert(!BufferIsValid(scan->rs_cbuf));
866-
tuple->t_data = NULL;
867-
return;
868-
}
869-
}
870-
else
871-
block = scan->rs_startblock; /* first page */
872875
heapgetpage((TableScanDesc) scan, block);
873876
lineindex = 0;
874877
scan->rs_inited = true;
@@ -889,58 +892,36 @@ heapgettup_pagemode(HeapScanDesc scan,
889892
}
890893
else
891894
{
892-
/* backward parallel scan not supported */
893-
Assert(scan->rs_base.rs_parallel == NULL);
894-
895895
if (!scan->rs_inited)
896896
{
897+
block = heapgettup_initial_block(scan, dir);
898+
897899
/*
898-
* return null immediately if relation is empty
900+
* Check if we have reached the end of the scan already. This
901+
* could happen if the table is empty.
899902
*/
900-
if (scan->rs_nblocks == 0 || scan->rs_numblocks == 0)
903+
if (block == InvalidBlockNumber)
901904
{
902905
Assert(!BufferIsValid(scan->rs_cbuf));
903906
tuple->t_data = NULL;
904907
return;
905908
}
906909

907-
/*
908-
* Disable reporting to syncscan logic in a backwards scan; it's
909-
* not very likely anyone else is doing the same thing at the same
910-
* time, and much more likely that we'll just bollix things for
911-
* forward scanners.
912-
*/
913-
scan->rs_base.rs_flags &= ~SO_ALLOW_SYNC;
914-
915-
/*
916-
* Start from last page of the scan. Ensure we take into account
917-
* rs_numblocks if it's been adjusted by heap_setscanlimits().
918-
*/
919-
if (scan->rs_numblocks != InvalidBlockNumber)
920-
block = (scan->rs_startblock + scan->rs_numblocks - 1) % scan->rs_nblocks;
921-
else if (scan->rs_startblock > 0)
922-
block = scan->rs_startblock - 1;
923-
else
924-
block = scan->rs_nblocks - 1;
925910
heapgetpage((TableScanDesc) scan, block);
911+
page = BufferGetPage(scan->rs_cbuf);
912+
TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
913+
lines = scan->rs_ntuples;
914+
lineindex = lines - 1;
915+
scan->rs_inited = true;
926916
}
927917
else
928918
{
929919
/* continue from previously returned page/tuple */
930920
block = scan->rs_cblock; /* current page */
931-
}
932-
933-
page = BufferGetPage(scan->rs_cbuf);
934-
TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
935-
lines = scan->rs_ntuples;
936921

937-
if (!scan->rs_inited)
938-
{
939-
lineindex = lines - 1;
940-
scan->rs_inited = true;
941-
}
942-
else
943-
{
922+
page = BufferGetPage(scan->rs_cbuf);
923+
TestForOldSnapshot(scan->rs_base.rs_snapshot, scan->rs_base.rs_rd, page);
924+
lines = scan->rs_ntuples;
944925
lineindex = scan->rs_cindex - 1;
945926
}
946927
/* block and lineindex now reference the previous visible tid */

0 commit comments

Comments
 (0)