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

Commit7b0d0e9

Browse files
committed
Preserve toast value OIDs in toast-swap-by-content for CLUSTER/VACUUM FULL.
This works around the problem that a catalog cache entry might contain atoast pointer that we try to dereference just as a VACUUM FULL completeson that catalog. We will see the sinval message on the cache entry whenwe acquire lock on the toast table, but by that point we've already toldtuptoaster.c "here's the pointer to fetch", so it's difficult from a codestructural standpoint to update the pointer before we use it. Much lesspainful to ensure that toast pointers are not invalidated in the firstplace. We have to add a bit of code to deal with the case that a valuethat previously wasn't toasted becomes so; but that should be aseldom-exercised corner case, so the inefficiency shouldn't be significant.Back-patch to 9.0. In prior versions, we didn't allow CLUSTER on systemcatalogs, and VACUUM FULL didn't result in reassignment of toast OIDs, sothere was no problem.
1 parent2ada677 commit7b0d0e9

File tree

2 files changed

+117
-9
lines changed

2 files changed

+117
-9
lines changed

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

Lines changed: 113 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,9 @@ do { \
7474

7575

7676
staticvoidtoast_delete_datum(Relationrel,Datumvalue);
77-
staticDatumtoast_save_datum(Relationrel,Datumvalue,intoptions);
77+
staticDatumtoast_save_datum(Relationrel,Datumvalue,
78+
structvarlena*oldexternal,intoptions);
79+
staticbooltoast_valueid_exists(Oidtoastrelid,Oidvalueid);
7880
staticstructvarlena*toast_fetch_datum(structvarlena*attr);
7981
staticstructvarlena*toast_fetch_datum_slice(structvarlena*attr,
8082
int32sliceoffset,int32length);
@@ -431,6 +433,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
431433
booltoast_oldisnull[MaxHeapAttributeNumber];
432434
Datumtoast_values[MaxHeapAttributeNumber];
433435
Datumtoast_oldvalues[MaxHeapAttributeNumber];
436+
structvarlena*toast_oldexternal[MaxHeapAttributeNumber];
434437
int32toast_sizes[MaxHeapAttributeNumber];
435438
booltoast_free[MaxHeapAttributeNumber];
436439
booltoast_delold[MaxHeapAttributeNumber];
@@ -466,6 +469,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
466469
* ----------
467470
*/
468471
memset(toast_action,' ',numAttrs*sizeof(char));
472+
memset(toast_oldexternal,0,numAttrs*sizeof(structvarlena*));
469473
memset(toast_free,0,numAttrs*sizeof(bool));
470474
memset(toast_delold,0,numAttrs*sizeof(bool));
471475

@@ -550,6 +554,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
550554
*/
551555
if (VARATT_IS_EXTERNAL(new_value))
552556
{
557+
toast_oldexternal[i]=new_value;
553558
if (att[i]->attstorage=='p')
554559
new_value=heap_tuple_untoast_attr(new_value);
555560
else
@@ -676,7 +681,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
676681
{
677682
old_value=toast_values[i];
678683
toast_action[i]='p';
679-
toast_values[i]=toast_save_datum(rel,toast_values[i],options);
684+
toast_values[i]=toast_save_datum(rel,toast_values[i],
685+
toast_oldexternal[i],options);
680686
if (toast_free[i])
681687
pfree(DatumGetPointer(old_value));
682688
toast_free[i]= true;
@@ -726,7 +732,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
726732
i=biggest_attno;
727733
old_value=toast_values[i];
728734
toast_action[i]='p';
729-
toast_values[i]=toast_save_datum(rel,toast_values[i],options);
735+
toast_values[i]=toast_save_datum(rel,toast_values[i],
736+
toast_oldexternal[i],options);
730737
if (toast_free[i])
731738
pfree(DatumGetPointer(old_value));
732739
toast_free[i]= true;
@@ -839,7 +846,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup,
839846
i=biggest_attno;
840847
old_value=toast_values[i];
841848
toast_action[i]='p';
842-
toast_values[i]=toast_save_datum(rel,toast_values[i],options);
849+
toast_values[i]=toast_save_datum(rel,toast_values[i],
850+
toast_oldexternal[i],options);
843851
if (toast_free[i])
844852
pfree(DatumGetPointer(old_value));
845853
toast_free[i]= true;
@@ -1117,10 +1125,16 @@ toast_compress_datum(Datum value)
11171125
*
11181126
*Save one single datum into the secondary relation and return
11191127
*a Datum reference for it.
1128+
*
1129+
* rel: the main relation we're working with (not the toast rel!)
1130+
* value: datum to be pushed to toast storage
1131+
* oldexternal: if not NULL, toast pointer previously representing the datum
1132+
* options: options to be passed to heap_insert() for toast rows
11201133
* ----------
11211134
*/
11221135
staticDatum
1123-
toast_save_datum(Relationrel,Datumvalue,intoptions)
1136+
toast_save_datum(Relationrel,Datumvalue,
1137+
structvarlena*oldexternal,intoptions)
11241138
{
11251139
Relationtoastrel;
11261140
Relationtoastidx;
@@ -1199,11 +1213,55 @@ toast_save_datum(Relation rel, Datum value, int options)
11991213
toast_pointer.va_toastrelid=RelationGetRelid(toastrel);
12001214

12011215
/*
1202-
* Choose an unused OID within the toast table for this toast value.
1216+
* Choose an OID to use as the value ID for this toast value.
1217+
*
1218+
* Normally we just choose an unused OID within the toast table. But
1219+
* during table-rewriting operations where we are preserving an existing
1220+
* toast table OID, we want to preserve toast value OIDs too. So, if
1221+
* rd_toastoid is set and we had a prior external value from that same
1222+
* toast table, re-use its value ID. If we didn't have a prior external
1223+
* value (which is a corner case, but possible if the table's attstorage
1224+
* options have been changed), we have to pick a value ID that doesn't
1225+
* conflict with either new or existing toast value OIDs.
12031226
*/
1204-
toast_pointer.va_valueid=GetNewOidWithIndex(toastrel,
1205-
RelationGetRelid(toastidx),
1206-
(AttrNumber)1);
1227+
if (!OidIsValid(rel->rd_toastoid))
1228+
{
1229+
/* normal case: just choose an unused OID */
1230+
toast_pointer.va_valueid=
1231+
GetNewOidWithIndex(toastrel,
1232+
RelationGetRelid(toastidx),
1233+
(AttrNumber)1);
1234+
}
1235+
else
1236+
{
1237+
/* rewrite case: check to see if value was in old toast table */
1238+
toast_pointer.va_valueid=InvalidOid;
1239+
if (oldexternal!=NULL)
1240+
{
1241+
structvaratt_externalold_toast_pointer;
1242+
1243+
Assert(VARATT_IS_EXTERNAL(oldexternal));
1244+
/* Must copy to access aligned fields */
1245+
VARATT_EXTERNAL_GET_POINTER(old_toast_pointer,oldexternal);
1246+
if (old_toast_pointer.va_toastrelid==rel->rd_toastoid)
1247+
toast_pointer.va_valueid=old_toast_pointer.va_valueid;
1248+
}
1249+
if (toast_pointer.va_valueid==InvalidOid)
1250+
{
1251+
/*
1252+
* new value; must choose an OID that doesn't conflict in either
1253+
* old or new toast table
1254+
*/
1255+
do
1256+
{
1257+
toast_pointer.va_valueid=
1258+
GetNewOidWithIndex(toastrel,
1259+
RelationGetRelid(toastidx),
1260+
(AttrNumber)1);
1261+
}while (toast_valueid_exists(rel->rd_toastoid,
1262+
toast_pointer.va_valueid));
1263+
}
1264+
}
12071265

12081266
/*
12091267
* Initialize constant parts of the tuple data
@@ -1338,6 +1396,52 @@ toast_delete_datum(Relation rel, Datum value)
13381396
}
13391397

13401398

1399+
/* ----------
1400+
* toast_valueid_exists -
1401+
*
1402+
*Test whether a toast value with the given ID exists in the toast relation
1403+
* ----------
1404+
*/
1405+
staticbool
1406+
toast_valueid_exists(Oidtoastrelid,Oidvalueid)
1407+
{
1408+
boolresult= false;
1409+
Relationtoastrel;
1410+
ScanKeyDatatoastkey;
1411+
SysScanDesctoastscan;
1412+
1413+
/*
1414+
* Open the toast relation
1415+
*/
1416+
toastrel=heap_open(toastrelid,AccessShareLock);
1417+
1418+
/*
1419+
* Setup a scan key to find chunks with matching va_valueid
1420+
*/
1421+
ScanKeyInit(&toastkey,
1422+
(AttrNumber)1,
1423+
BTEqualStrategyNumber,F_OIDEQ,
1424+
ObjectIdGetDatum(valueid));
1425+
1426+
/*
1427+
* Is there any such chunk?
1428+
*/
1429+
toastscan=systable_beginscan(toastrel,toastrel->rd_rel->reltoastidxid,
1430+
true,SnapshotToast,1,&toastkey);
1431+
1432+
if (systable_getnext(toastscan)!=NULL)
1433+
result= true;
1434+
1435+
/*
1436+
* End scan and close relations
1437+
*/
1438+
systable_endscan(toastscan);
1439+
heap_close(toastrel,AccessShareLock);
1440+
1441+
returnresult;
1442+
}
1443+
1444+
13411445
/* ----------
13421446
* toast_fetch_datum -
13431447
*

‎src/backend/commands/cluster.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,10 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
797797
* When doing swap by content, any toast pointers written into NewHeap
798798
* must use the old toast table's OID, because that's where the toast
799799
* data will eventually be found. Set this up by setting rd_toastoid.
800+
* This also tells tuptoaster.c to preserve the toast value OIDs,
801+
* which we want so as not to invalidate toast pointers in system
802+
* catalog caches.
803+
*
800804
* Note that we must hold NewHeap open until we are done writing data,
801805
* since the relcache will not guarantee to remember this setting once
802806
* the relation is closed.Also, this technique depends on the fact

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp