aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2014-10-29 12:35:19 -0400
committerRobert Haas <rhaas@postgresql.org>2014-10-29 12:35:19 -0400
commit6cb4afff33ba0b6f88cca2967904ad501d648e2f (patch)
treed5e34a8844cb3c6df5f8d97ed803ced5f851634b
parent8f8314b56003877185fb817c847c7c9609621d0c (diff)
downloadpostgresql-6cb4afff33ba0b6f88cca2967904ad501d648e2f.tar.gz
postgresql-6cb4afff33ba0b6f88cca2967904ad501d648e2f.zip
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.
-rw-r--r--src/backend/access/transam/xact.c2
-rw-r--r--src/backend/utils/cache/inval.c125
-rw-r--r--src/include/utils/inval.h4
3 files changed, 81 insertions, 50 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 5b5d31b33dc..651a5c40f46 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -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();
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index a7a768efa61..6b6c88eaf0f 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -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;
}
/*
@@ -727,24 +740,6 @@ PostPrepare_Inval(void)
}
/*
- * 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.
*/
static void
@@ -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;
- 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 != NULL && myInfo->parent != NULL);
- Assert(myInfo->my_level == my_level);
+ Assert(myInfo->my_level < my_level);
+ return;
+ }
+ if (isCommit)
+ {
/* 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);
@@ -1075,6 +1098,12 @@ CacheInvalidateHeapTuple(Relation 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
*/
tupleRelId = RelationGetRelid(relation);
@@ -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);
diff --git a/src/include/utils/inval.h b/src/include/utils/inval.h
index 6156e0219d0..9842b698d6a 100644
--- a/src/include/utils/inval.h
+++ b/src/include/utils/inval.h
@@ -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);