Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5a9325f

Browse files
committed
Fix handling of shared statistics with dropped databases
Dropping a database while a connection is attempted on it was able tolead to the presence of valid database entries in shared statistics.The issue is that MyDatabaseId was getting set too early than it should,as, if the connection attempted on the dropped database fails whenrenamed or dropped, the shutdown callback of the shared statistics wouldfinish by re-inserting a correct entry related to the database alreadydropped.As analyzed by the bug reporters, this issue could lead to phantomentries in the database list maintained by the autovacuum launcher(in rebuild_database_list()) if the database dropped was part of thedatabase list when it was still valid. After the database was dropped,it would remain the highest on the list of databases to considered bythe autovacuum worker as things to process. This would preventautovacuum jobs to happen on all the other databases still present.The commit fixes this issue by delaying setting MyDatabaseId until thedatabase existence has been re-checked with the second scan onpg_database after getting a shared lock on it, and by switchingpgstat_update_dbstats() so as nothing happens if MyDatabaseId is notvalid.Issue introduced by5891c7a, so backpatch down to 15.Reported-by: Will Mortensen, Jacob SpeidelAnalyzed-by: Will Mortensen, Jacob SpeidelAuthor: Andres FreundDiscussion:https://postgr.es/m/17973-bca1f7d5c14f601e@postgresql.orgBackpatch-through: 15
1 parent3daee7f commit5a9325f

File tree

2 files changed

+74
-57
lines changed

2 files changed

+74
-57
lines changed

‎src/backend/utils/activity/pgstat_database.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,13 @@ pgstat_update_dbstats(TimestampTz ts)
268268
{
269269
PgStat_StatDBEntry*dbentry;
270270

271+
/*
272+
* If not connected to a database yet, don't attribute time to "shared
273+
* state" (InvalidOid is used to track stats for shared relations, etc.).
274+
*/
275+
if (!OidIsValid(MyDatabaseId))
276+
return;
277+
271278
dbentry=pgstat_prep_database_pending(MyDatabaseId);
272279

273280
/*
@@ -324,6 +331,12 @@ pgstat_prep_database_pending(Oid dboid)
324331
{
325332
PgStat_EntryRef*entry_ref;
326333

334+
/*
335+
* This should not report stats on database objects before having
336+
* connected to a database.
337+
*/
338+
Assert(!OidIsValid(dboid)||OidIsValid(MyDatabaseId));
339+
327340
entry_ref=pgstat_prep_pending_entry(PGSTAT_KIND_DATABASE,dboid,InvalidOid,
328341
NULL);
329342

‎src/backend/utils/init/postinit.c

Lines changed: 61 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ InitPostgres(const char *in_dbname, Oid dboid,
932932
*/
933933
if (bootstrap)
934934
{
935-
MyDatabaseId=Template1DbOid;
935+
dboid=Template1DbOid;
936936
MyDatabaseTableSpace=DEFAULTTABLESPACE_OID;
937937
}
938938
elseif (in_dbname!=NULL)
@@ -946,32 +946,9 @@ InitPostgres(const char *in_dbname, Oid dboid,
946946
(errcode(ERRCODE_UNDEFINED_DATABASE),
947947
errmsg("database \"%s\" does not exist",in_dbname)));
948948
dbform= (Form_pg_database)GETSTRUCT(tuple);
949-
MyDatabaseId=dbform->oid;
950-
MyDatabaseTableSpace=dbform->dattablespace;
951-
/* take database name from the caller, just for paranoia */
952-
strlcpy(dbname,in_dbname,sizeof(dbname));
949+
dboid=dbform->oid;
953950
}
954-
elseif (OidIsValid(dboid))
955-
{
956-
/* caller specified database by OID */
957-
HeapTupletuple;
958-
Form_pg_databasedbform;
959-
960-
tuple=GetDatabaseTupleByOid(dboid);
961-
if (!HeapTupleIsValid(tuple))
962-
ereport(FATAL,
963-
(errcode(ERRCODE_UNDEFINED_DATABASE),
964-
errmsg("database %u does not exist",dboid)));
965-
dbform= (Form_pg_database)GETSTRUCT(tuple);
966-
MyDatabaseId=dbform->oid;
967-
MyDatabaseTableSpace=dbform->dattablespace;
968-
Assert(MyDatabaseId==dboid);
969-
strlcpy(dbname,NameStr(dbform->datname),sizeof(dbname));
970-
/* pass the database name back to the caller */
971-
if (out_dbname)
972-
strcpy(out_dbname,dbname);
973-
}
974-
else
951+
elseif (!OidIsValid(dboid))
975952
{
976953
/*
977954
* If this is a background worker not bound to any particular
@@ -1009,8 +986,64 @@ InitPostgres(const char *in_dbname, Oid dboid,
1009986
* CREATE DATABASE.
1010987
*/
1011988
if (!bootstrap)
1012-
LockSharedObject(DatabaseRelationId,MyDatabaseId,0,
1013-
RowExclusiveLock);
989+
LockSharedObject(DatabaseRelationId,dboid,0,RowExclusiveLock);
990+
991+
/*
992+
* Recheck pg_database to make sure the target database hasn't gone away.
993+
* If there was a concurrent DROP DATABASE, this ensures we will die
994+
* cleanly without creating a mess.
995+
*/
996+
if (!bootstrap)
997+
{
998+
HeapTupletuple;
999+
Form_pg_databasedatform;
1000+
1001+
tuple=GetDatabaseTupleByOid(dboid);
1002+
if (HeapTupleIsValid(tuple))
1003+
datform= (Form_pg_database)GETSTRUCT(tuple);
1004+
1005+
if (!HeapTupleIsValid(tuple)||
1006+
(in_dbname&&namestrcmp(&datform->datname,in_dbname)))
1007+
{
1008+
if (in_dbname)
1009+
ereport(FATAL,
1010+
(errcode(ERRCODE_UNDEFINED_DATABASE),
1011+
errmsg("database \"%s\" does not exist",in_dbname),
1012+
errdetail("It seems to have just been dropped or renamed.")));
1013+
else
1014+
ereport(FATAL,
1015+
(errcode(ERRCODE_UNDEFINED_DATABASE),
1016+
errmsg("database %u does not exist",dboid)));
1017+
}
1018+
1019+
strlcpy(dbname,NameStr(datform->datname),sizeof(dbname));
1020+
1021+
if (database_is_invalid_form(datform))
1022+
{
1023+
ereport(FATAL,
1024+
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1025+
errmsg("cannot connect to invalid database \"%s\"",dbname),
1026+
errhint("Use DROP DATABASE to drop invalid databases."));
1027+
}
1028+
1029+
MyDatabaseTableSpace=datform->dattablespace;
1030+
/* pass the database name back to the caller */
1031+
if (out_dbname)
1032+
strcpy(out_dbname,dbname);
1033+
}
1034+
1035+
/*
1036+
* Now that we rechecked, we are certain to be connected to a database and
1037+
* thus can set MyDatabaseId.
1038+
*
1039+
* It is important that MyDatabaseId only be set once we are sure that the
1040+
* target database can no longer be concurrently dropped or renamed. For
1041+
* example, without this guarantee, pgstat_update_dbstats() could create
1042+
* entries for databases that were just dropped in the pgstat shutdown
1043+
* callback, which could confuse other code paths like the autovacuum
1044+
* scheduler.
1045+
*/
1046+
MyDatabaseId=dboid;
10141047

10151048
/*
10161049
* Now we can mark our PGPROC entry with the database ID.
@@ -1034,35 +1067,6 @@ InitPostgres(const char *in_dbname, Oid dboid,
10341067
*/
10351068
InvalidateCatalogSnapshot();
10361069

1037-
/*
1038-
* Recheck pg_database to make sure the target database hasn't gone away.
1039-
* If there was a concurrent DROP DATABASE, this ensures we will die
1040-
* cleanly without creating a mess.
1041-
*/
1042-
if (!bootstrap)
1043-
{
1044-
HeapTupletuple;
1045-
Form_pg_databasedatform;
1046-
1047-
tuple=GetDatabaseTuple(dbname);
1048-
if (!HeapTupleIsValid(tuple)||
1049-
MyDatabaseId!= ((Form_pg_database)GETSTRUCT(tuple))->oid||
1050-
MyDatabaseTableSpace!= ((Form_pg_database)GETSTRUCT(tuple))->dattablespace)
1051-
ereport(FATAL,
1052-
(errcode(ERRCODE_UNDEFINED_DATABASE),
1053-
errmsg("database \"%s\" does not exist",dbname),
1054-
errdetail("It seems to have just been dropped or renamed.")));
1055-
1056-
datform= (Form_pg_database)GETSTRUCT(tuple);
1057-
if (database_is_invalid_form(datform))
1058-
{
1059-
ereport(FATAL,
1060-
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1061-
errmsg("cannot connect to invalid database \"%s\"",dbname),
1062-
errhint("Use DROP DATABASE to drop invalid databases."));
1063-
}
1064-
}
1065-
10661070
/*
10671071
* Now we should be able to access the database directory safely. Verify
10681072
* it's there and looks reasonable.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp