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

Commitc2e228d

Browse files
committed
Fix RelationCacheInitializePhase2 (Phase3, in HEAD) to cope with the
possibility of shared-inval messages causing a relcache flush while it triesto fill in missing data in preloaded relcache entries. There are actuallytwo distinct failure modes here:1. The flush could delete the next-to-be-processed cache entry, causingthe subsequent hash_seq_search calls to go off into the weeds. This isthe problem reported by Michael Brown, and I believe it also accountsfor bug #5074. The simplest fix is to restart the hashtable scan afterwe've read any new data from the catalogs. It appears that pre-8.4branches have not suffered from this failure, because by chance there wereno other catalogs sharing the same hash chains with the catalogs thatRelationCacheInitializePhase2 had work to do for. However that's obviouslypretty fragile, and it seems possible that derivative versions withadditional system catalogs might be vulnerable, so I'm back-patching thispart of the fix anyway.2. The flush could delete the *current* cache entry, in which case thepointer to the newly-loaded data would end up being stored into analready-deleted Relation struct. As long as it was still deleted, the onlyconsequence would be some leaked space in CacheMemoryContext. But it seemspossible that the Relation struct could already have been recycled, inwhich case this represents a hard-to-reproduce clobber of cached datastructures, with unforeseeable consequences. The fix here is to pin theentry while we work on it.In passing, also change RelationCacheInitializePhase2 to Assert thatformrdesc() set up the relation's cached TupleDesc (rd_att) with thecorrect type OID and hasoids values. This is more appropriate thansilently updating the values, because the original tupdesc might alreadyhave been copied into the catcache. However this part of the patch isnot in HEAD because it fails due to some questionable recent changes informrdesc :-(. That will be cleaned up in a subsequent patch.
1 parentd39a84a commitc2e228d

File tree

1 file changed

+54
-7
lines changed

1 file changed

+54
-7
lines changed

‎src/backend/utils/cache/relcache.c

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.290 2009/08/30 17:18:52 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.291 2009/09/2618:24:49 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -144,8 +144,7 @@ do { \
144144
RelIdCacheEnt *idhentry; bool found; \
145145
idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
146146
(void *) &(RELATION->rd_id), \
147-
HASH_ENTER, \
148-
&found); \
147+
HASH_ENTER, &found); \
149148
/* used to give notice if found -- now just keep quiet */ \
150149
idhentry->reldesc=RELATION; \
151150
}while(0)
@@ -154,7 +153,8 @@ do { \
154153
do { \
155154
RelIdCacheEnt *hentry; \
156155
hentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
157-
(void *) &(ID), HASH_FIND,NULL); \
156+
(void *) &(ID), \
157+
HASH_FIND, NULL); \
158158
if (hentry) \
159159
RELATION = hentry->reldesc; \
160160
else \
@@ -1412,7 +1412,9 @@ formrdesc(const char *relationName, bool isshared,
14121412
*
14131413
* The data we insert here is pretty incomplete/bogus, but it'll serve to
14141414
* get us launched. RelationCacheInitializePhase3() will read the real
1415-
* data from pg_class and replace what we've done here.
1415+
* data from pg_class and replace what we've done here. Note in particular
1416+
* that relowner is left as zero; this cues RelationCacheInitializePhase3
1417+
* that the real data isn't there yet.
14161418
*/
14171419
relation->rd_rel= (Form_pg_class)palloc0(CLASS_TUPLE_SIZE);
14181420

@@ -2687,17 +2689,31 @@ RelationCacheInitializePhase3(void)
26872689
* rows and replace the fake entries with them. Also, if any of the
26882690
* relcache entries have rules or triggers, load that info the hard way
26892691
* since it isn't recorded in the cache file.
2692+
*
2693+
* Whenever we access the catalogs to read data, there is a possibility
2694+
* of a shared-inval cache flush causing relcache entries to be removed.
2695+
* Since hash_seq_search only guarantees to still work after the *current*
2696+
* entry is removed, it's unsafe to continue the hashtable scan afterward.
2697+
* We handle this by restarting the scan from scratch after each access.
2698+
* This is theoretically O(N^2), but the number of entries that actually
2699+
* need to be fixed is small enough that it doesn't matter.
26902700
*/
26912701
hash_seq_init(&status,RelationIdCache);
26922702

26932703
while ((idhentry= (RelIdCacheEnt*)hash_seq_search(&status))!=NULL)
26942704
{
26952705
Relationrelation=idhentry->reldesc;
2706+
boolrestart= false;
2707+
2708+
/*
2709+
* Make sure *this* entry doesn't get flushed while we work with it.
2710+
*/
2711+
RelationIncrementReferenceCount(relation);
26962712

26972713
/*
26982714
* If it's a faked-up entry, read the real pg_class tuple.
26992715
*/
2700-
if (needNewCacheFile&&relation->rd_isnailed)
2716+
if (relation->rd_rel->relowner==InvalidOid)
27012717
{
27022718
HeapTuplehtup;
27032719
Form_pg_classrelp;
@@ -2714,7 +2730,6 @@ RelationCacheInitializePhase3(void)
27142730
* Copy tuple to relation->rd_rel. (See notes in
27152731
* AllocateRelationDesc())
27162732
*/
2717-
Assert(relation->rd_rel!=NULL);
27182733
memcpy((char*)relation->rd_rel, (char*)relp,CLASS_TUPLE_SIZE);
27192734

27202735
/* Update rd_options while we have the tuple */
@@ -2730,15 +2745,47 @@ RelationCacheInitializePhase3(void)
27302745
relation->rd_att->tdhasoid=relp->relhasoids;
27312746

27322747
ReleaseSysCache(htup);
2748+
2749+
/* relowner had better be OK now, else we'll loop forever */
2750+
if (relation->rd_rel->relowner==InvalidOid)
2751+
elog(ERROR,"invalid relowner in pg_class entry for \"%s\"",
2752+
RelationGetRelationName(relation));
2753+
2754+
restart= true;
27332755
}
27342756

27352757
/*
27362758
* Fix data that isn't saved in relcache cache file.
2759+
*
2760+
* relhasrules or relhastriggers could possibly be wrong or out of
2761+
* date. If we don't actually find any rules or triggers, clear the
2762+
* local copy of the flag so that we don't get into an infinite loop
2763+
* here. We don't make any attempt to fix the pg_class entry, though.
27372764
*/
27382765
if (relation->rd_rel->relhasrules&&relation->rd_rules==NULL)
2766+
{
27392767
RelationBuildRuleLock(relation);
2768+
if (relation->rd_rules==NULL)
2769+
relation->rd_rel->relhasrules= false;
2770+
restart= true;
2771+
}
27402772
if (relation->rd_rel->relhastriggers&&relation->trigdesc==NULL)
2773+
{
27412774
RelationBuildTriggers(relation);
2775+
if (relation->trigdesc==NULL)
2776+
relation->rd_rel->relhastriggers= false;
2777+
restart= true;
2778+
}
2779+
2780+
/* Release hold on the relation */
2781+
RelationDecrementReferenceCount(relation);
2782+
2783+
/* Now, restart the hashtable scan if needed */
2784+
if (restart)
2785+
{
2786+
hash_seq_term(&status);
2787+
hash_seq_init(&status,RelationIdCache);
2788+
}
27422789
}
27432790

27442791
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp