diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index da5638173fd..9ae956759e9 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -800,10 +800,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; - /* * 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 @@ -811,9 +807,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 @@ -825,6 +825,20 @@ 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; + /* * 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