diff options
author | Simon Riggs <simon@2ndQuadrant.com> | 2014-04-06 11:13:43 -0400 |
---|---|---|
committer | Simon Riggs <simon@2ndQuadrant.com> | 2014-04-06 11:13:43 -0400 |
commit | e5550d5fec66aa74caad1f79b79826ec64898688 (patch) | |
tree | 046444c974bf3aa9833545c0b9bbc183c37dbfa1 /src/backend/utils/cache/relcache.c | |
parent | 80a5cf643adb496abe577a1ca6dc0c476d849c19 (diff) | |
download | postgresql-e5550d5fec66aa74caad1f79b79826ec64898688.tar.gz postgresql-e5550d5fec66aa74caad1f79b79826ec64898688.zip |
Reduce lock levels of some ALTER TABLE cmds
VALIDATE CONSTRAINT
CLUSTER ON
SET WITHOUT CLUSTER
ALTER COLUMN SET STATISTICS
ALTER COLUMN SET ()
ALTER COLUMN RESET ()
All other sub-commands use AccessExclusiveLock
Simon Riggs and Noah Misch
Reviews by Robert Haas and Andres Freund
Diffstat (limited to 'src/backend/utils/cache/relcache.c')
-rw-r--r-- | src/backend/utils/cache/relcache.c | 74 |
1 files changed, 67 insertions, 7 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 32313244adb..c8cea028d4e 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -162,6 +162,14 @@ static bool eoxact_list_overflowed = false; eoxact_list_overflowed = true; \ } while (0) +/* + * EOXactTupleDescArray stores TupleDescs that (might) need AtEOXact + * cleanup work. The array expands as needed; there is no hashtable because + * we don't need to access individual items except at EOXact. + */ +static TupleDesc *EOXactTupleDescArray; +static int NextEOXactTupleDescNum = 0; +static int EOXactTupleDescArrayLen = 0; /* * macros to manipulate the lookup hashtables @@ -220,11 +228,12 @@ static HTAB *OpClassCache = NULL; /* non-export function prototypes */ -static void RelationDestroyRelation(Relation relation); +static void RelationDestroyRelation(Relation relation, bool remember_tupdesc); static void RelationClearRelation(Relation relation, bool rebuild); static void RelationReloadIndexInfo(Relation relation); static void RelationFlushRelation(Relation relation); +static void RememberToFreeTupleDescAtEOX(TupleDesc td); static void AtEOXact_cleanup(Relation relation, bool isCommit); static void AtEOSubXact_cleanup(Relation relation, bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid); @@ -1858,7 +1867,7 @@ RelationReloadIndexInfo(Relation relation) * Caller must already have unhooked the entry from the hash table. */ static void -RelationDestroyRelation(Relation relation) +RelationDestroyRelation(Relation relation, bool remember_tupdesc) { Assert(RelationHasReferenceCountZero(relation)); @@ -1878,7 +1887,20 @@ RelationDestroyRelation(Relation relation) /* can't use DecrTupleDescRefCount here */ Assert(relation->rd_att->tdrefcount > 0); if (--relation->rd_att->tdrefcount == 0) - FreeTupleDesc(relation->rd_att); + { + /* + * If we Rebuilt a relcache entry during a transaction then its + * possible we did that because the TupDesc changed as the result + * of an ALTER TABLE that ran at less than AccessExclusiveLock. + * It's possible someone copied that TupDesc, in which case the + * copy would point to free'd memory. So if we rebuild an entry + * we keep the TupDesc around until end of transaction, to be safe. + */ + if (remember_tupdesc) + RememberToFreeTupleDescAtEOX(relation->rd_att); + else + FreeTupleDesc(relation->rd_att); + } list_free(relation->rd_indexlist); bms_free(relation->rd_indexattr); FreeTriggerDesc(relation->trigdesc); @@ -1992,7 +2014,7 @@ RelationClearRelation(Relation relation, bool rebuild) RelationCacheDelete(relation); /* And release storage */ - RelationDestroyRelation(relation); + RelationDestroyRelation(relation, false); } else if (!IsTransactionState()) { @@ -2059,7 +2081,7 @@ RelationClearRelation(Relation relation, bool rebuild) { /* Should only get here if relation was deleted */ RelationCacheDelete(relation); - RelationDestroyRelation(relation); + RelationDestroyRelation(relation, false); elog(ERROR, "relation %u deleted while still in use", save_relid); } @@ -2121,7 +2143,7 @@ RelationClearRelation(Relation relation, bool rebuild) #undef SWAPFIELD /* And now we can throw away the temporary entry */ - RelationDestroyRelation(newrel); + RelationDestroyRelation(newrel, !keep_tupdesc); } } @@ -2359,6 +2381,33 @@ RelationCloseSmgrByOid(Oid relationId) RelationCloseSmgr(relation); } +void +RememberToFreeTupleDescAtEOX(TupleDesc td) +{ + if (EOXactTupleDescArray == NULL) + { + MemoryContext oldcxt; + oldcxt = MemoryContextSwitchTo(CacheMemoryContext); + + EOXactTupleDescArray = (TupleDesc *) palloc(16 * sizeof(TupleDesc)); + EOXactTupleDescArrayLen = 16; + NextEOXactTupleDescNum = 0; + MemoryContextSwitchTo(oldcxt); + } + else if (NextEOXactTupleDescNum >= EOXactTupleDescArrayLen) + { + int32 newlen = EOXactTupleDescArrayLen * 2; + + Assert(EOXactTupleDescArrayLen > 0); + + EOXactTupleDescArray = (TupleDesc *) repalloc(EOXactTupleDescArray, + newlen * sizeof(TupleDesc)); + EOXactTupleDescArrayLen = newlen; + } + + EOXactTupleDescArray[NextEOXactTupleDescNum++] = td; +} + /* * AtEOXact_RelationCache * @@ -2414,9 +2463,20 @@ AtEOXact_RelationCache(bool isCommit) } } - /* Now we're out of the transaction and can clear the list */ + if (EOXactTupleDescArrayLen > 0) + { + Assert(EOXactTupleDescArray != NULL); + for (i = 0; i < NextEOXactTupleDescNum; i++) + FreeTupleDesc(EOXactTupleDescArray[i]); + pfree(EOXactTupleDescArray); + EOXactTupleDescArray = NULL; + } + + /* Now we're out of the transaction and can clear the lists */ eoxact_list_len = 0; eoxact_list_overflowed = false; + NextEOXactTupleDescNum = 0; + EOXactTupleDescArrayLen = 0; } /* |