Skip to content

Commit 35548cd

Browse files
committed
cluster: integrate Stage 8 RF and external fencing foundation
Publish the latest frozen product tree from local immutable commit 628ce60. This integrates the accumulated Stage 8 R4/RF chain through RF-ROOT S04-13. The unfinished S04-14 worktree changes and all private design/talk artifacts are excluded. Local source tree: 0147045
1 parent d0e32b7 commit 35548cd

285 files changed

Lines changed: 91987 additions & 9468 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/backend/access/heap/heapam.c

Lines changed: 4033 additions & 1151 deletions
Large diffs are not rendered by default.

src/backend/access/heap/heapam_handler.c

Lines changed: 156 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
#include "utils/builtins.h"
5252
#include "utils/rel.h"
5353

54+
#include "heapam_r4_private.h"
55+
5456
static void reform_and_rewrite_tuple(HeapTuple tuple,
5557
Relation OldHeap, Relation NewHeap,
5658
Datum *values, bool *isnull, RewriteState rwstate);
@@ -63,6 +65,114 @@ static BlockNumber heapam_scan_get_blocks_done(HeapScanDesc hscan);
6365

6466
static const TableAmRoutine heapam_methods;
6567

68+
static TableIndexFetchTupleResult heapam_store_hot_search_result(
69+
HeapHotSearchResult *result, TupleTableSlot *slot, Buffer buffer,
70+
bool *call_again, bool *all_dead) pg_attribute_unused();
71+
#ifdef USE_PGRAC_CLUSTER
72+
static TableIndexFetchTupleResult heapam_index_fetch_cluster_hot(
73+
ItemPointer tid, Relation relation, Buffer buffer, Snapshot snapshot,
74+
HeapHotSearchResult *result, TupleTableSlot *slot,
75+
bool *call_again, bool *all_dead) pg_attribute_unused();
76+
#endif
77+
78+
/*
79+
* Consume the backend-private HOT result without leaking its descriptor
80+
* lifetime into the executor slot. BUFFER_BACKED remains pin-owned by the
81+
* buffer slot; OWNED_SCRATCH is copied while the scratch page is alive.
82+
*/
83+
static TableIndexFetchTupleResult
84+
heapam_store_hot_search_result(HeapHotSearchResult *result,
85+
TupleTableSlot *slot, Buffer buffer,
86+
bool *call_again, bool *all_dead)
87+
{
88+
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
89+
90+
Assert(result != NULL);
91+
Assert(TTS_IS_BUFFERTUPLE(slot));
92+
Assert(call_again != NULL);
93+
94+
*call_again = false;
95+
96+
switch (result->kind)
97+
{
98+
case HEAP_HOT_SEARCH_NOT_FOUND:
99+
ExecClearTuple(slot);
100+
return TABLE_INDEX_FETCH_NOT_FOUND;
101+
102+
case HEAP_HOT_SEARCH_BUFFER_BACKED:
103+
Assert(BufferIsValid(buffer));
104+
bslot->base.tupdata = result->tuple;
105+
ExecStoreBufferHeapTuple(&bslot->base.tupdata, slot, buffer);
106+
break;
107+
108+
case HEAP_HOT_SEARCH_OWNED_SCRATCH:
109+
ExecForceStoreHeapTuple(&result->tuple, slot, false);
110+
slot->tts_tid = result->tuple.t_self;
111+
slot->tts_tableOid = result->tuple.t_tableOid;
112+
break;
113+
114+
default:
115+
Assert(false);
116+
ExecClearTuple(slot);
117+
return TABLE_INDEX_FETCH_NOT_FOUND;
118+
}
119+
120+
if (all_dead != NULL)
121+
*all_dead = false;
122+
123+
return TABLE_INDEX_FETCH_FOUND;
124+
}
125+
126+
#ifdef USE_PGRAC_CLUSTER
127+
/*
128+
* Dormant post-SHARE-lock cluster-MVCC branch. The focused Unit37 receipt
129+
* enters this exact helper so it cannot replace the companion/FULL/scratch
130+
* walk with a test-only choreography. Live wiring waits for D13 to publish
131+
* an episode-safe TARGET admission state.
132+
*/
133+
static TableIndexFetchTupleResult
134+
heapam_index_fetch_cluster_hot(ItemPointer tid, Relation relation,
135+
Buffer buffer, Snapshot snapshot,
136+
HeapHotSearchResult *result,
137+
TupleTableSlot *slot,
138+
bool *call_again, bool *all_dead)
139+
{
140+
Assert(result != NULL);
141+
142+
memset(result, 0, sizeof(*result));
143+
result->kind = heap_hot_search_buffer_result(tid, relation, buffer,
144+
snapshot, result, all_dead,
145+
!*call_again);
146+
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
147+
return heapam_store_hot_search_result(result, slot, buffer,
148+
call_again, all_dead);
149+
}
150+
#endif
151+
152+
#ifdef USE_CLUSTER_UNIT
153+
TableIndexFetchTupleResult
154+
cluster_heap_test_r4_store_hot_result(HeapHotSearchResult *result,
155+
TupleTableSlot *slot, Buffer buffer,
156+
bool *call_again, bool *all_dead)
157+
{
158+
return heapam_store_hot_search_result(result, slot, buffer,
159+
call_again, all_dead);
160+
}
161+
162+
#ifdef USE_PGRAC_CLUSTER
163+
TableIndexFetchTupleResult
164+
cluster_heap_test_r4_index_hot_result(ItemPointer tid, Relation relation,
165+
Buffer buffer, Snapshot snapshot,
166+
HeapHotSearchResult *result,
167+
TupleTableSlot *slot,
168+
bool *call_again, bool *all_dead)
169+
{
170+
return heapam_index_fetch_cluster_hot(tid, relation, buffer, snapshot,
171+
result, slot, call_again, all_dead);
172+
}
173+
#endif
174+
#endif
175+
66176

67177
/* ------------------------------------------------------------------------
68178
* Slot related callbacks for heap AM
@@ -128,7 +238,7 @@ heapam_index_fetch_tuple_internal(struct IndexFetchTableData *scan,
128238
bool barrier_aware)
129239
{
130240
IndexFetchHeapData *hscan = (IndexFetchHeapData *) scan;
131-
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
241+
HeapHotSearchResult hot_result;
132242
bool got_heap_tuple;
133243

134244
Assert(TTS_IS_BUFFERTUPLE(slot));
@@ -164,32 +274,21 @@ heapam_index_fetch_tuple_internal(struct IndexFetchTableData *scan,
164274
}
165275
else
166276
LockBuffer(hscan->xs_cbuf, BUFFER_LOCK_SHARE);
167-
got_heap_tuple = heap_hot_search_buffer(tid,
168-
hscan->xs_base.rel,
169-
hscan->xs_cbuf,
170-
snapshot,
171-
&bslot->base.tupdata,
172-
all_dead,
173-
!*call_again);
174-
bslot->base.tupdata.t_self = *tid;
277+
memset(&hot_result, 0, sizeof(hot_result));
278+
hot_result.kind = heap_hot_search_buffer_result(tid,
279+
hscan->xs_base.rel,
280+
hscan->xs_cbuf,
281+
snapshot,
282+
&hot_result,
283+
all_dead,
284+
!*call_again);
175285
LockBuffer(hscan->xs_cbuf, BUFFER_LOCK_UNLOCK);
176-
177-
if (got_heap_tuple)
178-
{
179-
/*
180-
* Only in a non-MVCC snapshot can more than one member of the HOT
181-
* chain be visible.
182-
*/
183-
*call_again = !IsMVCCSnapshot(snapshot);
184-
185-
slot->tts_tableOid = RelationGetRelid(scan->rel);
186-
ExecStoreBufferHeapTuple(&bslot->base.tupdata, slot, hscan->xs_cbuf);
187-
}
188-
else
189-
{
190-
/* We've reached the end of the HOT chain. */
191-
*call_again = false;
192-
}
286+
got_heap_tuple = heapam_store_hot_search_result(&hot_result, slot,
287+
hscan->xs_cbuf, call_again, all_dead)
288+
== TABLE_INDEX_FETCH_FOUND;
289+
if (got_heap_tuple && !IsMVCCSnapshot(snapshot)
290+
&& hot_result.kind == HEAP_HOT_SEARCH_BUFFER_BACKED)
291+
*call_again = true;
193292

194293
return got_heap_tuple ? TABLE_INDEX_FETCH_FOUND : TABLE_INDEX_FETCH_NOT_FOUND;
195294
}
@@ -413,16 +512,29 @@ heapam_tuple_lock(Relation relation, ItemPointer tid, Snapshot snapshot,
413512
Buffer buffer;
414513
HeapTuple tuple = &bslot->base.tupdata;
415514
bool follow_updates;
515+
#ifdef USE_PGRAC_CLUSTER
516+
ClusterHeapSuccessorProof expected_successor;
517+
ClusterHeapSuccessorProof next_successor;
518+
#endif
416519

417520
follow_updates = (flags & TUPLE_LOCK_FLAG_LOCK_UPDATE_IN_PROGRESS) != 0;
418521
tmfd->traversed = false;
522+
#ifdef USE_PGRAC_CLUSTER
523+
memset(&expected_successor, 0, sizeof(expected_successor));
524+
memset(&next_successor, 0, sizeof(next_successor));
525+
#endif
419526

420527
Assert(TTS_IS_BUFFERTUPLE(slot));
421528

422529
tuple_lock_retry:
423530
tuple->t_self = *tid;
424531
result = heap_lock_tuple(relation, tuple, cid, mode, wait_policy,
425-
follow_updates, &buffer, tmfd);
532+
follow_updates, &buffer, tmfd
533+
#ifdef USE_PGRAC_CLUSTER
534+
, expected_successor.valid ? &expected_successor : NULL
535+
, &next_successor
536+
#endif
537+
);
426538

427539
if (result == TM_Updated &&
428540
(flags & TUPLE_LOCK_FLAG_FIND_LAST_VERSION))
@@ -437,6 +549,23 @@ heapam_tuple_lock(Relation relation, ItemPointer tid, Snapshot snapshot,
437549
SnapshotData SnapshotDirty;
438550
TransactionId priorXmax;
439551

552+
#ifdef USE_PGRAC_CLUSTER
553+
/*
554+
* A current-MultiXact authority result carries the exact
555+
* successor ITL/TT proof. Re-enter heap_lock_tuple directly and
556+
* consume that proof under the destination PCM-X; never reduce it
557+
* to tmfd.xmax/raw xmin across this unlocked handoff.
558+
*/
559+
if (next_successor.valid)
560+
{
561+
expected_successor = next_successor;
562+
*tid = next_successor.tid;
563+
tmfd->traversed = true;
564+
goto tuple_lock_retry;
565+
}
566+
memset(&expected_successor, 0, sizeof(expected_successor));
567+
#endif
568+
440569
/* it was updated, so look at the updated version */
441570
*tid = tmfd->ctid;
442571
/* updated row should have xmin matching this xmax */
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*-------------------------------------------------------------------------
2+
*
3+
* heapam_r4_private.h
4+
* Backend-private R4 heap HOT search result and test seams.
5+
*
6+
* This contract is shared only by heapam.c, heapam_visibility.c and
7+
* heapam_handler.c. It does not change the public heap or TableAM API.
8+
*
9+
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
10+
* Portions Copyright (c) 1994, Regents of the University of California
11+
* Portions Copyright (c) 2026, pgrac contributors
12+
*
13+
* IDENTIFICATION
14+
* src/backend/access/heap/heapam_r4_private.h
15+
*
16+
*-------------------------------------------------------------------------
17+
*/
18+
#ifndef HEAPAM_R4_PRIVATE_H
19+
#define HEAPAM_R4_PRIVATE_H
20+
21+
#include "access/htup.h"
22+
#include "access/tableam.h"
23+
#include "cluster/cluster_scn.h"
24+
#include "executor/tuptable.h"
25+
#include "storage/buf_internals.h"
26+
#include "storage/bufpage.h"
27+
#include "utils/snapshot.h"
28+
29+
typedef enum HeapHotSearchResultKind
30+
{
31+
HEAP_HOT_SEARCH_NOT_FOUND = 0,
32+
HEAP_HOT_SEARCH_BUFFER_BACKED,
33+
HEAP_HOT_SEARCH_OWNED_SCRATCH
34+
} HeapHotSearchResultKind;
35+
36+
typedef struct HeapHotSearchResult
37+
{
38+
HeapHotSearchResultKind kind;
39+
HeapTupleData tuple;
40+
char scratch_page[BLCKSZ] pg_attribute_aligned(MAXIMUM_ALIGNOF);
41+
} HeapHotSearchResult;
42+
43+
typedef struct ClusterR4HotScratchTestContext
44+
{
45+
Page scratch_page;
46+
BufferTag tag;
47+
ItemPointerData logical_root;
48+
SCN read_scn;
49+
bool already_full;
50+
bool allow_hint;
51+
bool allow_cleanout;
52+
} ClusterR4HotScratchTestContext;
53+
54+
typedef void (*ClusterR4HotLockTestHook)(void *arg, bool acquire);
55+
typedef bool (*ClusterR4HotFetchFullTestHook)(void *arg,
56+
const BufferTag *tag,
57+
SCN read_scn,
58+
char dst_page[BLCKSZ]);
59+
typedef bool (*ClusterR4HotScratchSearchTestHook)(
60+
void *arg, const ClusterR4HotScratchTestContext *context,
61+
HeapTuple scratch_tuple);
62+
63+
/* PK IndexScan companion; public heap_hot_search_buffer() remains unchanged. */
64+
extern HeapHotSearchResultKind heap_hot_search_buffer_result(
65+
ItemPointer tid, Relation relation, Buffer buffer, Snapshot snapshot,
66+
HeapHotSearchResult *result, bool *all_dead, bool first_call);
67+
68+
extern bool HeapTupleSatisfiesMVCCScratch(
69+
HeapTuple tuple, Snapshot snapshot,
70+
const ClusterR4HotScratchTestContext *context);
71+
72+
#ifdef USE_CLUSTER_UNIT
73+
extern HeapHotSearchResultKind cluster_heap_test_r4_hot_full_cycle(
74+
BufferTag tag, ItemPointerData logical_root, SCN read_scn,
75+
HeapHotSearchResult *result, ClusterR4HotLockTestHook lock_hook,
76+
ClusterR4HotFetchFullTestHook fetch_full_hook,
77+
ClusterR4HotScratchSearchTestHook scratch_search_hook, void *hook_arg,
78+
bool *call_again, bool *all_dead);
79+
extern TableIndexFetchTupleResult cluster_heap_test_r4_store_hot_result(
80+
HeapHotSearchResult *result, TupleTableSlot *slot, Buffer buffer,
81+
bool *call_again, bool *all_dead);
82+
#ifdef USE_PGRAC_CLUSTER
83+
extern TableIndexFetchTupleResult cluster_heap_test_r4_index_hot_result(
84+
ItemPointer tid, Relation relation, Buffer buffer, Snapshot snapshot,
85+
HeapHotSearchResult *result, TupleTableSlot *slot,
86+
bool *call_again, bool *all_dead);
87+
#endif
88+
#endif
89+
90+
#endif /* HEAPAM_R4_PRIVATE_H */

0 commit comments

Comments
 (0)