Skip to content

Commit ddfcfb7

Browse files
Ensure we have a snapshot when updating various system catalogs.
A few places that access system catalogs don't set up an active snapshot before potentially accessing their TOAST tables. To fix, push an active snapshot just before each section of code that might require accessing one of these TOAST tables, and pop it shortly afterwards. While at it, this commit adds some rather strict assertions in an attempt to prevent such issues in the future. Commit 16bf24e recently removed pg_replication_origin's TOAST table in order to fix the same problem for that catalog. On the back-branches, those bugs are left in place. We cannot easily remove a catalog's TOAST table on released major versions, and only replication origins with extremely long names are affected. Given the low severity of the issue, fixing older versions doesn't seem worth the trouble of significantly modifying the patch. Also, on v13 and v14, the aforementioned strict assertions have been omitted because commit 2776922, which added HaveRegisteredOrActiveSnapshot(), was not back-patched. While we could probably back-patch it now, I've opted against it because it seems unlikely that new TOAST snapshot issues will be introduced in the oldest supported versions. Reported-by: Alexander Lakhin <exclusion@gmail.com> Reviewed-by: Michael Paquier <michael@paquier.xyz> Discussion: https://postgr.es/m/18127-fe54b6a667f29658%40postgresql.org Discussion: https://postgr.es/m/18309-c0bf914950c46692%40postgresql.org Discussion: https://postgr.es/m/ZvMSUPOqUU-VNADN%40nathan Backpatch-through: 13
1 parent 3c31594 commit ddfcfb7

File tree

5 files changed

+88
-0
lines changed

5 files changed

+88
-0
lines changed

src/backend/access/heap/heapam.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include "catalog/catalog.h"
5555
#include "catalog/pg_database.h"
5656
#include "catalog/pg_database_d.h"
57+
#include "catalog/pg_replication_origin.h"
5758
#include "miscadmin.h"
5859
#include "pgstat.h"
5960
#include "port/atomics.h"
@@ -227,6 +228,38 @@ static const int MultiXactStatusLock[MaxMultiXactStatus + 1] =
227228
#define TUPLOCK_from_mxstatus(status) \
228229
(MultiXactStatusLock[(status)])
229230

231+
/*
232+
* Check that we have a valid snapshot if we might need TOAST access.
233+
*/
234+
static inline void
235+
AssertHasSnapshotForToast(Relation rel)
236+
{
237+
#ifdef USE_ASSERT_CHECKING
238+
239+
/* bootstrap mode in particular breaks this rule */
240+
if (!IsNormalProcessingMode())
241+
return;
242+
243+
/* if the relation doesn't have a TOAST table, we are good */
244+
if (!OidIsValid(rel->rd_rel->reltoastrelid))
245+
return;
246+
247+
/*
248+
* Commit 16bf24e fixed accesses to pg_replication_origin without a
249+
* an active snapshot by removing its TOAST table. On older branches,
250+
* these bugs are left in place. Its only varlena column is roname (the
251+
* replication origin name), so this is only a problem if the name
252+
* requires out-of-line storage, which seems unlikely. In any case,
253+
* fixing it doesn't seem worth extra code churn on the back-branches.
254+
*/
255+
if (RelationGetRelid(rel) == ReplicationOriginRelationId)
256+
return;
257+
258+
Assert(HaveRegisteredOrActiveSnapshot());
259+
260+
#endif /* USE_ASSERT_CHECKING */
261+
}
262+
230263
/* ----------------------------------------------------------------
231264
* heap support routines
232265
* ----------------------------------------------------------------
@@ -2047,6 +2080,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
20472080
Assert(HeapTupleHeaderGetNatts(tup->t_data) <=
20482081
RelationGetNumberOfAttributes(relation));
20492082

2083+
AssertHasSnapshotForToast(relation);
2084+
20502085
/*
20512086
* Fill in tuple header fields and toast the tuple if necessary.
20522087
*
@@ -2294,6 +2329,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
22942329
/* currently not needed (thus unsupported) for heap_multi_insert() */
22952330
AssertArg(!(options & HEAP_INSERT_NO_LOGICAL));
22962331

2332+
AssertHasSnapshotForToast(relation);
2333+
22972334
needwal = RelationNeedsWAL(relation);
22982335
saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
22992336
HEAP_DEFAULT_FILLFACTOR);
@@ -2697,6 +2734,8 @@ heap_delete(Relation relation, ItemPointer tid,
26972734

26982735
Assert(ItemPointerIsValid(tid));
26992736

2737+
AssertHasSnapshotForToast(relation);
2738+
27002739
/*
27012740
* Forbid this during a parallel operation, lest it allocate a combo CID.
27022741
* Other workers might need that combo CID for visibility checks, and we
@@ -3188,6 +3227,8 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
31883227
Assert(HeapTupleHeaderGetNatts(newtup->t_data) <=
31893228
RelationGetNumberOfAttributes(relation));
31903229

3230+
AssertHasSnapshotForToast(relation);
3231+
31913232
/*
31923233
* Forbid this during a parallel operation, lest it allocate a combo CID.
31933234
* Other workers might need that combo CID for visibility checks, and we

src/backend/commands/indexcmds.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3993,12 +3993,20 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params)
39933993
get_rel_namespace(oldidx->tableId),
39943994
false);
39953995

3996+
/*
3997+
* Swapping the indexes might involve TOAST table access, so ensure we
3998+
* have a valid snapshot.
3999+
*/
4000+
PushActiveSnapshot(GetTransactionSnapshot());
4001+
39964002
/*
39974003
* Swap old index with the new one. This also marks the new one as
39984004
* valid and the old one as not valid.
39994005
*/
40004006
index_concurrently_swap(newidx->indexId, oldidx->indexId, oldName);
40014007

4008+
PopActiveSnapshot();
4009+
40024010
/*
40034011
* Invalidate the relcache for the table, so that after this commit
40044012
* all sessions will refresh any cached plans that might reference the

src/backend/commands/tablecmds.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18810,9 +18810,17 @@ ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel,
1881018810
tab->rel = rel;
1881118811
}
1881218812

18813+
/*
18814+
* Detaching the partition might involve TOAST table access, so ensure we
18815+
* have a valid snapshot.
18816+
*/
18817+
PushActiveSnapshot(GetTransactionSnapshot());
18818+
1881318819
/* Do the final part of detaching */
1881418820
DetachPartitionFinalize(rel, partRel, concurrent, defaultPartOid);
1881518821

18822+
PopActiveSnapshot();
18823+
1881618824
ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
1881718825

1881818826
/* keep our lock until commit */

src/backend/postmaster/autovacuum.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2315,6 +2315,12 @@ do_autovacuum(void)
23152315
get_namespace_name(classForm->relnamespace),
23162316
NameStr(classForm->relname))));
23172317

2318+
/*
2319+
* Deletion might involve TOAST table access, so ensure we have a
2320+
* valid snapshot.
2321+
*/
2322+
PushActiveSnapshot(GetTransactionSnapshot());
2323+
23182324
object.classId = RelationRelationId;
23192325
object.objectId = relid;
23202326
object.objectSubId = 0;
@@ -2327,6 +2333,7 @@ do_autovacuum(void)
23272333
* To commit the deletion, end current transaction and start a new
23282334
* one. Note this also releases the locks we took.
23292335
*/
2336+
PopActiveSnapshot();
23302337
CommitTransactionCommand();
23312338
StartTransactionCommand();
23322339

src/backend/replication/logical/worker.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3794,8 +3794,16 @@ ApplyWorkerMain(Datum main_arg)
37943794
walrcv_startstreaming(LogRepWorkerWalRcvConn, &options);
37953795

37963796
StartTransactionCommand();
3797+
3798+
/*
3799+
* Updating pg_subscription might involve TOAST table access, so
3800+
* ensure we have a valid snapshot.
3801+
*/
3802+
PushActiveSnapshot(GetTransactionSnapshot());
3803+
37973804
UpdateTwoPhaseState(MySubscription->oid, LOGICALREP_TWOPHASE_STATE_ENABLED);
37983805
MySubscription->twophasestate = LOGICALREP_TWOPHASE_STATE_ENABLED;
3806+
PopActiveSnapshot();
37993807
CommitTransactionCommand();
38003808
}
38013809
else
@@ -3848,7 +3856,15 @@ DisableSubscriptionAndExit(void)
38483856

38493857
/* Disable the subscription */
38503858
StartTransactionCommand();
3859+
3860+
/*
3861+
* Updating pg_subscription might involve TOAST table access, so ensure we
3862+
* have a valid snapshot.
3863+
*/
3864+
PushActiveSnapshot(GetTransactionSnapshot());
3865+
38513866
DisableSubscription(MySubscription->oid);
3867+
PopActiveSnapshot();
38523868
CommitTransactionCommand();
38533869

38543870
/* Notify the subscription has been disabled and exit */
@@ -3939,6 +3955,12 @@ clear_subscription_skip_lsn(XLogRecPtr finish_lsn)
39393955
started_tx = true;
39403956
}
39413957

3958+
/*
3959+
* Updating pg_subscription might involve TOAST table access, so ensure we
3960+
* have a valid snapshot.
3961+
*/
3962+
PushActiveSnapshot(GetTransactionSnapshot());
3963+
39423964
/*
39433965
* Protect subskiplsn of pg_subscription from being concurrently updated
39443966
* while clearing it.
@@ -3997,6 +4019,8 @@ clear_subscription_skip_lsn(XLogRecPtr finish_lsn)
39974019
heap_freetuple(tup);
39984020
table_close(rel, NoLock);
39994021

4022+
PopActiveSnapshot();
4023+
40004024
if (started_tx)
40014025
CommitTransactionCommand();
40024026
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy