[PATCH]: Not to invaldiate CatalogSnapshot for local invalidation messages
Hi hackers,
For local invalidation messages, there is no need to call
`InvalidateCatalogSnapshot` to set the CatalogSnapshot to NULL and
rebuild it later. Instead, just update the CatalogSnapshot's `curcid`
in `SnapshotSetCommandId`, this way can make the CatalogSnapshot work
well too.
This optimization can reduce the overhead of rebuilding CatalogSnapshot
after each command.
Best regards, xiaoran
Attachments:
0001-Not-to-invalidate-CatalogSnapshot-for-local-invalida.patchapplication/octet-stream; name=0001-Not-to-invalidate-CatalogSnapshot-for-local-invalida.patchDownload
From 6860176dfe8e0ee8822fda399ff6bbb44ddbb0c5 Mon Sep 17 00:00:00 2001
From: Xiaoran Wang <wxiaoran@vmware.com>
Date: Tue, 5 Dec 2023 15:11:22 +0800
Subject: [PATCH] Not to invalidate CatalogSnapshot for local invalidation
messages
For local invalidation messages, there is no need to call
`InvalidateCatalogSnapshot` to set the CatalogSnapshot to NULL and
rebuild it later. Instead, just update the CatalogSnapshot's curcid
in `SnapshotSetCommandId`, this way can make the CatalogSnapshot work
well too.
This optimization can reduce the overhead of rebuilding CatalogSnapshot
after each command.
---
src/backend/utils/cache/inval.c | 47 ++++++++++++++++++++++++--------
src/backend/utils/time/snapmgr.c | 4 ++-
2 files changed, 39 insertions(+), 12 deletions(-)
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index a041d7d604..8b7e3903c6 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -273,6 +273,11 @@ static struct RELCACHECALLBACK
static int relcache_callback_count = 0;
+
+static inline void LocalExecuteInvalidationMessageIternal(SharedInvalidationMessage *msg,
+ bool localMsg);
+static void LocalExecuteLocalInvalidationMessage(SharedInvalidationMessage *msg);
+
/* ----------------------------------------------------------------
* Invalidation subgroup support functions
* ----------------------------------------------------------------
@@ -696,20 +701,21 @@ InvalidateSystemCachesExtended(bool debug_discard)
}
/*
- * LocalExecuteInvalidationMessage
+ * LocalExecuteInvalidationMessageInternal
*
* Process a single invalidation message (which could be of any type).
* Only the local caches are flushed; this does not transmit the message
* to other backends.
*/
-void
-LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
+static inline void
+LocalExecuteInvalidationMessageIternal(SharedInvalidationMessage *msg, bool localMsg)
{
if (msg->id >= 0)
{
if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == InvalidOid)
{
- InvalidateCatalogSnapshot();
+ if (!localMsg)
+ InvalidateCatalogSnapshot();
SysCacheInvalidate(msg->cc.id, msg->cc.hashValue);
@@ -720,7 +726,8 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
{
if (msg->cat.dbId == MyDatabaseId || msg->cat.dbId == InvalidOid)
{
- InvalidateCatalogSnapshot();
+ if (!localMsg)
+ InvalidateCatalogSnapshot();
CatalogCacheFlushCatalog(msg->cat.catId);
@@ -769,15 +776,33 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
else if (msg->id == SHAREDINVALSNAPSHOT_ID)
{
/* We only care about our own database and shared catalogs */
- if (msg->sn.dbId == InvalidOid)
- InvalidateCatalogSnapshot();
- else if (msg->sn.dbId == MyDatabaseId)
+ if ((msg->sn.dbId == InvalidOid || msg->sn.dbId == MyDatabaseId) && !localMsg)
InvalidateCatalogSnapshot();
}
else
elog(FATAL, "unrecognized SI message ID: %d", msg->id);
}
+/*
+ * Execute InvalidationMessage from other backend
+ */
+
+void
+LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
+{
+ LocalExecuteInvalidationMessageIternal(msg, false);
+}
+
+/*
+ * Execute InvalidationMessage from local backend
+ */
+static void
+LocalExecuteLocalInvalidationMessage(SharedInvalidationMessage *msg)
+{
+ LocalExecuteInvalidationMessageIternal(msg, true);
+}
+
+
/*
* InvalidateSystemCaches
*
@@ -1055,7 +1080,7 @@ AtEOXact_Inval(bool isCommit)
else
{
ProcessInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
- LocalExecuteInvalidationMessage);
+ LocalExecuteLocalInvalidationMessage);
}
/* Need not free anything explicitly */
@@ -1143,7 +1168,7 @@ AtEOSubXact_Inval(bool isCommit)
else
{
ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
- LocalExecuteInvalidationMessage);
+ LocalExecuteLocalInvalidationMessage);
/* Pop the transaction state stack */
transInvalInfo = myInfo->parent;
@@ -1180,7 +1205,7 @@ CommandEndInvalidationMessages(void)
return;
ProcessInvalidationMessages(&transInvalInfo->CurrentCmdInvalidMsgs,
- LocalExecuteInvalidationMessage);
+ LocalExecuteLocalInvalidationMessage);
/* WAL Log per-command invalidation messages for wal_level=logical */
if (XLogLogicalInfoActive())
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 9198850ad2..02842cad0c 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -462,6 +462,9 @@ InvalidateCatalogSnapshotConditionally(void)
void
SnapshotSetCommandId(CommandId curcid)
{
+ if (CatalogSnapshot)
+ CatalogSnapshot->curcid = curcid;
+
if (!FirstSnapshotSet)
return;
@@ -469,7 +472,6 @@ SnapshotSetCommandId(CommandId curcid)
CurrentSnapshot->curcid = curcid;
if (SecondarySnapshot)
SecondarySnapshot->curcid = curcid;
- /* Should we do the same with CatalogSnapshot? */
}
/*
--
2.39.2 (Apple Git-143)
Hi hackers,
I would like to give more details of my patch.
In postgres, it uses a global snapshot “CatalogSnapshot” to check catalog
data visibility.
“CatalogSnapshot” is always updated to the latest version to make the
latest catalog table
content visible.
If there is any updating on catalog tables, to make the changes to be
visible for the following
commands in the current transaction,
“CommandCounterIncrement”-
”AtCCI_LocalCache”
->”CommandEndInvalidationMessages
”->”LocalExecuteInvalidationMessage”
->”InvalidateCatalogSnapshot”
it will invalidate the “CatalogSnapshot” by setting it to NULL. And next
time, when it needs the
“CatalogSnapsthot” and finds it is NULL, it will regenerate one.
In a query, “CommandCounterIncrement” may be called many times, and
“CatalogSnapsthot” may be
destroyed and recreated many times. To reduce such overhead, instead of
invalidating “CatalogSnapshot”
, we can keep it and just increase the “curcid” of it.
When the transaction is committed or aborted, or there are catalog
invalidation messages from other
backends, the “CatalogSnapshot” will be invalidated and regenerated.
Sometimes, the “CatalogSnapshot” is
not the same as the transaction “CurrentSnapshot”, but we can still update
the CatalogSnapshot’s
“curcid”, as the “curcid” only be checked when the tuple is inserted or
deleted by the current transaction.
Xiaoran Wang <fanfuxiaoran@gmail.com> 于2023年12月7日周四 10:13写道:
Show quoted text
Hi hackers,
For local invalidation messages, there is no need to call
`InvalidateCatalogSnapshot` to set the CatalogSnapshot to NULL and
rebuild it later. Instead, just update the CatalogSnapshot's `curcid`
in `SnapshotSetCommandId`, this way can make the CatalogSnapshot work
well too.This optimization can reduce the overhead of rebuilding CatalogSnapshot
after each command.Best regards, xiaoran
Hi
---setup.
drop table s2;
create table s2(a int);
After apply the patch
alter table s2 add primary key (a);
watch CatalogSnapshot
----
#0 GetNonHistoricCatalogSnapshot (relid=1259)
at ../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:412
#1 0x000055ba78f0d6ba in GetCatalogSnapshot (relid=1259)
at ../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:371
#2 0x000055ba785ffbe1 in systable_beginscan
(heapRelation=0x7f256f30b5a8, indexId=2662, indexOK=false,
snapshot=0x0, nkeys=1, key=0x7ffe230f0180)
at ../../Desktop/pg_src/src7/postgresql/src/backend/access/index/genam.c:413
(More stack frames follow...)
-------------------------
Hardware watchpoint 13: CatalogSnapshot
Old value = (Snapshot) 0x55ba7980b6a0 <CatalogSnapshotData>
New value = (Snapshot) 0x0
InvalidateCatalogSnapshot () at
../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:435
435 SnapshotResetXmin();
(gdb) bt 4
#0 InvalidateCatalogSnapshot ()
at ../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:435
#1 0x000055ba78f0ee85 in AtEOXact_Snapshot (isCommit=true, resetXmin=false)
at ../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:1057
#2 0x000055ba7868201b in CommitTransaction ()
at ../../Desktop/pg_src/src7/postgresql/src/backend/access/transam/xact.c:2373
#3 0x000055ba78683495 in CommitTransactionCommand ()
at ../../Desktop/pg_src/src7/postgresql/src/backend/access/transam/xact.c:3061
(More stack frames follow...)
--
but the whole process changes pg_class, pg_index,
pg_attribute,pg_constraint etc.
only one GetCatalogSnapshot and InvalidateCatalogSnapshot seems not correct?
what if there are concurrency changes in the related pg_catalog table.
your patch did pass the isolation test!
I think you patch doing is against following code comments in
src/backend/utils/time/snapmgr.c
/*
* CurrentSnapshot points to the only snapshot taken in transaction-snapshot
* mode, and to the latest one taken in a read-committed transaction.
* SecondarySnapshot is a snapshot that's always up-to-date as of the current
* instant, even in transaction-snapshot mode. It should only be used for
* special-purpose code (say, RI checking.) CatalogSnapshot points to an
* MVCC snapshot intended to be used for catalog scans; we must invalidate it
* whenever a system catalog change occurs.
*
* These SnapshotData structs are static to simplify memory allocation
* (see the hack in GetSnapshotData to avoid repeated malloc/free).
*/
static SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC};
static SnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC};
SnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC};
SnapshotData SnapshotSelfData = {SNAPSHOT_SELF};
SnapshotData SnapshotAnyData = {SNAPSHOT_ANY};
Hi,
Thanks for your reply.
jian he <jian.universality@gmail.com> 于2023年12月18日周一 08:20写道:
Hi
---setup.
drop table s2;
create table s2(a int);After apply the patch
alter table s2 add primary key (a);watch CatalogSnapshot
----
#0 GetNonHistoricCatalogSnapshot (relid=1259)
at
../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:412
#1 0x000055ba78f0d6ba in GetCatalogSnapshot (relid=1259)
at
../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:371
#2 0x000055ba785ffbe1 in systable_beginscan
(heapRelation=0x7f256f30b5a8, indexId=2662, indexOK=false,
snapshot=0x0, nkeys=1, key=0x7ffe230f0180)
at
../../Desktop/pg_src/src7/postgresql/src/backend/access/index/genam.c:413
(More stack frames follow...)-------------------------
Hardware watchpoint 13: CatalogSnapshotOld value = (Snapshot) 0x55ba7980b6a0 <CatalogSnapshotData>
New value = (Snapshot) 0x0
InvalidateCatalogSnapshot () at
../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:435
435 SnapshotResetXmin();
(gdb) bt 4
#0 InvalidateCatalogSnapshot ()
at
../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:435
#1 0x000055ba78f0ee85 in AtEOXact_Snapshot (isCommit=true,
resetXmin=false)
at
../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:1057
#2 0x000055ba7868201b in CommitTransaction ()
at
../../Desktop/pg_src/src7/postgresql/src/backend/access/transam/xact.c:2373
#3 0x000055ba78683495 in CommitTransactionCommand ()
at
../../Desktop/pg_src/src7/postgresql/src/backend/access/transam/xact.c:3061
(More stack frames follow...)--
but the whole process changes pg_class, pg_index,
pg_attribute,pg_constraint etc.
only one GetCatalogSnapshot and InvalidateCatalogSnapshot seems not
correct?
what if there are concurrency changes in the related pg_catalog table.your patch did pass the isolation test!
Yes, I have run the installcheck-world locally, and all the tests passed.
There are two kinds of Invalidation Messages.
One kind is from the local backend, such as what you did in the example
"alter table s2 add primary key (a);", it modifies the pg_class,
pg_attribute ect ,
so it generates some Invalidation Messages to invalidate the "s2" related
tuples in pg_class , pg_attribute ect, and Invalidate Message to invalidate
s2
relation cache. When the command is finished, in the
CommandCounterIncrement,
those Invalidation Messages will be processed to make the system cache work
well for the following commands.
The other kind of Invalidation Messages are from other backends.
Suppose there are two sessions:
session1
---
1: create table foo(a int);
---
session 2
---
1: create table test(a int); (before session1:1)
2: insert into foo values(1); (execute after session1:1)
---
Session1 will generate Invalidation Messages and send them when the
transaction is committed,
and session 2 will accept those Invalidation Messages from session 1 and
then execute
the second command.
Before the patch, Postgres will invalidate the CatalogSnapshot for those
two kinds of Invalidation
Messages. So I did a small optimization in this patch, for local
Invalidation Messages, we don't
call InvalidateCatalogSnapshot, we can use one CatalogSnapshot in a
transaction even if we modify
the catalog and generate Invalidation Messages, as the visibility of the
tuple is identified by the curcid,
as long as we update the curcid of the CatalogSnapshot in
SnapshotSetCommandId,
it can work
correctly.
I think you patch doing is against following code comments in
src/backend/utils/time/snapmgr.c/*
* CurrentSnapshot points to the only snapshot taken in
transaction-snapshot
* mode, and to the latest one taken in a read-committed transaction.
* SecondarySnapshot is a snapshot that's always up-to-date as of the
current
* instant, even in transaction-snapshot mode. It should only be used for
* special-purpose code (say, RI checking.) CatalogSnapshot points to an
* MVCC snapshot intended to be used for catalog scans; we must invalidate
it
* whenever a system catalog change occurs.
*
* These SnapshotData structs are static to simplify memory allocation
* (see the hack in GetSnapshotData to avoid repeated malloc/free).
*/
static SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC};
static SnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC};
SnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC};
SnapshotData SnapshotSelfData = {SNAPSHOT_SELF};
SnapshotData SnapshotAnyData = {SNAPSHOT_ANY};
Thank you for pointing it out, I think I need to update the comment in the
patch too.
Hi,
I updated the comment about the CatalogSnapshot `src/backend/utils/time/
snapmgr.c`
Xiaoran Wang <fanfuxiaoran@gmail.com> 于2023年12月18日周一 15:02写道:
Show quoted text
Hi,
Thanks for your reply.jian he <jian.universality@gmail.com> 于2023年12月18日周一 08:20写道:
Hi
---setup.
drop table s2;
create table s2(a int);After apply the patch
alter table s2 add primary key (a);watch CatalogSnapshot
----
#0 GetNonHistoricCatalogSnapshot (relid=1259)
at
../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:412
#1 0x000055ba78f0d6ba in GetCatalogSnapshot (relid=1259)
at
../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:371
#2 0x000055ba785ffbe1 in systable_beginscan
(heapRelation=0x7f256f30b5a8, indexId=2662, indexOK=false,
snapshot=0x0, nkeys=1, key=0x7ffe230f0180)
at
../../Desktop/pg_src/src7/postgresql/src/backend/access/index/genam.c:413
(More stack frames follow...)-------------------------
Hardware watchpoint 13: CatalogSnapshotOld value = (Snapshot) 0x55ba7980b6a0 <CatalogSnapshotData>
New value = (Snapshot) 0x0
InvalidateCatalogSnapshot () at
../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:435
435 SnapshotResetXmin();
(gdb) bt 4
#0 InvalidateCatalogSnapshot ()
at
../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:435
#1 0x000055ba78f0ee85 in AtEOXact_Snapshot (isCommit=true,
resetXmin=false)
at
../../Desktop/pg_src/src7/postgresql/src/backend/utils/time/snapmgr.c:1057
#2 0x000055ba7868201b in CommitTransaction ()
at
../../Desktop/pg_src/src7/postgresql/src/backend/access/transam/xact.c:2373
#3 0x000055ba78683495 in CommitTransactionCommand ()
at
../../Desktop/pg_src/src7/postgresql/src/backend/access/transam/xact.c:3061
(More stack frames follow...)--
but the whole process changes pg_class, pg_index,
pg_attribute,pg_constraint etc.
only one GetCatalogSnapshot and InvalidateCatalogSnapshot seems not
correct?
what if there are concurrency changes in the related pg_catalog table.your patch did pass the isolation test!
Yes, I have run the installcheck-world locally, and all the tests passed.
There are two kinds of Invalidation Messages.
One kind is from the local backend, such as what you did in the example
"alter table s2 add primary key (a);", it modifies the pg_class,
pg_attribute ect ,
so it generates some Invalidation Messages to invalidate the "s2" related
tuples in pg_class , pg_attribute ect, and Invalidate Message to
invalidate s2
relation cache. When the command is finished, in the
CommandCounterIncrement,
those Invalidation Messages will be processed to make the system cache work
well for the following commands.The other kind of Invalidation Messages are from other backends.
Suppose there are two sessions:
session1
---
1: create table foo(a int);
---
session 2
---
1: create table test(a int); (before session1:1)
2: insert into foo values(1); (execute after session1:1)
---
Session1 will generate Invalidation Messages and send them when the
transaction is committed,
and session 2 will accept those Invalidation Messages from session 1 and
then execute
the second command.Before the patch, Postgres will invalidate the CatalogSnapshot for those
two kinds of Invalidation
Messages. So I did a small optimization in this patch, for local
Invalidation Messages, we don't
call InvalidateCatalogSnapshot, we can use one CatalogSnapshot in a
transaction even if we modify
the catalog and generate Invalidation Messages, as the visibility of the
tuple is identified by the curcid,
as long as we update the curcid of the CatalogSnapshot in SnapshotSetCommandId,
it can work
correctly.I think you patch doing is against following code comments in
src/backend/utils/time/snapmgr.c/*
* CurrentSnapshot points to the only snapshot taken in
transaction-snapshot
* mode, and to the latest one taken in a read-committed transaction.
* SecondarySnapshot is a snapshot that's always up-to-date as of the
current
* instant, even in transaction-snapshot mode. It should only be used for
* special-purpose code (say, RI checking.) CatalogSnapshot points to an
* MVCC snapshot intended to be used for catalog scans; we must
invalidate it
* whenever a system catalog change occurs.
*
* These SnapshotData structs are static to simplify memory allocation
* (see the hack in GetSnapshotData to avoid repeated malloc/free).
*/
static SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC};
static SnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC};
SnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC};
SnapshotData SnapshotSelfData = {SNAPSHOT_SELF};
SnapshotData SnapshotAnyData = {SNAPSHOT_ANY};Thank you for pointing it out, I think I need to update the comment in the
patch too.
Attachments:
v2-0001-Not-to-invalidate-CatalogSnapshot-for-local-inval.patchapplication/octet-stream; name=v2-0001-Not-to-invalidate-CatalogSnapshot-for-local-inval.patchDownload
From 9600d3e13f90ffb0930d9a833072d15184ac342f Mon Sep 17 00:00:00 2001
From: Xiaoran Wang <wxiaoran@vmware.com>
Date: Tue, 5 Dec 2023 15:11:22 +0800
Subject: [PATCH v2] Not to invalidate CatalogSnapshot for local invalidation
messages
For local invalidation messages, there is no need to call
`InvalidateCatalogSnapshot` to set the CatalogSnapshot to NULL and
rebuild it later. Instead, just update the CatalogSnapshot's curcid
in `SnapshotSetCommandId`, this way can make the CatalogSnapshot work
well too.
This optimization can reduce the overhead of rebuilding CatalogSnapshot
after each command.
---
src/backend/utils/cache/inval.c | 47 ++++++++++++++++++++++++--------
src/backend/utils/time/snapmgr.c | 6 ++--
2 files changed, 40 insertions(+), 13 deletions(-)
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index a041d7d604..8b7e3903c6 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -273,6 +273,11 @@ static struct RELCACHECALLBACK
static int relcache_callback_count = 0;
+
+static inline void LocalExecuteInvalidationMessageIternal(SharedInvalidationMessage *msg,
+ bool localMsg);
+static void LocalExecuteLocalInvalidationMessage(SharedInvalidationMessage *msg);
+
/* ----------------------------------------------------------------
* Invalidation subgroup support functions
* ----------------------------------------------------------------
@@ -696,20 +701,21 @@ InvalidateSystemCachesExtended(bool debug_discard)
}
/*
- * LocalExecuteInvalidationMessage
+ * LocalExecuteInvalidationMessageInternal
*
* Process a single invalidation message (which could be of any type).
* Only the local caches are flushed; this does not transmit the message
* to other backends.
*/
-void
-LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
+static inline void
+LocalExecuteInvalidationMessageIternal(SharedInvalidationMessage *msg, bool localMsg)
{
if (msg->id >= 0)
{
if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == InvalidOid)
{
- InvalidateCatalogSnapshot();
+ if (!localMsg)
+ InvalidateCatalogSnapshot();
SysCacheInvalidate(msg->cc.id, msg->cc.hashValue);
@@ -720,7 +726,8 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
{
if (msg->cat.dbId == MyDatabaseId || msg->cat.dbId == InvalidOid)
{
- InvalidateCatalogSnapshot();
+ if (!localMsg)
+ InvalidateCatalogSnapshot();
CatalogCacheFlushCatalog(msg->cat.catId);
@@ -769,15 +776,33 @@ LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
else if (msg->id == SHAREDINVALSNAPSHOT_ID)
{
/* We only care about our own database and shared catalogs */
- if (msg->sn.dbId == InvalidOid)
- InvalidateCatalogSnapshot();
- else if (msg->sn.dbId == MyDatabaseId)
+ if ((msg->sn.dbId == InvalidOid || msg->sn.dbId == MyDatabaseId) && !localMsg)
InvalidateCatalogSnapshot();
}
else
elog(FATAL, "unrecognized SI message ID: %d", msg->id);
}
+/*
+ * Execute InvalidationMessage from other backend
+ */
+
+void
+LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
+{
+ LocalExecuteInvalidationMessageIternal(msg, false);
+}
+
+/*
+ * Execute InvalidationMessage from local backend
+ */
+static void
+LocalExecuteLocalInvalidationMessage(SharedInvalidationMessage *msg)
+{
+ LocalExecuteInvalidationMessageIternal(msg, true);
+}
+
+
/*
* InvalidateSystemCaches
*
@@ -1055,7 +1080,7 @@ AtEOXact_Inval(bool isCommit)
else
{
ProcessInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
- LocalExecuteInvalidationMessage);
+ LocalExecuteLocalInvalidationMessage);
}
/* Need not free anything explicitly */
@@ -1143,7 +1168,7 @@ AtEOSubXact_Inval(bool isCommit)
else
{
ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
- LocalExecuteInvalidationMessage);
+ LocalExecuteLocalInvalidationMessage);
/* Pop the transaction state stack */
transInvalInfo = myInfo->parent;
@@ -1180,7 +1205,7 @@ CommandEndInvalidationMessages(void)
return;
ProcessInvalidationMessages(&transInvalInfo->CurrentCmdInvalidMsgs,
- LocalExecuteInvalidationMessage);
+ LocalExecuteLocalInvalidationMessage);
/* WAL Log per-command invalidation messages for wal_level=logical */
if (XLogLogicalInfoActive())
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 9198850ad2..341d9efa63 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -80,7 +80,7 @@
* instant, even in transaction-snapshot mode. It should only be used for
* special-purpose code (say, RI checking.) CatalogSnapshot points to an
* MVCC snapshot intended to be used for catalog scans; we must invalidate it
- * whenever a system catalog change occurs.
+ * whenever a system catalog change occurs in other backends.
*
* These SnapshotData structs are static to simplify memory allocation
* (see the hack in GetSnapshotData to avoid repeated malloc/free).
@@ -462,6 +462,9 @@ InvalidateCatalogSnapshotConditionally(void)
void
SnapshotSetCommandId(CommandId curcid)
{
+ if (CatalogSnapshot)
+ CatalogSnapshot->curcid = curcid;
+
if (!FirstSnapshotSet)
return;
@@ -469,7 +472,6 @@ SnapshotSetCommandId(CommandId curcid)
CurrentSnapshot->curcid = curcid;
if (SecondarySnapshot)
SecondarySnapshot->curcid = curcid;
- /* Should we do the same with CatalogSnapshot? */
}
/*
--
2.39.2 (Apple Git-143)