Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commit3e2f3c2

Browse files
committed
Prevent "snapshot too old" from trying to return pruned TOAST tuples.
Previously, we tested for MVCC snapshots to see whether they were tooold, but not TOAST snapshots, which can lead to complaints about missingTOAST chunks if those chunks are subject to early pruning. Ideally,the threshold lsn and timestamp for a TOAST snapshot would be that ofthe corresponding MVCC snapshot, but since we have no way of decidingwhich MVCC snapshot was used to fetch the TOAST pointer, use the oldestactive or registered snapshot instead.Reported by Andres Freund, who also sketched out what the fix shouldlook like. Patch by me, reviewed by Amit Kapila.
1 parenta3c7a99 commit3e2f3c2

File tree

6 files changed

+96
-16
lines changed

6 files changed

+96
-16
lines changed

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

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include"utils/expandeddatum.h"
4141
#include"utils/fmgroids.h"
4242
#include"utils/rel.h"
43+
#include"utils/snapmgr.h"
4344
#include"utils/typcache.h"
4445
#include"utils/tqual.h"
4546

@@ -81,6 +82,7 @@ static int toast_open_indexes(Relation toastrel,
8182
int*num_indexes);
8283
staticvoidtoast_close_indexes(Relation*toastidxs,intnum_indexes,
8384
LOCKMODElock);
85+
staticvoidinit_toast_snapshot(Snapshottoast_snapshot);
8486

8587

8688
/* ----------
@@ -1665,6 +1667,7 @@ toast_delete_datum(Relation rel, Datum value)
16651667
HeapTupletoasttup;
16661668
intnum_indexes;
16671669
intvalidIndex;
1670+
SnapshotDataSnapshotToast;
16681671

16691672
if (!VARATT_IS_EXTERNAL_ONDISK(attr))
16701673
return;
@@ -1696,8 +1699,9 @@ toast_delete_datum(Relation rel, Datum value)
16961699
* sequence or not, but since we've already locked the index we might as
16971700
* well use systable_beginscan_ordered.)
16981701
*/
1702+
init_toast_snapshot(&SnapshotToast);
16991703
toastscan=systable_beginscan_ordered(toastrel,toastidxs[validIndex],
1700-
SnapshotToast,1,&toastkey);
1704+
&SnapshotToast,1,&toastkey);
17011705
while ((toasttup=systable_getnext_ordered(toastscan,ForwardScanDirection))!=NULL)
17021706
{
17031707
/*
@@ -1730,6 +1734,7 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid)
17301734
intnum_indexes;
17311735
intvalidIndex;
17321736
Relation*toastidxs;
1737+
SnapshotDataSnapshotToast;
17331738

17341739
/* Fetch a valid index relation */
17351740
validIndex=toast_open_indexes(toastrel,
@@ -1748,9 +1753,10 @@ toastrel_valueid_exists(Relation toastrel, Oid valueid)
17481753
/*
17491754
* Is there any such chunk?
17501755
*/
1756+
init_toast_snapshot(&SnapshotToast);
17511757
toastscan=systable_beginscan(toastrel,
17521758
RelationGetRelid(toastidxs[validIndex]),
1753-
true,SnapshotToast,1,&toastkey);
1759+
true,&SnapshotToast,1,&toastkey);
17541760

17551761
if (systable_getnext(toastscan)!=NULL)
17561762
result= true;
@@ -1813,6 +1819,7 @@ toast_fetch_datum(struct varlena * attr)
18131819
int32chunksize;
18141820
intnum_indexes;
18151821
intvalidIndex;
1822+
SnapshotDataSnapshotToast;
18161823

18171824
if (!VARATT_IS_EXTERNAL_ONDISK(attr))
18181825
elog(ERROR,"toast_fetch_datum shouldn't be called for non-ondisk datums");
@@ -1859,8 +1866,9 @@ toast_fetch_datum(struct varlena * attr)
18591866
*/
18601867
nextidx=0;
18611868

1869+
init_toast_snapshot(&SnapshotToast);
18621870
toastscan=systable_beginscan_ordered(toastrel,toastidxs[validIndex],
1863-
SnapshotToast,1,&toastkey);
1871+
&SnapshotToast,1,&toastkey);
18641872
while ((ttup=systable_getnext_ordered(toastscan,ForwardScanDirection))!=NULL)
18651873
{
18661874
/*
@@ -1990,6 +1998,7 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
19901998
int32chcpyend;
19911999
intnum_indexes;
19922000
intvalidIndex;
2001+
SnapshotDataSnapshotToast;
19932002

19942003
if (!VARATT_IS_EXTERNAL_ONDISK(attr))
19952004
elog(ERROR,"toast_fetch_datum_slice shouldn't be called for non-ondisk datums");
@@ -2082,9 +2091,10 @@ toast_fetch_datum_slice(struct varlena * attr, int32 sliceoffset, int32 length)
20822091
*
20832092
* The index is on (valueid, chunkidx) so they will come in order
20842093
*/
2094+
init_toast_snapshot(&SnapshotToast);
20852095
nextidx=startchunk;
20862096
toastscan=systable_beginscan_ordered(toastrel,toastidxs[validIndex],
2087-
SnapshotToast,nscankeys,toastkey);
2097+
&SnapshotToast,nscankeys,toastkey);
20882098
while ((ttup=systable_getnext_ordered(toastscan,ForwardScanDirection))!=NULL)
20892099
{
20902100
/*
@@ -2289,3 +2299,22 @@ toast_close_indexes(Relation *toastidxs, int num_indexes, LOCKMODE lock)
22892299
index_close(toastidxs[i],lock);
22902300
pfree(toastidxs);
22912301
}
2302+
2303+
/* ----------
2304+
* init_toast_snapshot
2305+
*
2306+
*Initialize an appropriate TOAST snapshot. We must use an MVCC snapshot
2307+
*to initialize the TOAST snapshot; since we don't know which one to use,
2308+
*just use the oldest one. This is safe: at worst, we will get a "snapshot
2309+
*too old" error that might have been avoided otherwise.
2310+
*/
2311+
staticvoid
2312+
init_toast_snapshot(Snapshottoast_snapshot)
2313+
{
2314+
Snapshotsnapshot=GetOldestSnapshot();
2315+
2316+
if (snapshot==NULL)
2317+
elog(ERROR,"no known snapshots");
2318+
2319+
InitToastSnapshot(toast_snapshot,snapshot->lsn,snapshot->whenTaken);
2320+
}

‎src/backend/utils/time/snapmgr.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ typedef struct ActiveSnapshotElt
188188
/* Top of the stack of active snapshots */
189189
staticActiveSnapshotElt*ActiveSnapshot=NULL;
190190

191+
/* Bottom of the stack of active snapshots */
192+
staticActiveSnapshotElt*OldestActiveSnapshot=NULL;
193+
191194
/*
192195
* Currently registered Snapshots. Ordered in a heap by xmin, so that we can
193196
* quickly find the one with lowest xmin, to advance our MyPgXat->xmin.
@@ -393,6 +396,34 @@ GetLatestSnapshot(void)
393396
returnSecondarySnapshot;
394397
}
395398

399+
/*
400+
* GetOldestSnapshot
401+
*
402+
*Get the oldest known snapshot, as judged by the LSN.
403+
*/
404+
Snapshot
405+
GetOldestSnapshot(void)
406+
{
407+
SnapshotOldestRegisteredSnapshot=NULL;
408+
XLogRecPtrRegisteredLSN=InvalidXLogRecPtr;
409+
XLogRecPtrActiveLSN=InvalidXLogRecPtr;
410+
411+
if (!pairingheap_is_empty(&RegisteredSnapshots))
412+
{
413+
OldestRegisteredSnapshot=pairingheap_container(SnapshotData,ph_node,
414+
pairingheap_first(&RegisteredSnapshots));
415+
RegisteredLSN=OldestRegisteredSnapshot->lsn;
416+
}
417+
418+
if (OldestActiveSnapshot!=NULL)
419+
ActiveLSN=OldestActiveSnapshot->as_snap->lsn;
420+
421+
if (XLogRecPtrIsInvalid(RegisteredLSN)||RegisteredLSN>ActiveLSN)
422+
returnOldestActiveSnapshot->as_snap;
423+
424+
returnOldestRegisteredSnapshot;
425+
}
426+
396427
/*
397428
* GetCatalogSnapshot
398429
*Get a snapshot that is sufficiently up-to-date for scan of the
@@ -674,6 +705,8 @@ PushActiveSnapshot(Snapshot snap)
674705
newactive->as_snap->active_count++;
675706

676707
ActiveSnapshot=newactive;
708+
if (OldestActiveSnapshot==NULL)
709+
OldestActiveSnapshot=ActiveSnapshot;
677710
}
678711

679712
/*
@@ -744,6 +777,8 @@ PopActiveSnapshot(void)
744777

745778
pfree(ActiveSnapshot);
746779
ActiveSnapshot=newstack;
780+
if (ActiveSnapshot==NULL)
781+
OldestActiveSnapshot=NULL;
747782

748783
SnapshotResetXmin();
749784
}
@@ -953,6 +988,8 @@ AtSubAbort_Snapshot(int level)
953988
pfree(ActiveSnapshot);
954989

955990
ActiveSnapshot=next;
991+
if (ActiveSnapshot==NULL)
992+
OldestActiveSnapshot=NULL;
956993
}
957994

958995
SnapshotResetXmin();
@@ -1037,6 +1074,7 @@ AtEOXact_Snapshot(bool isCommit)
10371074
* it'll go away with TopTransactionContext.
10381075
*/
10391076
ActiveSnapshot=NULL;
1077+
OldestActiveSnapshot=NULL;
10401078
pairingheap_reset(&RegisteredSnapshots);
10411079

10421080
CurrentSnapshot=NULL;

‎src/backend/utils/time/tqual.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@
7878
/* Static variables representing various special snapshot semantics */
7979
SnapshotDataSnapshotSelfData= {HeapTupleSatisfiesSelf};
8080
SnapshotDataSnapshotAnyData= {HeapTupleSatisfiesAny};
81-
SnapshotDataSnapshotToastData= {HeapTupleSatisfiesToast};
8281

8382
/* local functions */
8483
staticboolXidInMVCCSnapshot(TransactionIdxid,Snapshotsnapshot);

‎src/include/storage/bufmgr.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,8 @@ TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
279279

280280
if (old_snapshot_threshold >=0
281281
&& (snapshot)!=NULL
282-
&& (snapshot)->satisfies==HeapTupleSatisfiesMVCC
282+
&& ((snapshot)->satisfies==HeapTupleSatisfiesMVCC
283+
|| (snapshot)->satisfies==HeapTupleSatisfiesToast)
283284
&& !XLogRecPtrIsInvalid((snapshot)->lsn)
284285
&&PageGetLSN(page)> (snapshot)->lsn)
285286
TestForOldSnapshot_impl(snapshot,relation);

‎src/include/utils/snapmgr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ extern TransactionId RecentGlobalDataXmin;
6464
externSnapshotGetTransactionSnapshot(void);
6565
externSnapshotGetLatestSnapshot(void);
6666
externvoidSnapshotSetCommandId(CommandIdcurcid);
67+
externSnapshotGetOldestSnapshot(void);
6768

6869
externSnapshotGetCatalogSnapshot(Oidrelid);
6970
externSnapshotGetNonHistoricCatalogSnapshot(Oidrelid);

‎src/include/utils/tqual.h

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,16 @@
1616
#defineTQUAL_H
1717

1818
#include"utils/snapshot.h"
19+
#include"access/xlogdefs.h"
1920

2021

2122
/* Static variables representing various special snapshot semantics */
2223
externPGDLLIMPORTSnapshotDataSnapshotSelfData;
2324
externPGDLLIMPORTSnapshotDataSnapshotAnyData;
24-
externPGDLLIMPORTSnapshotDataSnapshotToastData;
2525
externPGDLLIMPORTSnapshotDataCatalogSnapshotData;
2626

2727
#defineSnapshotSelf(&SnapshotSelfData)
2828
#defineSnapshotAny(&SnapshotAnyData)
29-
#defineSnapshotToast(&SnapshotToastData)
30-
31-
/*
32-
* We don't provide a static SnapshotDirty variable because it would be
33-
* non-reentrant. Instead, users of that snapshot type should declare a
34-
* local variable of type SnapshotData, and initialize it with this macro.
35-
*/
36-
#defineInitDirtySnapshot(snapshotdata) \
37-
((snapshotdata).satisfies = HeapTupleSatisfiesDirty)
3829

3930
/* This macro encodes the knowledge of which snapshots are MVCC-safe */
4031
#defineIsMVCCSnapshot(snapshot) \
@@ -100,4 +91,25 @@ extern bool ResolveCminCmaxDuringDecoding(struct HTAB *tuplecid_data,
10091
HeapTuplehtup,
10192
Bufferbuffer,
10293
CommandId*cmin,CommandId*cmax);
94+
95+
/*
96+
* We don't provide a static SnapshotDirty variable because it would be
97+
* non-reentrant. Instead, users of that snapshot type should declare a
98+
* local variable of type SnapshotData, and initialize it with this macro.
99+
*/
100+
#defineInitDirtySnapshot(snapshotdata) \
101+
((snapshotdata).satisfies = HeapTupleSatisfiesDirty)
102+
103+
/*
104+
* Similarly, some initialization is required for SnapshotToast. We need
105+
* to set lsn and whenTaken correctly to support snapshot_too_old.
106+
*/
107+
staticinlinevoid
108+
InitToastSnapshot(Snapshotsnapshot,XLogRecPtrlsn,int64whenTaken)
109+
{
110+
snapshot->satisfies=HeapTupleSatisfiesToast;
111+
snapshot->lsn=lsn;
112+
snapshot->whenTaken=whenTaken;
113+
}
114+
103115
#endif/* TQUAL_H */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp