aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/utils/init/postinit.c44
1 files changed, 29 insertions, 15 deletions
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index aa67f75c0ca..2fba6b772dc 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
@@ -882,6 +874,28 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
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
* cleanly without creating a mess.