diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index aa67f75c0c..2fba6b772d 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -848,18 +848,6 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, strcpy(out_dbname, dbname); } - /* Now we can mark our PGPROC entry with the database ID */ - /* (We assume this is an atomic store so no lock is needed) */ - MyProc->databaseId = MyDatabaseId; - - /* - * We established a catalog snapshot while reading pg_authid and/or - * pg_database; but until we have set up MyDatabaseId, we won't react to - * incoming sinval messages for unshared catalogs, so we won't realize it - * if the snapshot has been invalidated. Assume it's no good anymore. - */ - InvalidateCatalogSnapshot(); - /* * Now, take a writer's lock on the database we are trying to connect to. * If there is a concurrently running DROP DATABASE on that database, this @@ -867,9 +855,13 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, * pg_database). * * Note that the lock is not held long, only until the end of this startup - * transaction. This is OK since we are already advertising our use of - * the database in the PGPROC array; anyone trying a DROP DATABASE after - * this point will see us there. + * transaction. This is OK since we will advertise our use of the + * database in the ProcArray before dropping the lock (in fact, that's the + * next thing to do). Anyone trying a DROP DATABASE after this point will + * see us in the array once they have the lock. Ordering is important for + * this because we don't want to advertise ourselves as being in this + * database until we have the lock; otherwise we create what amounts to a + * deadlock with CountOtherDBBackends(). * * Note: use of RowExclusiveLock here is reasonable because we envision * our session as being a concurrent writer of the database. If we had a @@ -881,6 +873,28 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, LockSharedObject(DatabaseRelationId, MyDatabaseId, 0, RowExclusiveLock); + /* + * Now we can mark our PGPROC entry with the database ID. + * + * We assume this is an atomic store so no lock is needed; though actually + * things would work fine even if it weren't atomic. Anyone searching the + * ProcArray for this database's ID should hold the database lock, so they + * would not be executing concurrently with this store. A process looking + * for another database's ID could in theory see a chance match if it read + * a partially-updated databaseId value; but as long as all such searches + * wait and retry, as in CountOtherDBBackends(), they will certainly see + * the correct value on their next try. + */ + MyProc->databaseId = MyDatabaseId; + + /* + * We established a catalog snapshot while reading pg_authid and/or + * pg_database; but until we have set up MyDatabaseId, we won't react to + * incoming sinval messages for unshared catalogs, so we won't realize it + * if the snapshot has been invalidated. Assume it's no good anymore. + */ + InvalidateCatalogSnapshot(); + /* * Recheck pg_database to make sure the target database hasn't gone away. * If there was a concurrent DROP DATABASE, this ensures we will die