mirror of
https://github.com/postgres/postgres.git
synced 2025-10-16 17:07:43 +03:00
Nested transactions. There is still much left to do, especially on the
performance front, but with feature freeze upon us I think it's time to drive a stake in the ground and say that this will be in 7.5. Alvaro Herrera, with some help from Tom Lane.
This commit is contained in:
143
src/backend/utils/cache/relcache.c
vendored
143
src/backend/utils/cache/relcache.c
vendored
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.205 2004/06/18 06:13:52 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.206 2004/07/01 00:51:17 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -273,6 +273,8 @@ static void IndexSupportInitialize(Form_pg_index iform,
|
||||
static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
|
||||
StrategyNumber numStrats,
|
||||
StrategyNumber numSupport);
|
||||
static inline void RelationPushReferenceCount(Relation rel);
|
||||
static inline void RelationPopReferenceCount(Relation rel);
|
||||
|
||||
|
||||
/*
|
||||
@@ -1678,6 +1680,8 @@ RelationClearRelation(Relation relation, bool rebuild)
|
||||
list_free(relation->rd_indexlist);
|
||||
if (relation->rd_indexcxt)
|
||||
MemoryContextDelete(relation->rd_indexcxt);
|
||||
if (relation->rd_prevrefcnt)
|
||||
pfree(relation->rd_prevrefcnt);
|
||||
|
||||
/*
|
||||
* If we're really done with the relcache entry, blow it away. But if
|
||||
@@ -1968,7 +1972,7 @@ RelationCacheInvalidate(void)
|
||||
* we must reset refcnts before handling pending invalidations.
|
||||
*/
|
||||
void
|
||||
AtEOXact_RelationCache(bool commit)
|
||||
AtEOXact_RelationCache(bool isCommit)
|
||||
{
|
||||
HASH_SEQ_STATUS status;
|
||||
RelIdCacheEnt *idhentry;
|
||||
@@ -1993,7 +1997,7 @@ AtEOXact_RelationCache(bool commit)
|
||||
*/
|
||||
if (relation->rd_isnew)
|
||||
{
|
||||
if (commit)
|
||||
if (isCommit)
|
||||
relation->rd_isnew = false;
|
||||
else
|
||||
{
|
||||
@@ -2019,7 +2023,7 @@ AtEOXact_RelationCache(bool commit)
|
||||
*/
|
||||
expected_refcnt = relation->rd_isnailed ? 1 : 0;
|
||||
|
||||
if (commit)
|
||||
if (isCommit)
|
||||
{
|
||||
if (relation->rd_refcnt != expected_refcnt &&
|
||||
!IsBootstrapProcessingMode())
|
||||
@@ -2036,6 +2040,12 @@ AtEOXact_RelationCache(bool commit)
|
||||
RelationSetReferenceCount(relation, expected_refcnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the refcount stack. Just drop the item count; don't deallocate
|
||||
* the stack itself so it can be reused by future subtransactions.
|
||||
*/
|
||||
relation->rd_numpushed = 0;
|
||||
|
||||
/*
|
||||
* Flush any temporary index list.
|
||||
*/
|
||||
@@ -2048,6 +2058,131 @@ AtEOXact_RelationCache(bool commit)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* RelationPushReferenceCount
|
||||
*
|
||||
* Push the current reference count into the stack. Don't modify the
|
||||
* reference count itself.
|
||||
*/
|
||||
static inline void
|
||||
RelationPushReferenceCount(Relation rel)
|
||||
{
|
||||
/* Enlarge the stack if we run out of space. */
|
||||
if (rel->rd_numpushed == rel->rd_numalloc)
|
||||
{
|
||||
MemoryContext old_cxt = MemoryContextSwitchTo(CacheMemoryContext);
|
||||
|
||||
if (rel->rd_numalloc == 0)
|
||||
{
|
||||
rel->rd_numalloc = 8;
|
||||
rel->rd_prevrefcnt = palloc(rel->rd_numalloc * sizeof(int));
|
||||
}
|
||||
else
|
||||
{
|
||||
rel->rd_numalloc *= 2;
|
||||
rel->rd_prevrefcnt = repalloc(rel->rd_prevrefcnt, rel->rd_numalloc * sizeof(int));
|
||||
}
|
||||
|
||||
MemoryContextSwitchTo(old_cxt);
|
||||
}
|
||||
|
||||
rel->rd_prevrefcnt[rel->rd_numpushed++] = rel->rd_refcnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* RelationPopReferenceCount
|
||||
*
|
||||
* Pop the latest stored reference count. If there is none, drop it
|
||||
* to zero; the entry was created in the current subtransaction.
|
||||
*/
|
||||
static inline void
|
||||
RelationPopReferenceCount(Relation rel)
|
||||
{
|
||||
if (rel->rd_numpushed == 0)
|
||||
{
|
||||
rel->rd_refcnt = rel->rd_isnailed ? 1 : 0;
|
||||
return;
|
||||
}
|
||||
|
||||
rel->rd_refcnt = rel->rd_prevrefcnt[--rel->rd_numpushed];
|
||||
}
|
||||
|
||||
/*
|
||||
* AtEOSubXact_RelationCache
|
||||
*/
|
||||
void
|
||||
AtEOSubXact_RelationCache(bool isCommit)
|
||||
{
|
||||
HASH_SEQ_STATUS status;
|
||||
RelIdCacheEnt *idhentry;
|
||||
|
||||
/* We'd better not be bootstrapping. */
|
||||
Assert(!IsBootstrapProcessingMode());
|
||||
|
||||
hash_seq_init(&status, RelationIdCache);
|
||||
|
||||
while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
|
||||
{
|
||||
Relation relation = idhentry->reldesc;
|
||||
|
||||
/*
|
||||
* During subtransaction commit, we first check whether the
|
||||
* current refcount is correct: if there is no item in the stack,
|
||||
* the relcache entry was created during this subtransaction, it should
|
||||
* be 0 (or 1 for nailed relations). If the stack has at least one
|
||||
* item, the expected count is whatever that item is.
|
||||
*/
|
||||
if (isCommit)
|
||||
{
|
||||
int expected_refcnt;
|
||||
|
||||
if (relation->rd_numpushed == 0)
|
||||
expected_refcnt = relation->rd_isnailed ? 1 : 0;
|
||||
else
|
||||
expected_refcnt = relation->rd_prevrefcnt[relation->rd_numpushed - 1];
|
||||
|
||||
if (relation->rd_refcnt != expected_refcnt)
|
||||
{
|
||||
elog(WARNING, "relcache reference leak: relation \"%s\" has refcnt %d instead of %d",
|
||||
RelationGetRelationName(relation),
|
||||
relation->rd_refcnt, expected_refcnt);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* On commit, the expected count is stored so there's no harm in
|
||||
* popping it (and we may need to fix if there was a leak); and during
|
||||
* abort, the correct refcount has to be restored.
|
||||
*/
|
||||
RelationPopReferenceCount(relation);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* AtSubStart_RelationCache
|
||||
*
|
||||
* At subtransaction start, we push the current reference count into
|
||||
* the refcount stack, so it can be restored if the subtransaction aborts.
|
||||
*/
|
||||
void
|
||||
AtSubStart_RelationCache(void)
|
||||
{
|
||||
HASH_SEQ_STATUS status;
|
||||
RelIdCacheEnt *idhentry;
|
||||
|
||||
/* We'd better not be bootstrapping. */
|
||||
Assert(!IsBootstrapProcessingMode());
|
||||
|
||||
hash_seq_init(&status, RelationIdCache);
|
||||
|
||||
while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
|
||||
{
|
||||
Relation relation = idhentry->reldesc;
|
||||
|
||||
RelationPushReferenceCount(relation);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* RelationBuildLocalRelation
|
||||
* Build a relcache entry for an about-to-be-created relation,
|
||||
|
Reference in New Issue
Block a user