Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit ed1b1ee

Browse files
committed
Optimize pg_visibility with read streams.
We've measured 5% performance improvement, and this arranges to benefit automatically from future optimizations to the read_stream subsystem. Nazir Bilal Yavuz Discussion: https://postgr.es/m/CAN55FZ1_Ru3XpMgTwsU67FTH2fs_FrRROmb7x6zs+F44QBEiww@mail.gmail.com
1 parent c582b75 commit ed1b1ee

File tree

1 file changed

+93
-21
lines changed

1 file changed

+93
-21
lines changed

contrib/pg_visibility/pg_visibility.c

Lines changed: 93 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "storage/bufmgr.h"
2222
#include "storage/proc.h"
2323
#include "storage/procarray.h"
24+
#include "storage/read_stream.h"
2425
#include "storage/smgr.h"
2526
#include "utils/rel.h"
2627
#include "utils/snapmgr.h"
@@ -41,6 +42,17 @@ typedef struct corrupt_items
4142
ItemPointer tids;
4243
} corrupt_items;
4344

45+
/* for collect_corrupt_items_read_stream_next_block */
46+
struct collect_corrupt_items_read_stream_private
47+
{
48+
bool all_frozen;
49+
bool all_visible;
50+
BlockNumber current_blocknum;
51+
BlockNumber last_exclusive;
52+
Relation rel;
53+
Buffer vmbuffer;
54+
};
55+
4456
PG_FUNCTION_INFO_V1(pg_visibility_map);
4557
PG_FUNCTION_INFO_V1(pg_visibility_map_rel);
4658
PG_FUNCTION_INFO_V1(pg_visibility);
@@ -478,6 +490,7 @@ collect_visibility_data(Oid relid, bool include_pd)
478490
BlockNumber blkno;
479491
Buffer vmbuffer = InvalidBuffer;
480492
BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
493+
ReadStream *stream = NULL;
481494

482495
rel = relation_open(relid, AccessShareLock);
483496

@@ -489,6 +502,22 @@ collect_visibility_data(Oid relid, bool include_pd)
489502
info->next = 0;
490503
info->count = nblocks;
491504

505+
/* Create a stream if reading main fork. */
506+
if (include_pd)
507+
{
508+
BlockRangeReadStreamPrivate p;
509+
510+
p.current_blocknum = 0;
511+
p.last_exclusive = nblocks;
512+
stream = read_stream_begin_relation(READ_STREAM_FULL,
513+
bstrategy,
514+
rel,
515+
MAIN_FORKNUM,
516+
block_range_read_stream_cb,
517+
&p,
518+
0);
519+
}
520+
492521
for (blkno = 0; blkno < nblocks; ++blkno)
493522
{
494523
int32 mapbits;
@@ -513,8 +542,7 @@ collect_visibility_data(Oid relid, bool include_pd)
513542
Buffer buffer;
514543
Page page;
515544

516-
buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
517-
bstrategy);
545+
buffer = read_stream_next_buffer(stream, NULL);
518546
LockBuffer(buffer, BUFFER_LOCK_SHARE);
519547

520548
page = BufferGetPage(buffer);
@@ -525,6 +553,12 @@ collect_visibility_data(Oid relid, bool include_pd)
525553
}
526554
}
527555

556+
if (include_pd)
557+
{
558+
Assert(read_stream_next_buffer(stream, NULL) == InvalidBuffer);
559+
read_stream_end(stream);
560+
}
561+
528562
/* Clean up. */
529563
if (vmbuffer != InvalidBuffer)
530564
ReleaseBuffer(vmbuffer);
@@ -610,6 +644,38 @@ GetStrictOldestNonRemovableTransactionId(Relation rel)
610644
}
611645
}
612646

647+
/*
648+
* Callback function to get next block for read stream object used in
649+
* collect_corrupt_items() function.
650+
*/
651+
static BlockNumber
652+
collect_corrupt_items_read_stream_next_block(ReadStream *stream,
653+
void *callback_private_data,
654+
void *per_buffer_data)
655+
{
656+
struct collect_corrupt_items_read_stream_private *p = callback_private_data;
657+
658+
for (; p->current_blocknum < p->last_exclusive; p->current_blocknum++)
659+
{
660+
bool check_frozen = false;
661+
bool check_visible = false;
662+
663+
/* Make sure we are interruptible. */
664+
CHECK_FOR_INTERRUPTS();
665+
666+
if (p->all_frozen && VM_ALL_FROZEN(p->rel, p->current_blocknum, &p->vmbuffer))
667+
check_frozen = true;
668+
if (p->all_visible && VM_ALL_VISIBLE(p->rel, p->current_blocknum, &p->vmbuffer))
669+
check_visible = true;
670+
if (!check_visible && !check_frozen)
671+
continue;
672+
673+
return p->current_blocknum++;
674+
}
675+
676+
return InvalidBlockNumber;
677+
}
678+
613679
/*
614680
* Returns a list of items whose visibility map information does not match
615681
* the status of the tuples on the page.
@@ -628,12 +694,13 @@ static corrupt_items *
628694
collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
629695
{
630696
Relation rel;
631-
BlockNumber nblocks;
632697
corrupt_items *items;
633-
BlockNumber blkno;
634698
Buffer vmbuffer = InvalidBuffer;
635699
BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
636700
TransactionId OldestXmin = InvalidTransactionId;
701+
struct collect_corrupt_items_read_stream_private p;
702+
ReadStream *stream;
703+
Buffer buffer;
637704

638705
rel = relation_open(relid, AccessShareLock);
639706

@@ -643,8 +710,6 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
643710
if (all_visible)
644711
OldestXmin = GetStrictOldestNonRemovableTransactionId(rel);
645712

646-
nblocks = RelationGetNumberOfBlocks(rel);
647-
648713
/*
649714
* Guess an initial array size. We don't expect many corrupted tuples, so
650715
* start with a small array. This function uses the "next" field to track
@@ -658,42 +723,46 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
658723
items->count = 64;
659724
items->tids = palloc(items->count * sizeof(ItemPointerData));
660725

726+
p.current_blocknum = 0;
727+
p.last_exclusive = RelationGetNumberOfBlocks(rel);
728+
p.rel = rel;
729+
p.vmbuffer = InvalidBuffer;
730+
p.all_frozen = all_frozen;
731+
p.all_visible = all_visible;
732+
stream = read_stream_begin_relation(READ_STREAM_FULL,
733+
bstrategy,
734+
rel,
735+
MAIN_FORKNUM,
736+
collect_corrupt_items_read_stream_next_block,
737+
&p,
738+
0);
739+
661740
/* Loop over every block in the relation. */
662-
for (blkno = 0; blkno < nblocks; ++blkno)
741+
while ((buffer = read_stream_next_buffer(stream, NULL)) != InvalidBuffer)
663742
{
664743
bool check_frozen = false;
665744
bool check_visible = false;
666-
Buffer buffer;
667745
Page page;
668746
OffsetNumber offnum,
669747
maxoff;
748+
BlockNumber blkno;
670749

671750
/* Make sure we are interruptible. */
672751
CHECK_FOR_INTERRUPTS();
673752

674-
/* Use the visibility map to decide whether to check this page. */
675-
if (all_frozen && VM_ALL_FROZEN(rel, blkno, &vmbuffer))
676-
check_frozen = true;
677-
if (all_visible && VM_ALL_VISIBLE(rel, blkno, &vmbuffer))
678-
check_visible = true;
679-
if (!check_visible && !check_frozen)
680-
continue;
681-
682-
/* Read and lock the page. */
683-
buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
684-
bstrategy);
685753
LockBuffer(buffer, BUFFER_LOCK_SHARE);
686754

687755
page = BufferGetPage(buffer);
688756
maxoff = PageGetMaxOffsetNumber(page);
757+
blkno = BufferGetBlockNumber(buffer);
689758

690759
/*
691760
* The visibility map bits might have changed while we were acquiring
692761
* the page lock. Recheck to avoid returning spurious results.
693762
*/
694-
if (check_frozen && !VM_ALL_FROZEN(rel, blkno, &vmbuffer))
763+
if (all_frozen && !VM_ALL_FROZEN(rel, blkno, &vmbuffer))
695764
check_frozen = false;
696-
if (check_visible && !VM_ALL_VISIBLE(rel, blkno, &vmbuffer))
765+
if (all_visible && !VM_ALL_VISIBLE(rel, blkno, &vmbuffer))
697766
check_visible = false;
698767
if (!check_visible && !check_frozen)
699768
{
@@ -778,10 +847,13 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
778847

779848
UnlockReleaseBuffer(buffer);
780849
}
850+
read_stream_end(stream);
781851

782852
/* Clean up. */
783853
if (vmbuffer != InvalidBuffer)
784854
ReleaseBuffer(vmbuffer);
855+
if (p.vmbuffer != InvalidBuffer)
856+
ReleaseBuffer(p.vmbuffer);
785857
relation_close(rel, AccessShareLock);
786858

787859
/*

0 commit comments

Comments
 (0)