From: Alexander Korotkov Date: Sun, 11 Feb 2024 22:33:44 +0000 (+0200) Subject: Use heap_inplace_update() to unset pg_database.dathasloginevt X-Git-Tag: REL_17_BETA1~903 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8be93177c46b0f6a29a7376229b7ee002066d5f8;p=thirdparty%2Fpostgresql.git 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 --- 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);