From 8be93177c46b0f6a29a7376229b7ee002066d5f8 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Mon, 12 Feb 2024 00:33:44 +0200 Subject: [PATCH] Use heap_inplace_update() to unset pg_database.dathasloginevt Doing this instead of regular updates serves two purposes. First, that avoids possible waiting on the row-level lock. Second, that avoids dealing with TOAST. It's known that changes made by heap_inplace_update() may be lost due to concurrent normal updates. However, we are OK with that. The subsequent connections will still have a chance to set "dathasloginevt" to false. Reported-by: Alexander Lakhin Discussion: https://postgr.es/m/e2a0248e-5f32-af0c-9832-a90d303c2c61%40gmail.com --- src/backend/commands/event_trigger.c | 36 ++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index f193c7ddf60..c8b662131c3 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -13,6 +13,7 @@ */ #include "postgres.h" +#include "access/heapam.h" #include "access/htup_details.h" #include "access/table.h" #include "access/xact.h" @@ -943,18 +944,45 @@ EventTriggerOnLogin(void) Relation pg_db = table_open(DatabaseRelationId, RowExclusiveLock); HeapTuple tuple; Form_pg_database db; + ScanKeyData key[1]; + SysScanDesc scan; - tuple = SearchSysCacheCopy1(DATABASEOID, - ObjectIdGetDatum(MyDatabaseId)); + /* + * Get the pg_database tuple to scribble on. Note that this does + * not directly rely on the syscache to avoid issues with + * flattened toast values for the in-place update. + */ + ScanKeyInit(&key[0], + Anum_pg_database_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(MyDatabaseId)); + + scan = systable_beginscan(pg_db, DatabaseOidIndexId, true, + NULL, 1, key); + tuple = systable_getnext(scan); + tuple = heap_copytuple(tuple); + systable_endscan(scan); if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for database %u", MyDatabaseId); + elog(ERROR, "could not find tuple for database %u", MyDatabaseId); db = (Form_pg_database) GETSTRUCT(tuple); if (db->dathasloginevt) { db->dathasloginevt = false; - CatalogTupleUpdate(pg_db, &tuple->t_self, tuple); + + /* + * Do an "in place" update of the pg_database tuple. Doing + * this instead of regular updates serves two purposes. First, + * that avoids possible waiting on the row-level lock. Second, + * that avoids dealing with TOAST. + * + * It's known that changes made by heap_inplace_update() may + * be lost due to concurrent normal updates. However, we are + * OK with that. The subsequent connections will still have a + * chance to set "dathasloginevt" to false. + */ + heap_inplace_update(pg_db, tuple); } table_close(pg_db, RowExclusiveLock); heap_freetuple(tuple); -- 2.39.5