Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e590211

Browse filesBrowse files
Handle new HOT chains in index-build table scans
When a table is scanned by heapam_index_build_range_scan (née IndexBuildHeapScan) and the table lock being held allows concurrent data changes, it is possible for new HOT chains to sprout in a page that were unknown when the scan of a page happened. This leads to an error such as ERROR: failed to find parent tuple for heap-only tuple at (X,Y) in table "tbl" because the root tuple was not present when we first obtained the list of the page's root tuples. This can be fixed by re-obtaining the list of root tuples, if we see that a heap-only tuple appears to point to a non-existing root. This was reported by Anastasia as occurring for BRIN summarization (which exists since 9.5), but I think it could theoretically also happen with CREATE INDEX CONCURRENTLY (much older) or REINDEX CONCURRENTLY (very recent). It seems a happy coincidence that BRIN forces us to backpatch this all the way to 9.5. Reported-by: Anastasia Lubennikova <a.lubennikova@postgrespro.ru> Diagnosed-by: Anastasia Lubennikova <a.lubennikova@postgrespro.ru> Co-authored-by: Anastasia Lubennikova <a.lubennikova@postgrespro.ru> Co-authored-by: Álvaro Herrera <alvherre@alvh.no-ip.org> Discussion: https://postgr.es/m/602d8487-f0b2-5486-0088-0f372b2549fa@postgrespro.ru Backpatch: 9.5 - master
1 parent 7a3c261 commit e590211
Copy full SHA for e590211

File tree

Expand file treeCollapse file tree

2 files changed

+23
-2
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+23
-2
lines changed

‎src/backend/access/heap/pruneheap.c

Copy file name to clipboardExpand all lines: src/backend/access/heap/pruneheap.c
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ heap_page_prune_execute(Buffer buffer,
731731
* root_offsets[k - 1] = j.
732732
*
733733
* The passed-in root_offsets array must have MaxHeapTuplesPerPage entries.
734-
* We zero out all unused entries.
734+
* Unused entries are filled with InvalidOffsetNumber (zero).
735735
*
736736
* The function must be called with at least share lock on the buffer, to
737737
* prevent concurrent prune operations.
@@ -746,7 +746,8 @@ heap_get_root_tuples(Page page, OffsetNumber *root_offsets)
746746
OffsetNumber offnum,
747747
maxoff;
748748

749-
MemSet(root_offsets, 0, MaxHeapTuplesPerPage * sizeof(OffsetNumber));
749+
MemSet(root_offsets, InvalidOffsetNumber,
750+
MaxHeapTuplesPerPage * sizeof(OffsetNumber));
750751

751752
maxoff = PageGetMaxOffsetNumber(page);
752753
for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum))

‎src/backend/catalog/index.c

Copy file name to clipboardExpand all lines: src/backend/catalog/index.c
+20Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,6 +2389,12 @@ IndexBuildHeapRangeScan(Relation heapRelation,
23892389
* buffer continuously while visiting the page, so no pruning
23902390
* operation can occur either.
23912391
*
2392+
* In cases with only ShareUpdateExclusiveLock on the table, it's
2393+
* possible for some HOT tuples to appear that we didn't know about
2394+
* when we first read the page. To handle that case, we re-obtain the
2395+
* list of root offsets when a HOT tuple points to a root item that we
2396+
* don't know about.
2397+
*
23922398
* Also, although our opinions about tuple liveness could change while
23932399
* we scan the page (due to concurrent transaction commits/aborts),
23942400
* the chain root locations won't, so this info doesn't need to be
@@ -2659,6 +2665,20 @@ IndexBuildHeapRangeScan(Relation heapRelation,
26592665
rootTuple = *heapTuple;
26602666
offnum = ItemPointerGetOffsetNumber(&heapTuple->t_self);
26612667

2668+
/*
2669+
* If a HOT tuple points to a root that we don't know
2670+
* about, obtain root items afresh. If that still fails,
2671+
* report it as corruption.
2672+
*/
2673+
if (root_offsets[offnum - 1] == InvalidOffsetNumber)
2674+
{
2675+
Page page = BufferGetPage(scan->rs_cbuf);
2676+
2677+
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
2678+
heap_get_root_tuples(page, root_offsets);
2679+
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
2680+
}
2681+
26622682
if (!OffsetNumberIsValid(root_offsets[offnum - 1]))
26632683
ereport(ERROR,
26642684
(errcode(ERRCODE_DATA_CORRUPTED),

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.