Avoid setup work for invalidation messages at start-of-(sub)xact.
Instead of initializing a new TransInvalidationInfo for every transaction or subtransaction, we can just do it for those transactions or subtransactions that actually need to queue invalidation messages. That also avoids needing to free those entries at the end of a transaction or subtransaction that does not generate any invalidation messages, which is by far the common case. Patch by me. Review by Simon Riggs and Andres Freund.
This commit is contained in:
parent
8f8314b560
commit
6cb4afff33
@ -1838,7 +1838,6 @@ StartTransaction(void)
|
||||
* initialize other subsystems for new transaction
|
||||
*/
|
||||
AtStart_GUC();
|
||||
AtStart_Inval();
|
||||
AtStart_Cache();
|
||||
AfterTriggerBeginXact();
|
||||
|
||||
@ -4151,7 +4150,6 @@ StartSubTransaction(void)
|
||||
*/
|
||||
AtSubStart_Memory();
|
||||
AtSubStart_ResourceOwner();
|
||||
AtSubStart_Inval();
|
||||
AtSubStart_Notify();
|
||||
AfterTriggerBeginSubXact();
|
||||
|
||||
|
125
src/backend/utils/cache/inval.c
vendored
125
src/backend/utils/cache/inval.c
vendored
@ -693,19 +693,32 @@ AcceptInvalidationMessages(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* AtStart_Inval
|
||||
* Initialize inval lists at start of a main transaction.
|
||||
* PrepareInvalidationState
|
||||
* Initialize inval lists for the current (sub)transaction.
|
||||
*/
|
||||
void
|
||||
AtStart_Inval(void)
|
||||
static void
|
||||
PrepareInvalidationState(void)
|
||||
{
|
||||
Assert(transInvalInfo == NULL);
|
||||
transInvalInfo = (TransInvalidationInfo *)
|
||||
TransInvalidationInfo *myInfo;
|
||||
|
||||
if (transInvalInfo != NULL &&
|
||||
transInvalInfo->my_level == GetCurrentTransactionNestLevel())
|
||||
return;
|
||||
|
||||
myInfo = (TransInvalidationInfo *)
|
||||
MemoryContextAllocZero(TopTransactionContext,
|
||||
sizeof(TransInvalidationInfo));
|
||||
transInvalInfo->my_level = GetCurrentTransactionNestLevel();
|
||||
SharedInvalidMessagesArray = NULL;
|
||||
numSharedInvalidMessagesArray = 0;
|
||||
myInfo->parent = transInvalInfo;
|
||||
myInfo->my_level = GetCurrentTransactionNestLevel();
|
||||
|
||||
/*
|
||||
* If there's any previous entry, this one should be for a deeper
|
||||
* nesting level.
|
||||
*/
|
||||
Assert(transInvalInfo == NULL ||
|
||||
myInfo->my_level > transInvalInfo->my_level);
|
||||
|
||||
transInvalInfo = myInfo;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -726,24 +739,6 @@ PostPrepare_Inval(void)
|
||||
AtEOXact_Inval(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* AtSubStart_Inval
|
||||
* Initialize inval lists at start of a subtransaction.
|
||||
*/
|
||||
void
|
||||
AtSubStart_Inval(void)
|
||||
{
|
||||
TransInvalidationInfo *myInfo;
|
||||
|
||||
Assert(transInvalInfo != NULL);
|
||||
myInfo = (TransInvalidationInfo *)
|
||||
MemoryContextAllocZero(TopTransactionContext,
|
||||
sizeof(TransInvalidationInfo));
|
||||
myInfo->parent = transInvalInfo;
|
||||
myInfo->my_level = GetCurrentTransactionNestLevel();
|
||||
transInvalInfo = myInfo;
|
||||
}
|
||||
|
||||
/*
|
||||
* Collect invalidation messages into SharedInvalidMessagesArray array.
|
||||
*/
|
||||
@ -803,8 +798,16 @@ xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
|
||||
{
|
||||
MemoryContext oldcontext;
|
||||
|
||||
/* Quick exit if we haven't done anything with invalidation messages. */
|
||||
if (transInvalInfo == NULL)
|
||||
{
|
||||
*RelcacheInitFileInval = false;
|
||||
*msgs = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Must be at top of stack */
|
||||
Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL);
|
||||
Assert(transInvalInfo->my_level == 1 && transInvalInfo->parent == NULL);
|
||||
|
||||
/*
|
||||
* Relcache init file invalidation requires processing both before and
|
||||
@ -904,11 +907,15 @@ ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
|
||||
void
|
||||
AtEOXact_Inval(bool isCommit)
|
||||
{
|
||||
/* Quick exit if no messages */
|
||||
if (transInvalInfo == NULL)
|
||||
return;
|
||||
|
||||
/* Must be at top of stack */
|
||||
Assert(transInvalInfo->my_level == 1 && transInvalInfo->parent == NULL);
|
||||
|
||||
if (isCommit)
|
||||
{
|
||||
/* Must be at top of stack */
|
||||
Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL);
|
||||
|
||||
/*
|
||||
* Relcache init file invalidation requires processing both before and
|
||||
* after we send the SI messages. However, we need not do anything
|
||||
@ -926,17 +933,16 @@ AtEOXact_Inval(bool isCommit)
|
||||
if (transInvalInfo->RelcacheInitFileInval)
|
||||
RelationCacheInitFilePostInvalidate();
|
||||
}
|
||||
else if (transInvalInfo != NULL)
|
||||
else
|
||||
{
|
||||
/* Must be at top of stack */
|
||||
Assert(transInvalInfo->parent == NULL);
|
||||
|
||||
ProcessInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
|
||||
LocalExecuteInvalidationMessage);
|
||||
}
|
||||
|
||||
/* Need not free anything explicitly */
|
||||
transInvalInfo = NULL;
|
||||
SharedInvalidMessagesArray = NULL;
|
||||
numSharedInvalidMessagesArray = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -960,18 +966,38 @@ AtEOXact_Inval(bool isCommit)
|
||||
void
|
||||
AtEOSubXact_Inval(bool isCommit)
|
||||
{
|
||||
int my_level = GetCurrentTransactionNestLevel();
|
||||
int my_level;
|
||||
TransInvalidationInfo *myInfo = transInvalInfo;
|
||||
|
||||
/* Quick exit if no messages. */
|
||||
if (myInfo == NULL)
|
||||
return;
|
||||
|
||||
/* Also bail out quickly if messages are not for this level. */
|
||||
my_level = GetCurrentTransactionNestLevel();
|
||||
if (myInfo->my_level != my_level)
|
||||
{
|
||||
Assert(myInfo->my_level < my_level);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCommit)
|
||||
{
|
||||
/* Must be at non-top of stack */
|
||||
Assert(myInfo != NULL && myInfo->parent != NULL);
|
||||
Assert(myInfo->my_level == my_level);
|
||||
|
||||
/* If CurrentCmdInvalidMsgs still has anything, fix it */
|
||||
CommandEndInvalidationMessages();
|
||||
|
||||
/*
|
||||
* We create invalidation stack entries lazily, so the parent might
|
||||
* not have one. Instead of creating one, moving all the data over,
|
||||
* and then freeing our own, we can just adjust the level of our own
|
||||
* entry.
|
||||
*/
|
||||
if (myInfo->parent == NULL || myInfo->parent->my_level < my_level - 1)
|
||||
{
|
||||
myInfo->my_level--;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Pass up my inval messages to parent */
|
||||
AppendInvalidationMessages(&myInfo->parent->PriorCmdInvalidMsgs,
|
||||
&myInfo->PriorCmdInvalidMsgs);
|
||||
@ -986,11 +1012,8 @@ AtEOSubXact_Inval(bool isCommit)
|
||||
/* Need not free anything else explicitly */
|
||||
pfree(myInfo);
|
||||
}
|
||||
else if (myInfo != NULL && myInfo->my_level == my_level)
|
||||
else
|
||||
{
|
||||
/* Must be at non-top of stack */
|
||||
Assert(myInfo->parent != NULL);
|
||||
|
||||
ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
|
||||
LocalExecuteInvalidationMessage);
|
||||
|
||||
@ -1074,6 +1097,12 @@ CacheInvalidateHeapTuple(Relation relation,
|
||||
if (IsToastRelation(relation))
|
||||
return;
|
||||
|
||||
/*
|
||||
* If we're not prepared to queue invalidation messages for this
|
||||
* subtransaction level, get ready now.
|
||||
*/
|
||||
PrepareInvalidationState();
|
||||
|
||||
/*
|
||||
* First let the catcache do its thing
|
||||
*/
|
||||
@ -1159,6 +1188,8 @@ CacheInvalidateCatalog(Oid catalogId)
|
||||
{
|
||||
Oid databaseId;
|
||||
|
||||
PrepareInvalidationState();
|
||||
|
||||
if (IsSharedRelation(catalogId))
|
||||
databaseId = InvalidOid;
|
||||
else
|
||||
@ -1182,6 +1213,8 @@ CacheInvalidateRelcache(Relation relation)
|
||||
Oid databaseId;
|
||||
Oid relationId;
|
||||
|
||||
PrepareInvalidationState();
|
||||
|
||||
relationId = RelationGetRelid(relation);
|
||||
if (relation->rd_rel->relisshared)
|
||||
databaseId = InvalidOid;
|
||||
@ -1202,6 +1235,8 @@ CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
|
||||
Oid databaseId;
|
||||
Oid relationId;
|
||||
|
||||
PrepareInvalidationState();
|
||||
|
||||
relationId = HeapTupleGetOid(classTuple);
|
||||
if (classtup->relisshared)
|
||||
databaseId = InvalidOid;
|
||||
@ -1221,6 +1256,8 @@ CacheInvalidateRelcacheByRelid(Oid relid)
|
||||
{
|
||||
HeapTuple tup;
|
||||
|
||||
PrepareInvalidationState();
|
||||
|
||||
tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "cache lookup failed for relation %u", relid);
|
||||
|
@ -25,10 +25,6 @@ typedef void (*RelcacheCallbackFunction) (Datum arg, Oid relid);
|
||||
|
||||
extern void AcceptInvalidationMessages(void);
|
||||
|
||||
extern void AtStart_Inval(void);
|
||||
|
||||
extern void AtSubStart_Inval(void);
|
||||
|
||||
extern void AtEOXact_Inval(bool isCommit);
|
||||
|
||||
extern void AtEOSubXact_Inval(bool isCommit);
|
||||
|
Loading…
x
Reference in New Issue
Block a user