Commit 6cb4afff authored by Robert Haas's avatar Robert Haas

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.
parent 8f8314b5
...@@ -1838,7 +1838,6 @@ StartTransaction(void) ...@@ -1838,7 +1838,6 @@ StartTransaction(void)
* initialize other subsystems for new transaction * initialize other subsystems for new transaction
*/ */
AtStart_GUC(); AtStart_GUC();
AtStart_Inval();
AtStart_Cache(); AtStart_Cache();
AfterTriggerBeginXact(); AfterTriggerBeginXact();
...@@ -4151,7 +4150,6 @@ StartSubTransaction(void) ...@@ -4151,7 +4150,6 @@ StartSubTransaction(void)
*/ */
AtSubStart_Memory(); AtSubStart_Memory();
AtSubStart_ResourceOwner(); AtSubStart_ResourceOwner();
AtSubStart_Inval();
AtSubStart_Notify(); AtSubStart_Notify();
AfterTriggerBeginSubXact(); AfterTriggerBeginSubXact();
......
...@@ -693,19 +693,32 @@ AcceptInvalidationMessages(void) ...@@ -693,19 +693,32 @@ AcceptInvalidationMessages(void)
} }
/* /*
* AtStart_Inval * PrepareInvalidationState
* Initialize inval lists at start of a main transaction. * Initialize inval lists for the current (sub)transaction.
*/ */
void static void
AtStart_Inval(void) PrepareInvalidationState(void)
{ {
Assert(transInvalInfo == NULL); TransInvalidationInfo *myInfo;
transInvalInfo = (TransInvalidationInfo *)
if (transInvalInfo != NULL &&
transInvalInfo->my_level == GetCurrentTransactionNestLevel())
return;
myInfo = (TransInvalidationInfo *)
MemoryContextAllocZero(TopTransactionContext, MemoryContextAllocZero(TopTransactionContext,
sizeof(TransInvalidationInfo)); sizeof(TransInvalidationInfo));
transInvalInfo->my_level = GetCurrentTransactionNestLevel(); myInfo->parent = transInvalInfo;
SharedInvalidMessagesArray = NULL; myInfo->my_level = GetCurrentTransactionNestLevel();
numSharedInvalidMessagesArray = 0;
/*
* 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) ...@@ -726,24 +739,6 @@ PostPrepare_Inval(void)
AtEOXact_Inval(false); 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. * Collect invalidation messages into SharedInvalidMessagesArray array.
*/ */
...@@ -803,8 +798,16 @@ xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs, ...@@ -803,8 +798,16 @@ xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
{ {
MemoryContext oldcontext; 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 */ /* 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 * Relcache init file invalidation requires processing both before and
...@@ -904,11 +907,15 @@ ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs, ...@@ -904,11 +907,15 @@ ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
void void
AtEOXact_Inval(bool isCommit) 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) if (isCommit)
{ {
/* Must be at top of stack */
Assert(transInvalInfo != NULL && transInvalInfo->parent == NULL);
/* /*
* Relcache init file invalidation requires processing both before and * Relcache init file invalidation requires processing both before and
* after we send the SI messages. However, we need not do anything * after we send the SI messages. However, we need not do anything
...@@ -926,17 +933,16 @@ AtEOXact_Inval(bool isCommit) ...@@ -926,17 +933,16 @@ AtEOXact_Inval(bool isCommit)
if (transInvalInfo->RelcacheInitFileInval) if (transInvalInfo->RelcacheInitFileInval)
RelationCacheInitFilePostInvalidate(); RelationCacheInitFilePostInvalidate();
} }
else if (transInvalInfo != NULL) else
{ {
/* Must be at top of stack */
Assert(transInvalInfo->parent == NULL);
ProcessInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs, ProcessInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
LocalExecuteInvalidationMessage); LocalExecuteInvalidationMessage);
} }
/* Need not free anything explicitly */ /* Need not free anything explicitly */
transInvalInfo = NULL; transInvalInfo = NULL;
SharedInvalidMessagesArray = NULL;
numSharedInvalidMessagesArray = 0;
} }
/* /*
...@@ -960,18 +966,38 @@ AtEOXact_Inval(bool isCommit) ...@@ -960,18 +966,38 @@ AtEOXact_Inval(bool isCommit)
void void
AtEOSubXact_Inval(bool isCommit) AtEOSubXact_Inval(bool isCommit)
{ {
int my_level = GetCurrentTransactionNestLevel(); int my_level;
TransInvalidationInfo *myInfo = transInvalInfo; TransInvalidationInfo *myInfo = transInvalInfo;
if (isCommit) /* 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)
{ {
/* Must be at non-top of stack */ Assert(myInfo->my_level < my_level);
Assert(myInfo != NULL && myInfo->parent != NULL); return;
Assert(myInfo->my_level == my_level); }
if (isCommit)
{
/* If CurrentCmdInvalidMsgs still has anything, fix it */ /* If CurrentCmdInvalidMsgs still has anything, fix it */
CommandEndInvalidationMessages(); 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 */ /* Pass up my inval messages to parent */
AppendInvalidationMessages(&myInfo->parent->PriorCmdInvalidMsgs, AppendInvalidationMessages(&myInfo->parent->PriorCmdInvalidMsgs,
&myInfo->PriorCmdInvalidMsgs); &myInfo->PriorCmdInvalidMsgs);
...@@ -986,11 +1012,8 @@ AtEOSubXact_Inval(bool isCommit) ...@@ -986,11 +1012,8 @@ AtEOSubXact_Inval(bool isCommit)
/* Need not free anything else explicitly */ /* Need not free anything else explicitly */
pfree(myInfo); 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, ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
LocalExecuteInvalidationMessage); LocalExecuteInvalidationMessage);
...@@ -1074,6 +1097,12 @@ CacheInvalidateHeapTuple(Relation relation, ...@@ -1074,6 +1097,12 @@ CacheInvalidateHeapTuple(Relation relation,
if (IsToastRelation(relation)) if (IsToastRelation(relation))
return; 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 * First let the catcache do its thing
*/ */
...@@ -1159,6 +1188,8 @@ CacheInvalidateCatalog(Oid catalogId) ...@@ -1159,6 +1188,8 @@ CacheInvalidateCatalog(Oid catalogId)
{ {
Oid databaseId; Oid databaseId;
PrepareInvalidationState();
if (IsSharedRelation(catalogId)) if (IsSharedRelation(catalogId))
databaseId = InvalidOid; databaseId = InvalidOid;
else else
...@@ -1182,6 +1213,8 @@ CacheInvalidateRelcache(Relation relation) ...@@ -1182,6 +1213,8 @@ CacheInvalidateRelcache(Relation relation)
Oid databaseId; Oid databaseId;
Oid relationId; Oid relationId;
PrepareInvalidationState();
relationId = RelationGetRelid(relation); relationId = RelationGetRelid(relation);
if (relation->rd_rel->relisshared) if (relation->rd_rel->relisshared)
databaseId = InvalidOid; databaseId = InvalidOid;
...@@ -1202,6 +1235,8 @@ CacheInvalidateRelcacheByTuple(HeapTuple classTuple) ...@@ -1202,6 +1235,8 @@ CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
Oid databaseId; Oid databaseId;
Oid relationId; Oid relationId;
PrepareInvalidationState();
relationId = HeapTupleGetOid(classTuple); relationId = HeapTupleGetOid(classTuple);
if (classtup->relisshared) if (classtup->relisshared)
databaseId = InvalidOid; databaseId = InvalidOid;
...@@ -1221,6 +1256,8 @@ CacheInvalidateRelcacheByRelid(Oid relid) ...@@ -1221,6 +1256,8 @@ CacheInvalidateRelcacheByRelid(Oid relid)
{ {
HeapTuple tup; HeapTuple tup;
PrepareInvalidationState();
tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "cache lookup failed for relation %u", relid); elog(ERROR, "cache lookup failed for relation %u", relid);
......
...@@ -25,10 +25,6 @@ typedef void (*RelcacheCallbackFunction) (Datum arg, Oid relid); ...@@ -25,10 +25,6 @@ typedef void (*RelcacheCallbackFunction) (Datum arg, Oid relid);
extern void AcceptInvalidationMessages(void); extern void AcceptInvalidationMessages(void);
extern void AtStart_Inval(void);
extern void AtSubStart_Inval(void);
extern void AtEOXact_Inval(bool isCommit); extern void AtEOXact_Inval(bool isCommit);
extern void AtEOSubXact_Inval(bool isCommit); extern void AtEOSubXact_Inval(bool isCommit);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment