Skip to content

Commit 2037b16

Browse files
committed
Improve performance by caching MongoClient
1 parent 9ce9ef3 commit 2037b16

File tree

3 files changed

+30
-8
lines changed

3 files changed

+30
-8
lines changed

django_mongodb_backend/base.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class DatabaseWrapper(BaseDatabaseWrapper):
8989
"endswith": "LIKE '%%' || {}",
9090
"iendswith": "LIKE '%%' || UPPER({})",
9191
}
92+
_connection_pools = {}
9293

9394
def _isnull_operator(a, b):
9495
is_null = {
@@ -176,7 +177,12 @@ def get_connection_params(self):
176177

177178
@async_unsafe
178179
def get_new_connection(self, conn_params):
179-
return MongoClient(**conn_params, driver=self._driver_info())
180+
if self.alias not in self._connection_pools:
181+
conn = MongoClient(**conn_params, driver=self._driver_info())
182+
# setdefault() ensures that multiple threads don't set this in
183+
# parallel.
184+
self._connection_pools.setdefault(self.alias, conn)
185+
return self._connection_pools[self.alias]
180186

181187
def _driver_info(self):
182188
if not os.environ.get("RUNNING_DJANGOS_TEST_SUITE"):
@@ -189,14 +195,23 @@ def _commit(self):
189195
def _rollback(self):
190196
pass
191197

192-
def set_autocommit(self, autocommit, force_begin_transaction_with_broken_autocommit=False):
193-
self.autocommit = autocommit
198+
def _close(self):
199+
# MongoClient is a connection pool and, unlike database drivers that
200+
# implement PEP 249, shouldn't be closed by connection.close().
201+
pass
194202

195-
@async_unsafe
196-
def close(self):
197-
super().close()
203+
def close_pool(self):
204+
connection = self.connection
205+
# Remove any reference to the connection.
206+
self.connection = None
198207
with contextlib.suppress(AttributeError):
199208
del self.database
209+
del self._connection_pools[self.alias]
210+
# Then close it.
211+
connection.close()
212+
213+
def set_autocommit(self, autocommit, force_begin_transaction_with_broken_autocommit=False):
214+
self.autocommit = autocommit
200215

201216
@async_unsafe
202217
def cursor(self):

django_mongodb_backend/features.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ class DatabaseFeatures(BaseDatabaseFeatures):
7575
# Connection creation doesn't follow the usual Django API.
7676
"backends.tests.ThreadTests.test_pass_connection_between_threads",
7777
"backends.tests.ThreadTests.test_default_connection_thread_local",
78+
# Disallowed query protection doesn't work because this backend doesn't
79+
# use cursor(), chunked_cursor(), etc.
80+
# https://github.com/django/django/blob/045110ff3089aefd9c3e65c707df465bacfed986/django/test/testcases.py#L195-L206
81+
"test_utils.test_testcase.TestTestCase.test_disallowed_database_queries",
82+
"test_utils.test_transactiontestcase.DisallowedDatabaseQueriesTests.test_disallowed_database_queries",
83+
"test_utils.tests.DisallowedDatabaseQueriesTests.test_disallowed_database_chunked_cursor_queries",
84+
"test_utils.tests.DisallowedDatabaseQueriesTests.test_disallowed_database_queries",
7885
"test_utils.tests.DisallowedDatabaseQueriesTests.test_disallowed_thread_database_connection",
7986
# Object of type ObjectId is not JSON serializable.
8087
"auth_tests.test_views.LoginTest.test_login_session_without_hash_session_key",

tests/backend_/test_base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ def receiver(sender, connection, **kwargs): # noqa: ARG001
3333
data["database"] = connection.database
3434

3535
connection_created.connect(receiver)
36-
connection.close()
36+
connection.close_pool()
3737
# Accessing database implicitly connects.
3838
connection.database # noqa: B018
3939
self.assertIs(data["database"], connection.database)
40-
connection.close()
40+
connection.close_pool()
4141
connection_created.disconnect(receiver)
4242
data.clear()
4343
connection.connect()

0 commit comments

Comments
 (0)