From 94f29c626633fa05050b702b00ff31c04de55de1 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 3 Jun 2020 11:01:48 +0900 Subject: [PATCH 2/2] Move heap_get_latest_tid() within the heap AM handler This routine is not getting called in any code path except through the table AM interface, so let's make the cut clear. --- src/include/access/heapam.h | 2 - src/backend/access/heap/heapam.c | 117 ----------------------- src/backend/access/heap/heapam_handler.c | 117 +++++++++++++++++++++++ 3 files changed, 117 insertions(+), 119 deletions(-) diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index 4a5b14f10e..273b8be02e 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -128,8 +128,6 @@ extern bool heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer, Snapshot snapshot, HeapTuple heapTuple, bool *all_dead, bool first_call); -extern void heap_get_latest_tid(TableScanDesc scan, ItemPointer tid); - extern BulkInsertState GetBulkInsertState(void); extern void FreeBulkInsertState(BulkInsertState); extern void ReleaseBulkInsertStatePin(BulkInsertState bistate); diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 94eb37d48d..e177065e20 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -1618,123 +1618,6 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer, return false; } -/* - * heap_get_latest_tid - get the latest tid of a specified tuple - * - * Actually, this gets the latest version that is visible according to the - * scan's snapshot. Create a scan using SnapshotDirty to get the very latest, - * possibly uncommitted version. - * - * *tid is both an input and an output parameter: it is updated to - * show the latest version of the row. Note that it will not be changed - * if no version of the row passes the snapshot test. - */ -void -heap_get_latest_tid(TableScanDesc sscan, - ItemPointer tid) -{ - Relation relation = sscan->rs_rd; - Snapshot snapshot = sscan->rs_snapshot; - ItemPointerData ctid; - TransactionId priorXmax; - - /* - * table_get_latest_tid verified that the passed in tid is valid. Assume - * that t_ctid links are valid however - there shouldn't be invalid ones - * in the table. - */ - Assert(ItemPointerIsValid(tid)); - - /* - * Loop to chase down t_ctid links. At top of loop, ctid is the tuple we - * need to examine, and *tid is the TID we will return if ctid turns out - * to be bogus. - * - * Note that we will loop until we reach the end of the t_ctid chain. - * Depending on the snapshot passed, there might be at most one visible - * version of the row, but we don't try to optimize for that. - */ - ctid = *tid; - priorXmax = InvalidTransactionId; /* cannot check first XMIN */ - for (;;) - { - Buffer buffer; - Page page; - OffsetNumber offnum; - ItemId lp; - HeapTupleData tp; - bool valid; - - /* - * Read, pin, and lock the page. - */ - buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&ctid)); - LockBuffer(buffer, BUFFER_LOCK_SHARE); - page = BufferGetPage(buffer); - TestForOldSnapshot(snapshot, relation, page); - - /* - * Check for bogus item number. This is not treated as an error - * condition because it can happen while following a t_ctid link. We - * just assume that the prior tid is OK and return it unchanged. - */ - offnum = ItemPointerGetOffsetNumber(&ctid); - if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(page)) - { - UnlockReleaseBuffer(buffer); - break; - } - lp = PageGetItemId(page, offnum); - if (!ItemIdIsNormal(lp)) - { - UnlockReleaseBuffer(buffer); - break; - } - - /* OK to access the tuple */ - tp.t_self = ctid; - tp.t_data = (HeapTupleHeader) PageGetItem(page, lp); - tp.t_len = ItemIdGetLength(lp); - tp.t_tableOid = RelationGetRelid(relation); - - /* - * After following a t_ctid link, we might arrive at an unrelated - * tuple. Check for XMIN match. - */ - if (TransactionIdIsValid(priorXmax) && - !TransactionIdEquals(priorXmax, HeapTupleHeaderGetXmin(tp.t_data))) - { - UnlockReleaseBuffer(buffer); - break; - } - - /* - * Check tuple visibility; if visible, set it as the new result - * candidate. - */ - valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer); - HeapCheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot); - if (valid) - *tid = ctid; - - /* - * If there's a valid t_ctid link, follow it, else we're done. - */ - if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) || - HeapTupleHeaderIsOnlyLocked(tp.t_data) || - HeapTupleHeaderIndicatesMovedPartitions(tp.t_data) || - ItemPointerEquals(&tp.t_self, &tp.t_data->t_ctid)) - { - UnlockReleaseBuffer(buffer); - break; - } - - ctid = tp.t_data->t_ctid; - priorXmax = HeapTupleHeaderGetUpdateXid(tp.t_data); - UnlockReleaseBuffer(buffer); - } /* end of loop */ -} - /* * UpdateXmaxHintBits - update tuple hint bits after xmax transaction ends diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index 56b35622f1..84d32bc4ff 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -199,6 +199,123 @@ heapam_fetch_row_version(Relation relation, return false; } +/* + * heap_get_latest_tid - get the latest tid of a specified tuple + * + * Actually, this gets the latest version that is visible according to the + * scan's snapshot. Create a scan using SnapshotDirty to get the very latest, + * possibly uncommitted version. + * + * *tid is both an input and an output parameter: it is updated to + * show the latest version of the row. Note that it will not be changed + * if no version of the row passes the snapshot test. + */ +static void +heap_get_latest_tid(TableScanDesc sscan, + ItemPointer tid) +{ + Relation relation = sscan->rs_rd; + Snapshot snapshot = sscan->rs_snapshot; + ItemPointerData ctid; + TransactionId priorXmax; + + /* + * table_get_latest_tid verified that the passed in tid is valid. Assume + * that t_ctid links are valid however - there shouldn't be invalid ones + * in the table. + */ + Assert(ItemPointerIsValid(tid)); + + /* + * Loop to chase down t_ctid links. At top of loop, ctid is the tuple we + * need to examine, and *tid is the TID we will return if ctid turns out + * to be bogus. + * + * Note that we will loop until we reach the end of the t_ctid chain. + * Depending on the snapshot passed, there might be at most one visible + * version of the row, but we don't try to optimize for that. + */ + ctid = *tid; + priorXmax = InvalidTransactionId; /* cannot check first XMIN */ + for (;;) + { + Buffer buffer; + Page page; + OffsetNumber offnum; + ItemId lp; + HeapTupleData tp; + bool valid; + + /* + * Read, pin, and lock the page. + */ + buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&ctid)); + LockBuffer(buffer, BUFFER_LOCK_SHARE); + page = BufferGetPage(buffer); + TestForOldSnapshot(snapshot, relation, page); + + /* + * Check for bogus item number. This is not treated as an error + * condition because it can happen while following a t_ctid link. We + * just assume that the prior tid is OK and return it unchanged. + */ + offnum = ItemPointerGetOffsetNumber(&ctid); + if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(page)) + { + UnlockReleaseBuffer(buffer); + break; + } + lp = PageGetItemId(page, offnum); + if (!ItemIdIsNormal(lp)) + { + UnlockReleaseBuffer(buffer); + break; + } + + /* OK to access the tuple */ + tp.t_self = ctid; + tp.t_data = (HeapTupleHeader) PageGetItem(page, lp); + tp.t_len = ItemIdGetLength(lp); + tp.t_tableOid = RelationGetRelid(relation); + + /* + * After following a t_ctid link, we might arrive at an unrelated + * tuple. Check for XMIN match. + */ + if (TransactionIdIsValid(priorXmax) && + !TransactionIdEquals(priorXmax, HeapTupleHeaderGetXmin(tp.t_data))) + { + UnlockReleaseBuffer(buffer); + break; + } + + /* + * Check tuple visibility; if visible, set it as the new result + * candidate. + */ + valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer); + HeapCheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot); + if (valid) + *tid = ctid; + + /* + * If there's a valid t_ctid link, follow it, else we're done. + */ + if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) || + HeapTupleHeaderIsOnlyLocked(tp.t_data) || + HeapTupleHeaderIndicatesMovedPartitions(tp.t_data) || + ItemPointerEquals(&tp.t_self, &tp.t_data->t_ctid)) + { + UnlockReleaseBuffer(buffer); + break; + } + + ctid = tp.t_data->t_ctid; + priorXmax = HeapTupleHeaderGetUpdateXid(tp.t_data); + UnlockReleaseBuffer(buffer); + } /* end of loop */ +} + static bool heapam_tuple_tid_valid(TableScanDesc scan, ItemPointer tid) { -- 2.27.0.rc0