Обсуждение: [PATCH]: Not to invaldiate CatalogSnapshot for local invalidation messages

Поиск
Список
Период
Сортировка

[PATCH]: Not to invaldiate CatalogSnapshot for local invalidation messages

От
Xiaoran Wang
Дата:

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
Вложения

Re: [PATCH]: Not to invaldiate CatalogSnapshot for local invalidation messages

От
Xiaoran Wang
Дата:
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写道:

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

Re: [PATCH]: Not to invaldiate CatalogSnapshot for local invalidation messages

От
jian he
Дата:
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};



Re: [PATCH]: Not to invaldiate CatalogSnapshot for local invalidation messages

От
Xiaoran Wang
Дата:
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: 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!
 
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. 

Re: [PATCH]: Not to invaldiate CatalogSnapshot for local invalidation messages

От
Xiaoran Wang
Дата:
Hi,
I updated the comment about the CatalogSnapshot `src/backend/utils/time/snapmgr.c`

Xiaoran Wang <fanfuxiaoran@gmail.com> 于2023年12月18日周一 15:02写道:
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: 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!
 
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. 
Вложения