tablecmds: Open pg_class only when an update is required

Started by Chao Liabout 1 month ago3 messages
#1Chao Li
li.evan.chao@gmail.com
1 attachment(s)

Hi Hackers,

I just noticed that relation_mark_replica_identity() unconditionally opened
pg_class with RowExclusiveLock even in cases where relreplident has no
change, which incurred unnecessary relation opens, lock acquisition.

I just made a tiny refactor that defers opening pg_class until we know that
an update to relreplident is required.

I have manually tested the change, and "make check" passed.

Best regards,
Chao Li (Evan)
---------------------
HighGo Software Co., Ltd.
https://www.highgo.com/

Attachments:

v1-0001-tablecmds-Open-pg_class-only-when-an-update-is-re.patchapplication/octet-stream; name=v1-0001-tablecmds-Open-pg_class-only-when-an-update-is-re.patchDownload
From d8a16e8c640db8781729912089af366e16687d08 Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <lic@highgo.com>
Date: Thu, 11 Dec 2025 15:08:00 +0800
Subject: [PATCH v1] tablecmds: Open pg_class only when an update is required

relation_mark_replica_identity() previously opened pg_class with
RowExclusiveLock unconditionally, even in cases where relreplident
did not change. This incurred unnecessary relation opens, lock
acquisition, and syscache lookups.

Refactor the code to defer opening pg_class until we know that an
update to relreplident is required. This reduces overhead on the
common path where no catalog modification is needed, without changing
any visible behavior.

Author: Chao Li <lic@highgo.com>
---
 src/backend/commands/tablecmds.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1c9ef53be20..c2f34ceaa96 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -18393,7 +18393,6 @@ relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
 							   bool is_internal)
 {
 	Relation	pg_index;
-	Relation	pg_class;
 	HeapTuple	pg_class_tuple;
 	HeapTuple	pg_index_tuple;
 	Form_pg_class pg_class_form;
@@ -18403,7 +18402,7 @@ relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
 	/*
 	 * Check whether relreplident has changed, and update it if so.
 	 */
-	pg_class = table_open(RelationRelationId, RowExclusiveLock);
+
 	pg_class_tuple = SearchSysCacheCopy1(RELOID,
 										 ObjectIdGetDatum(RelationGetRelid(rel)));
 	if (!HeapTupleIsValid(pg_class_tuple))
@@ -18412,10 +18411,12 @@ relation_mark_replica_identity(Relation rel, char ri_type, Oid indexOid,
 	pg_class_form = (Form_pg_class) GETSTRUCT(pg_class_tuple);
 	if (pg_class_form->relreplident != ri_type)
 	{
+		Relation	pg_class = table_open(RelationRelationId, RowExclusiveLock);
+
 		pg_class_form->relreplident = ri_type;
 		CatalogTupleUpdate(pg_class, &pg_class_tuple->t_self, pg_class_tuple);
+		table_close(pg_class, RowExclusiveLock);
 	}
-	table_close(pg_class, RowExclusiveLock);
 	heap_freetuple(pg_class_tuple);
 
 	/*
-- 
2.39.5 (Apple Git-154)

#2Ashutosh Bapat
ashutosh.bapat.oss@gmail.com
In reply to: Chao Li (#1)
Re: tablecmds: Open pg_class only when an update is required

On Thu, Dec 11, 2025 at 12:45 PM Chao Li <li.evan.chao@gmail.com> wrote:

Hi Hackers,

I just noticed that relation_mark_replica_identity() unconditionally opened pg_class with RowExclusiveLock even in cases where relreplident has no change, which incurred unnecessary relation opens, lock acquisition.

I just made a tiny refactor that defers opening pg_class until we know that an update to relreplident is required.

I think we need to lock the relation before fetching the tuple so that
the field being read remains consistent. Instead of upgrading the lock
which can deadlock, we get hold of row exclusive lock right at the
beginning.

--
Best Wishes,
Ashutosh Bapat

#3Chao Li
li.evan.chao@gmail.com
In reply to: Ashutosh Bapat (#2)
Re: tablecmds: Open pg_class only when an update is required

On Dec 11, 2025, at 21:17, Ashutosh Bapat <ashutosh.bapat.oss@gmail.com> wrote:

On Thu, Dec 11, 2025 at 12:45 PM Chao Li <li.evan.chao@gmail.com> wrote:

Hi Hackers,

I just noticed that relation_mark_replica_identity() unconditionally opened pg_class with RowExclusiveLock even in cases where relreplident has no change, which incurred unnecessary relation opens, lock acquisition.

I just made a tiny refactor that defers opening pg_class until we know that an update to relreplident is required.

I think we need to lock the relation before fetching the tuple so that
the field being read remains consistent. Instead of upgrading the lock
which can deadlock, we get hold of row exclusive lock right at the
beginning.

--
Best Wishes,
Ashutosh Bapat

Hi Ashutosh,

Thanks for the explanation, so I withdraw this patch.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/