Small optimization set tuple block/tableOid once
Hi.
Inspired by [1]Re: AIO writes vs hint bits vs checksums </messages/by-id/lxzj26ga6ippdeunz6kuncectr5gfuugmm2ry22qu6hcx6oid6@lzx3sjsqhmt6>
There is an opportunity for optimization according to the commit:
2904324 <http://2904324a88f672b2ecc22735279c16d6e1ee178c>
" Due to splitting the block id into two 16 bit integers, BlockIdSet() is
more expensive than one might think. Doing it once per returned tuple shows
up as a small but reliably reproducible cost. It's simple enough to set the
block number just once per block in pagemode, so do so."
By moving the invariants out of the loop, it really is an improvement.
Then the following sources can be optimized:
contrib/pg_visibility/pg_visibility.c
contrib/pgstattuple/pgstatapprox.c
src/backend/access/heap/heapam.c
src/backend/access/heap/heapam_handler.c
src/backend/access/heap/pruneheap.c
src/backend/access/heap/vacuumlazy.c
src/backend/commands/dbcommands.c
Attached all patchs.
best regards,
Ranier Vilela
[1]: Re: AIO writes vs hint bits vs checksums </messages/by-id/lxzj26ga6ippdeunz6kuncectr5gfuugmm2ry22qu6hcx6oid6@lzx3sjsqhmt6>
</messages/by-id/lxzj26ga6ippdeunz6kuncectr5gfuugmm2ry22qu6hcx6oid6@lzx3sjsqhmt6>
Attachments:
pg_visibility_set_tuple_block_once.patchapplication/octet-stream; name=pg_visibility_set_tuple_block_once.patchDownload
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index d79ef35006..d0c73eaeb0 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -769,6 +769,7 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
OffsetNumber offnum,
maxoff;
BlockNumber blkno;
+ HeapTupleData tuple;
/* Make sure we are interruptible. */
CHECK_FOR_INTERRUPTS();
@@ -793,12 +794,15 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
continue;
}
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&tuple.t_self, blkno);
+ tuple.t_tableOid = relid;
+
/* Iterate over each tuple on the page. */
for (offnum = FirstOffsetNumber;
offnum <= maxoff;
offnum = OffsetNumberNext(offnum))
{
- HeapTupleData tuple;
ItemId itemid;
itemid = PageGetItemId(page, offnum);
@@ -807,19 +811,18 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
if (!ItemIdIsUsed(itemid) || ItemIdIsRedirected(itemid))
continue;
+ ItemPointerSetOffsetNumber(&tuple.t_self, offnum);
+
/* Dead line pointers are neither all-visible nor frozen. */
if (ItemIdIsDead(itemid))
{
- ItemPointerSet(&(tuple.t_self), blkno, offnum);
record_corrupt_item(items, &tuple.t_self);
continue;
}
/* Initialize a HeapTupleData structure for checks below. */
- ItemPointerSet(&(tuple.t_self), blkno, offnum);
tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
tuple.t_len = ItemIdGetLength(itemid);
- tuple.t_tableOid = relid;
/*
* If we're checking whether the page is all-visible, we expect
pgstattuple_set_tuple_block_once.patchapplication/octet-stream; name=pgstattuple_set_tuple_block_once.patchDownload
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index a59ff4e9d4..26afe55c01 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -78,6 +78,7 @@ statapprox_heap(Relation rel, output_type *stat)
OffsetNumber offnum,
maxoff;
Size freespace;
+ HeapTupleData tuple;
CHECK_FOR_INTERRUPTS();
@@ -118,12 +119,15 @@ statapprox_heap(Relation rel, output_type *stat)
*/
maxoff = PageGetMaxOffsetNumber(page);
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&tuple.t_self, blkno);
+ tuple.t_tableOid = RelationGetRelid(rel);
+
for (offnum = FirstOffsetNumber;
offnum <= maxoff;
offnum = OffsetNumberNext(offnum))
{
ItemId itemid;
- HeapTupleData tuple;
itemid = PageGetItemId(page, offnum);
@@ -135,11 +139,9 @@ statapprox_heap(Relation rel, output_type *stat)
Assert(ItemIdIsNormal(itemid));
- ItemPointerSet(&(tuple.t_self), blkno, offnum);
-
tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
tuple.t_len = ItemIdGetLength(itemid);
- tuple.t_tableOid = RelationGetRelid(rel);
+ ItemPointerSetOffsetNumber(&tuple.t_self, offnum);
/*
* We follow VACUUM's lead in counting INSERT_IN_PROGRESS tuples
heapam_set_tuple_block_once.patchapplication/octet-stream; name=heapam_set_tuple_block_once.patchDownload
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index cedaa195cb..148a979699 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -508,13 +508,17 @@ page_collect_tuples(HeapScanDesc scan, Snapshot snapshot,
BlockNumber block, int lines,
bool all_visible, bool check_serializable)
{
+ HeapTupleData loctup;
int ntup = 0;
OffsetNumber lineoff;
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&loctup.t_self, block);
+ loctup.t_tableOid = RelationGetRelid(scan->rs_base.rs_rd);
+
for (lineoff = FirstOffsetNumber; lineoff <= lines; lineoff++)
{
ItemId lpp = PageGetItemId(page, lineoff);
- HeapTupleData loctup;
bool valid;
if (!ItemIdIsNormal(lpp))
@@ -522,8 +526,7 @@ page_collect_tuples(HeapScanDesc scan, Snapshot snapshot,
loctup.t_data = (HeapTupleHeader) PageGetItem(page, lpp);
loctup.t_len = ItemIdGetLength(lpp);
- loctup.t_tableOid = RelationGetRelid(scan->rs_base.rs_rd);
- ItemPointerSet(&(loctup.t_self), block, lineoff);
+ ItemPointerSetOffsetNumber(&loctup.t_self, lineoff);
if (all_visible)
valid = true;
@@ -931,6 +934,10 @@ heapgettup(HeapScanDesc scan,
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
page = heapgettup_start_page(scan, dir, &linesleft, &lineoff);
+
+ /* block is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&tuple->t_self, scan->rs_cblock);
+
continue_page:
/*
@@ -950,7 +957,7 @@ continue_page:
tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp);
tuple->t_len = ItemIdGetLength(lpp);
- ItemPointerSet(&(tuple->t_self), scan->rs_cblock, lineoff);
+ ItemPointerSetOffsetNumber(&tuple->t_self, lineoff);
visible = HeapTupleSatisfiesVisibility(tuple,
scan->rs_base.rs_snapshot,
@@ -1766,6 +1773,10 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
Assert(TransactionIdIsValid(RecentXmin));
Assert(BufferGetBlockNumber(buffer) == blkno);
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&heapTuple->t_self, blkno);
+ heapTuple->t_tableOid = RelationGetRelid(relation);
+
/* Scan through possible multiple members of HOT-chain */
for (;;)
{
@@ -1800,8 +1811,7 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
*/
heapTuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
heapTuple->t_len = ItemIdGetLength(lp);
- heapTuple->t_tableOid = RelationGetRelid(relation);
- ItemPointerSet(&heapTuple->t_self, blkno, offnum);
+ ItemPointerSetOffsetNumber(&heapTuple->t_self, offnum);
/*
* Shouldn't see a HEAP_ONLY tuple at chain start.
heapam_handler_set_tuple_block_once.patchapplication/octet-stream; name=heapam_handler_set_tuple_block_once.patchDownload
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 24d3765aa2..5c42bce2de 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -1031,6 +1031,7 @@ heapam_scan_analyze_next_tuple(TableScanDesc scan, TransactionId OldestXmin,
TupleTableSlot *slot)
{
HeapScanDesc hscan = (HeapScanDesc) scan;
+ HeapTuple targtuple;
Page targpage;
OffsetNumber maxoffset;
BufferHeapTupleTableSlot *hslot;
@@ -1038,14 +1039,18 @@ heapam_scan_analyze_next_tuple(TableScanDesc scan, TransactionId OldestXmin,
Assert(TTS_IS_BUFFERTUPLE(slot));
hslot = (BufferHeapTupleTableSlot *) slot;
+ targtuple = &hslot->base.tupdata;
targpage = BufferGetPage(hscan->rs_cbuf);
maxoffset = PageGetMaxOffsetNumber(targpage);
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&targtuple->t_self, hscan->rs_cblock);
+ targtuple->t_tableOid = RelationGetRelid(scan->rs_rd);
+
/* Inner loop over all tuples on the selected page */
for (; hscan->rs_cindex <= maxoffset; hscan->rs_cindex++)
{
ItemId itemid;
- HeapTuple targtuple = &hslot->base.tupdata;
bool sample_it = false;
itemid = PageGetItemId(targpage, hscan->rs_cindex);
@@ -1063,11 +1068,9 @@ heapam_scan_analyze_next_tuple(TableScanDesc scan, TransactionId OldestXmin,
continue;
}
- ItemPointerSet(&targtuple->t_self, hscan->rs_cblock, hscan->rs_cindex);
-
- targtuple->t_tableOid = RelationGetRelid(scan->rs_rd);
targtuple->t_data = (HeapTupleHeader) PageGetItem(targpage, itemid);
targtuple->t_len = ItemIdGetLength(itemid);
+ ItemPointerSetOffsetNumber(&targtuple->t_self, hscan->rs_cindex);
switch (HeapTupleSatisfiesVacuum(targtuple, OldestXmin,
hscan->rs_cbuf))
@@ -2291,6 +2294,7 @@ heapam_scan_sample_next_tuple(TableScanDesc scan, SampleScanState *scanstate,
TupleTableSlot *slot)
{
HeapScanDesc hscan = (HeapScanDesc) scan;
+ HeapTuple tuple = &(hscan->rs_ctup);
TsmRoutine *tsm = scanstate->tsmroutine;
BlockNumber blockno = hscan->rs_cblock;
bool pagemode = (scan->rs_flags & SO_ALLOW_PAGEMODE) != 0;
@@ -2311,6 +2315,9 @@ heapam_scan_sample_next_tuple(TableScanDesc scan, SampleScanState *scanstate,
!scan->rs_snapshot->takenDuringRecovery;
maxoffset = PageGetMaxOffsetNumber(page);
+ /* block is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&tuple->t_self, blockno);
+
for (;;)
{
OffsetNumber tupoffset;
@@ -2326,7 +2333,6 @@ heapam_scan_sample_next_tuple(TableScanDesc scan, SampleScanState *scanstate,
{
ItemId itemid;
bool visible;
- HeapTuple tuple = &(hscan->rs_ctup);
/* Skip invalid tuple pointers. */
itemid = PageGetItemId(page, tupoffset);
@@ -2335,8 +2341,7 @@ heapam_scan_sample_next_tuple(TableScanDesc scan, SampleScanState *scanstate,
tuple->t_data = (HeapTupleHeader) PageGetItem(page, itemid);
tuple->t_len = ItemIdGetLength(itemid);
- ItemPointerSet(&(tuple->t_self), blockno, tupoffset);
-
+ ItemPointerSetOffsetNumber(&tuple->t_self, blockno);
if (all_visible)
visible = true;
@@ -2578,18 +2583,21 @@ BitmapHeapScanNextBlock(TableScanDesc scan,
* tbmres; but we have to follow any HOT chain starting at each such
* offset.
*/
+ ItemPointerData tid;
int curslot;
/* We must have extracted the tuple offsets by now */
Assert(noffsets > -1);
+ /* block is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&tid, block);
+
for (curslot = 0; curslot < noffsets; curslot++)
{
OffsetNumber offnum = offsets[curslot];
- ItemPointerData tid;
HeapTupleData heapTuple;
- ItemPointerSet(&tid, block, offnum);
+ ItemPointerSetOffsetNumber(&tid, offnum);
if (heap_hot_search_buffer(&tid, scan->rs_rd, buffer, snapshot,
&heapTuple, NULL, true))
hscan->rs_vistuples[ntup++] = ItemPointerGetOffsetNumber(&tid);
@@ -2604,11 +2612,15 @@ BitmapHeapScanNextBlock(TableScanDesc scan,
Page page = BufferGetPage(buffer);
OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
OffsetNumber offnum;
+ HeapTupleData loctup;
+
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&loctup.t_self, block);
+ loctup.t_tableOid = scan->rs_rd->rd_id;
for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum))
{
ItemId lp;
- HeapTupleData loctup;
bool valid;
lp = PageGetItemId(page, offnum);
@@ -2616,8 +2628,8 @@ BitmapHeapScanNextBlock(TableScanDesc scan,
continue;
loctup.t_data = (HeapTupleHeader) PageGetItem(page, lp);
loctup.t_len = ItemIdGetLength(lp);
- loctup.t_tableOid = scan->rs_rd->rd_id;
- ItemPointerSet(&loctup.t_self, block, offnum);
+ ItemPointerSetOffsetNumber(&loctup.t_self, offnum);
+
valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);
if (valid)
{
pruneheap_set_tuple_block_once.patchapplication/octet-stream; name=pruneheap_set_tuple_block_once.patchDownload
diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c
index a8025889be..7bf73f4d93 100644
--- a/src/backend/access/heap/pruneheap.c
+++ b/src/backend/access/heap/pruneheap.c
@@ -467,6 +467,9 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
prstate.visibility_cutoff_xid = InvalidTransactionId;
maxoff = PageGetMaxOffsetNumber(page);
+
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&tup.t_self, blockno);
tup.t_tableOid = RelationGetRelid(relation);
/*
@@ -540,7 +543,7 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
htup = (HeapTupleHeader) PageGetItem(page, itemid);
tup.t_data = htup;
tup.t_len = ItemIdGetLength(itemid);
- ItemPointerSet(&tup.t_self, blockno, offnum);
+ ItemPointerSetOffsetNumber(&tup.t_self, offnum);
prstate.htsv[offnum] = heap_prune_satisfies_vacuum(&prstate, &tup,
buffer);
vacuumlazy_set_tuple_block_once.patchapplication/octet-stream; name=vacuumlazy_set_tuple_block_once.patchDownload
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index f28326bad0..175f83cf64 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -2249,6 +2249,7 @@ lazy_scan_noprune(LVRelState *vacrel,
missed_dead_tuples;
bool hastup;
HeapTupleHeader tupleheader;
+ HeapTupleData tuple;
TransactionId NoFreezePageRelfrozenXid = vacrel->NewRelfrozenXid;
MultiXactId NoFreezePageRelminMxid = vacrel->NewRelminMxid;
OffsetNumber deadoffsets[MaxHeapTuplesPerPage];
@@ -2262,13 +2263,16 @@ lazy_scan_noprune(LVRelState *vacrel,
recently_dead_tuples = 0;
missed_dead_tuples = 0;
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&tuple.t_self, blkno);
+ tuple.t_tableOid = RelationGetRelid(vacrel->rel);
+
maxoff = PageGetMaxOffsetNumber(page);
for (offnum = FirstOffsetNumber;
offnum <= maxoff;
offnum = OffsetNumberNext(offnum))
{
ItemId itemid;
- HeapTupleData tuple;
vacrel->offnum = offnum;
itemid = PageGetItemId(page, offnum);
@@ -2326,10 +2330,9 @@ lazy_scan_noprune(LVRelState *vacrel,
*/
}
- ItemPointerSet(&(tuple.t_self), blkno, offnum);
tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
tuple.t_len = ItemIdGetLength(itemid);
- tuple.t_tableOid = RelationGetRelid(vacrel->rel);
+ ItemPointerSetOffsetNumber(&tuple.t_self, offnum);
switch (HeapTupleSatisfiesVacuum(&tuple, vacrel->cutoffs.OldestXmin,
buf))
@@ -3621,17 +3624,21 @@ heap_page_is_all_visible(LVRelState *vacrel, Buffer buf,
OffsetNumber offnum,
maxoff;
bool all_visible = true;
+ HeapTupleData tuple;
*visibility_cutoff_xid = InvalidTransactionId;
*all_frozen = true;
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&tuple.t_self, blockno);
+ tuple.t_tableOid = RelationGetRelid(vacrel->rel);
+
maxoff = PageGetMaxOffsetNumber(page);
for (offnum = FirstOffsetNumber;
offnum <= maxoff && all_visible;
offnum = OffsetNumberNext(offnum))
{
ItemId itemid;
- HeapTupleData tuple;
/*
* Set the offset number so that we can display it along with any
@@ -3644,8 +3651,6 @@ heap_page_is_all_visible(LVRelState *vacrel, Buffer buf,
if (!ItemIdIsUsed(itemid) || ItemIdIsRedirected(itemid))
continue;
- ItemPointerSet(&(tuple.t_self), blockno, offnum);
-
/*
* Dead line pointers can have index pointers pointing to them. So
* they can't be treated as visible
@@ -3661,7 +3666,7 @@ heap_page_is_all_visible(LVRelState *vacrel, Buffer buf,
tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
tuple.t_len = ItemIdGetLength(itemid);
- tuple.t_tableOid = RelationGetRelid(vacrel->rel);
+ ItemPointerSetOffsetNumber(&tuple.t_self, offnum);
switch (HeapTupleSatisfiesVacuum(&tuple, vacrel->cutoffs.OldestXmin,
buf))
dbcommands_set_tuple_block_once.patchapplication/octet-stream; name=dbcommands_set_tuple_block_once.patchDownload
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 5fbbcdaabb..9ec07e52e0 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -337,6 +337,10 @@ ScanSourceDatabasePgClassPage(Page page, Buffer buf, Oid tbid, Oid dbid,
maxoff = PageGetMaxOffsetNumber(page);
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&tuple.t_self, blkno);
+ tuple.t_tableOid = RelationRelationId;
+
/* Loop over offsets. */
for (offnum = FirstOffsetNumber;
offnum <= maxoff;
@@ -352,12 +356,11 @@ ScanSourceDatabasePgClassPage(Page page, Buffer buf, Oid tbid, Oid dbid,
continue;
Assert(ItemIdIsNormal(itemid));
- ItemPointerSet(&(tuple.t_self), blkno, offnum);
/* Initialize a HeapTupleData structure. */
tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
tuple.t_len = ItemIdGetLength(itemid);
- tuple.t_tableOid = RelationRelationId;
+ ItemPointerSetOffsetNumber(&tuple.t_self, offnum);
/* Skip tuples that are not visible to this snapshot. */
if (HeapTupleSatisfiesVisibility(&tuple, snapshot, buf))
rebased heapam.c and heapam_handler.c
best regards,
Ranier Vilela
Attachments:
v1-heapam_set_tuple_block_once.patchapplication/octet-stream; name=v1-heapam_set_tuple_block_once.patchDownload
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index cedaa195cb..148a979699 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -508,13 +508,17 @@ page_collect_tuples(HeapScanDesc scan, Snapshot snapshot,
BlockNumber block, int lines,
bool all_visible, bool check_serializable)
{
+ HeapTupleData loctup;
int ntup = 0;
OffsetNumber lineoff;
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&loctup.t_self, block);
+ loctup.t_tableOid = RelationGetRelid(scan->rs_base.rs_rd);
+
for (lineoff = FirstOffsetNumber; lineoff <= lines; lineoff++)
{
ItemId lpp = PageGetItemId(page, lineoff);
- HeapTupleData loctup;
bool valid;
if (!ItemIdIsNormal(lpp))
@@ -522,8 +526,7 @@ page_collect_tuples(HeapScanDesc scan, Snapshot snapshot,
loctup.t_data = (HeapTupleHeader) PageGetItem(page, lpp);
loctup.t_len = ItemIdGetLength(lpp);
- loctup.t_tableOid = RelationGetRelid(scan->rs_base.rs_rd);
- ItemPointerSet(&(loctup.t_self), block, lineoff);
+ ItemPointerSetOffsetNumber(&loctup.t_self, lineoff);
if (all_visible)
valid = true;
@@ -931,6 +934,10 @@ heapgettup(HeapScanDesc scan,
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
page = heapgettup_start_page(scan, dir, &linesleft, &lineoff);
+
+ /* block is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&tuple->t_self, scan->rs_cblock);
+
continue_page:
/*
@@ -950,7 +957,7 @@ continue_page:
tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp);
tuple->t_len = ItemIdGetLength(lpp);
- ItemPointerSet(&(tuple->t_self), scan->rs_cblock, lineoff);
+ ItemPointerSetOffsetNumber(&tuple->t_self, lineoff);
visible = HeapTupleSatisfiesVisibility(tuple,
scan->rs_base.rs_snapshot,
@@ -1766,6 +1773,10 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
Assert(TransactionIdIsValid(RecentXmin));
Assert(BufferGetBlockNumber(buffer) == blkno);
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&heapTuple->t_self, blkno);
+ heapTuple->t_tableOid = RelationGetRelid(relation);
+
/* Scan through possible multiple members of HOT-chain */
for (;;)
{
@@ -1800,8 +1811,7 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
*/
heapTuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
heapTuple->t_len = ItemIdGetLength(lp);
- heapTuple->t_tableOid = RelationGetRelid(relation);
- ItemPointerSet(&heapTuple->t_self, blkno, offnum);
+ ItemPointerSetOffsetNumber(&heapTuple->t_self, offnum);
/*
* Shouldn't see a HEAP_ONLY tuple at chain start.
v1-heapam_handler_set_tuple_block_once.patchapplication/octet-stream; name=v1-heapam_handler_set_tuple_block_once.patchDownload
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index 24d3765aa2..5c42bce2de 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -1031,6 +1031,7 @@ heapam_scan_analyze_next_tuple(TableScanDesc scan, TransactionId OldestXmin,
TupleTableSlot *slot)
{
HeapScanDesc hscan = (HeapScanDesc) scan;
+ HeapTuple targtuple;
Page targpage;
OffsetNumber maxoffset;
BufferHeapTupleTableSlot *hslot;
@@ -1038,14 +1039,18 @@ heapam_scan_analyze_next_tuple(TableScanDesc scan, TransactionId OldestXmin,
Assert(TTS_IS_BUFFERTUPLE(slot));
hslot = (BufferHeapTupleTableSlot *) slot;
+ targtuple = &hslot->base.tupdata;
targpage = BufferGetPage(hscan->rs_cbuf);
maxoffset = PageGetMaxOffsetNumber(targpage);
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&targtuple->t_self, hscan->rs_cblock);
+ targtuple->t_tableOid = RelationGetRelid(scan->rs_rd);
+
/* Inner loop over all tuples on the selected page */
for (; hscan->rs_cindex <= maxoffset; hscan->rs_cindex++)
{
ItemId itemid;
- HeapTuple targtuple = &hslot->base.tupdata;
bool sample_it = false;
itemid = PageGetItemId(targpage, hscan->rs_cindex);
@@ -1063,11 +1068,9 @@ heapam_scan_analyze_next_tuple(TableScanDesc scan, TransactionId OldestXmin,
continue;
}
- ItemPointerSet(&targtuple->t_self, hscan->rs_cblock, hscan->rs_cindex);
-
- targtuple->t_tableOid = RelationGetRelid(scan->rs_rd);
targtuple->t_data = (HeapTupleHeader) PageGetItem(targpage, itemid);
targtuple->t_len = ItemIdGetLength(itemid);
+ ItemPointerSetOffsetNumber(&targtuple->t_self, hscan->rs_cindex);
switch (HeapTupleSatisfiesVacuum(targtuple, OldestXmin,
hscan->rs_cbuf))
@@ -2291,6 +2294,7 @@ heapam_scan_sample_next_tuple(TableScanDesc scan, SampleScanState *scanstate,
TupleTableSlot *slot)
{
HeapScanDesc hscan = (HeapScanDesc) scan;
+ HeapTuple tuple = &(hscan->rs_ctup);
TsmRoutine *tsm = scanstate->tsmroutine;
BlockNumber blockno = hscan->rs_cblock;
bool pagemode = (scan->rs_flags & SO_ALLOW_PAGEMODE) != 0;
@@ -2311,6 +2315,9 @@ heapam_scan_sample_next_tuple(TableScanDesc scan, SampleScanState *scanstate,
!scan->rs_snapshot->takenDuringRecovery;
maxoffset = PageGetMaxOffsetNumber(page);
+ /* block is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&tuple->t_self, blockno);
+
for (;;)
{
OffsetNumber tupoffset;
@@ -2326,7 +2333,6 @@ heapam_scan_sample_next_tuple(TableScanDesc scan, SampleScanState *scanstate,
{
ItemId itemid;
bool visible;
- HeapTuple tuple = &(hscan->rs_ctup);
/* Skip invalid tuple pointers. */
itemid = PageGetItemId(page, tupoffset);
@@ -2335,8 +2341,7 @@ heapam_scan_sample_next_tuple(TableScanDesc scan, SampleScanState *scanstate,
tuple->t_data = (HeapTupleHeader) PageGetItem(page, itemid);
tuple->t_len = ItemIdGetLength(itemid);
- ItemPointerSet(&(tuple->t_self), blockno, tupoffset);
-
+ ItemPointerSetOffsetNumber(&tuple->t_self, blockno);
if (all_visible)
visible = true;
@@ -2578,18 +2583,21 @@ BitmapHeapScanNextBlock(TableScanDesc scan,
* tbmres; but we have to follow any HOT chain starting at each such
* offset.
*/
+ ItemPointerData tid;
int curslot;
/* We must have extracted the tuple offsets by now */
Assert(noffsets > -1);
+ /* block is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&tid, block);
+
for (curslot = 0; curslot < noffsets; curslot++)
{
OffsetNumber offnum = offsets[curslot];
- ItemPointerData tid;
HeapTupleData heapTuple;
- ItemPointerSet(&tid, block, offnum);
+ ItemPointerSetOffsetNumber(&tid, offnum);
if (heap_hot_search_buffer(&tid, scan->rs_rd, buffer, snapshot,
&heapTuple, NULL, true))
hscan->rs_vistuples[ntup++] = ItemPointerGetOffsetNumber(&tid);
@@ -2604,11 +2612,15 @@ BitmapHeapScanNextBlock(TableScanDesc scan,
Page page = BufferGetPage(buffer);
OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
OffsetNumber offnum;
+ HeapTupleData loctup;
+
+ /* block and tableOid is the same for all tuples, set it once outside the loop */
+ ItemPointerSetBlockNumber(&loctup.t_self, block);
+ loctup.t_tableOid = scan->rs_rd->rd_id;
for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum))
{
ItemId lp;
- HeapTupleData loctup;
bool valid;
lp = PageGetItemId(page, offnum);
@@ -2616,8 +2628,8 @@ BitmapHeapScanNextBlock(TableScanDesc scan,
continue;
loctup.t_data = (HeapTupleHeader) PageGetItem(page, lp);
loctup.t_len = ItemIdGetLength(lp);
- loctup.t_tableOid = scan->rs_rd->rd_id;
- ItemPointerSet(&loctup.t_self, block, offnum);
+ ItemPointerSetOffsetNumber(&loctup.t_self, offnum);
+
valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);
if (valid)
{
On Thu, 3 Apr 2025 at 23:09, Ranier Vilela <ranier.vf@gmail.com> wrote:
rebased heapam.c and heapam_handler.c
This doesn't work. The tids are not being set in all cases.
patched:
select tableoid,ctid,oid from pg_class TABLESAMPLE BERNOULLI (100);
tableoid | ctid | oid
----------+---------+-------
1259 | (0,0) | 16409
1259 | (0,0) | 16403
1259 | (0,0) | 16412
1259 | (0,0) | 16407
1259 | (0,0) | 16415
1259 | (0,0) | 16418
1259 | (0,0) | 16434
...
master:
tableoid | ctid | oid
----------+---------+-------
1259 | (0,10) | 16409
1259 | (0,11) | 16403
1259 | (0,12) | 16412
1259 | (0,13) | 16407
1259 | (0,15) | 16415
1259 | (0,16) | 16418
1259 | (0,17) | 16434
...
David