From b00584b892db05dbef286c69057a02a62207a021 Mon Sep 17 00:00:00 2001 From: Shane Harvey Date: Tue, 15 Aug 2017 14:58:05 -0700 Subject: [PATCH] PYTHON-1353 Kill cursors synchronously in CommandCursor.close. --- pymongo/command_cursor.py | 20 ++++++++++++-------- pymongo/cursor.py | 4 +--- test/test_client.py | 4 ++++ test/test_cursor.py | 15 +++++++++++---- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/pymongo/command_cursor.py b/pymongo/command_cursor.py index 337740e87..3f98e110b 100644 --- a/pymongo/command_cursor.py +++ b/pymongo/command_cursor.py @@ -48,20 +48,24 @@ class CommandCursor(object): if self.__id and not self.__killed: self.__die() - def __die(self): + def __die(self, synchronous=False): """Closes this cursor. """ if self.__id and not self.__killed: - self.__collection.database.client.close_cursor( - self.__id, _CursorAddress(self.__address, self.__ns)) + address = _CursorAddress( + self.__address, self.__collection.full_name) + if synchronous: + self.__collection.database.client._close_cursor_now( + self.__id, address) + else: + self.__collection.database.client.close_cursor( + self.__id, address) self.__killed = True def close(self): - """Explicitly close / kill this cursor. Required for PyPy, Jython and - other Python implementations that don't use reference counting - garbage collection. + """Explicitly close / kill this cursor. """ - self.__die() + self.__die(True) def batch_size(self, batch_size): """Limits the number of documents returned in one batch. Each batch @@ -242,4 +246,4 @@ class CommandCursor(object): return self def __exit__(self, exc_type, exc_val, exc_tb): - self.__die() + self.close() diff --git a/pymongo/cursor.py b/pymongo/cursor.py index 11137bf8a..e9e1f7314 100644 --- a/pymongo/cursor.py +++ b/pymongo/cursor.py @@ -294,9 +294,7 @@ class Cursor(object): self.__killed = True def close(self): - """Explicitly close / kill this cursor. Required for PyPy, Jython and - other Python implementations that don't use reference counting - garbage collection. + """Explicitly close / kill this cursor. """ self.__die(True) diff --git a/test/test_client.py b/test/test_client.py index 19707a936..87232bd91 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -534,6 +534,10 @@ class TestClient(IntegrationTest): cursor = coll.find().batch_size(10) self.assertTrue(bool(next(cursor))) self.assertLess(cursor.retrieved, docs_inserted) + + # Open a command cursor and leave it open on the server. + cursor = coll.aggregate([], batchSize=10) + self.assertTrue(bool(next(cursor))) del cursor # Required for PyPy, Jython and other Python implementations that # don't use reference counting garbage collection. diff --git a/test/test_cursor.py b/test/test_cursor.py index ed49b3f4d..7b863e4d7 100644 --- a/test/test_cursor.py +++ b/test/test_cursor.py @@ -1302,17 +1302,24 @@ class TestCursor(IntegrationTest): results.clear() - # Close the cursor while it's still open on the server. + # Close a cursor while it's still open on the server. cursor = coll.find().batch_size(10) self.assertTrue(bool(next(cursor))) self.assertLess(cursor.retrieved, docs_inserted) cursor.close() - # Test that the cursor was closed. - self.assertEqual(1, len(results["started"])) + # Close a command cursor while it's still open on the server. + cursor = coll.aggregate([], batchSize=10) + self.assertTrue(bool(next(cursor))) + cursor.close() + + # Test that both cursors were closed. + self.assertEqual(2, len(results["started"])) self.assertEqual("killCursors", results["started"][0].command_name) - self.assertEqual(1, len(results["succeeded"])) + self.assertEqual("killCursors", results["started"][1].command_name) + self.assertEqual(2, len(results["succeeded"])) self.assertEqual("killCursors", results["succeeded"][0].command_name) + self.assertEqual("killCursors", results["succeeded"][1].command_name) if __name__ == "__main__":