Use direct connections instead of the connection pool when patching
Using the regular connection pool unnecessarily pollinates the pool with
connections to databases, most importantly to the template database,
which should not maintain any connections.  Instead of fighting the
pool, connect to Postgres directly while patching.
@@ -854,13 +854,9 @@ class Server(ha_base.ClusterProtocol):
async def _maybe_patch_db(self, dbname, patches):
logger.info("applying patches to database '%s'", dbname)
- conn = await self.acquire_pgcon(dbname)
-
- try:
if dbname != defines.EDGEDB_SYSTEM_DB:
+ async with self._direct_pgcon(dbname) as conn:
await self._maybe_apply_patches(dbname, conn, patches)
- finally:
- self.release_pgcon(dbname, conn)
async def _maybe_patch(self):
"""Apply patches to all the databases"""
@@ -883,7 +879,8 @@ class Server(ha_base.ClusterProtocol):
g.create_task(self._maybe_patch_db(
defines.EDGEDB_TEMPLATE_DB, patches))
- async with self._exclusive_database_access(defines.EDGEDB_TEMPLATE_DB):
+ await self._ensure_database_not_connected(defines.EDGEDB_TEMPLATE_DB)
+
# Patch the system db last. The system db needs to go last so
# that it only gets updated if all of the other databases have
# been succesfully patched. This is important, since we don't check
@@ -1099,7 +1096,6 @@ class Server(ha_base.ClusterProtocol):
raise errors.ExecutionError(
f'database {dbname!r} is being accessed by other users')
else:
- # Block new connections to the database.
self._block_new_connections.add(dbname)
# Prune our inactive connections.
@@ -1143,14 +1139,6 @@ class Server(ha_base.ClusterProtocol):
def _allow_database_connections(self, dbname: str) -> None:
self._block_new_connections.discard(dbname)
- @contextlib.asynccontextmanager
- async def _exclusive_database_access(self, dbname: str):
- await self._ensure_database_not_connected(dbname)
- try:
- yield
- finally:
- self._allow_database_connections(dbname)
-
def _on_after_drop_db(self, dbname: str):
try:
assert self._dbindex is not None
@@ -1265,6 +1253,19 @@ class Server(ha_base.ClusterProtocol):
finally:
self._release_sys_pgcon()
+ @contextlib.asynccontextmanager
+ async def _direct_pgcon(
+ self,
+ dbname: str,
+ ) -> AsyncGenerator[pgcon.PGConnection, None]:
+ conn = None
+ try:
+ conn = await self._pg_connect(dbname)
+ yield conn
+ finally:
+ if conn is not None:
+ await self._pg_disconnect(conn)
+
async def _cancel_pgcon_operation(self, pgcon) -> bool:
async with self._use_sys_pgcon() as syscon:
if pgcon.idle:
