Skip to content

Commit cbf948f

Browse files
committed
JAVA-2651: Ensure that cursor iteration eventually stops when the cursor is closed
1 parent 6f43646 commit cbf948f

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

driver-core/src/main/com/mongodb/operation/QueryBatchCursor.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class QueryBatchCursor<T> implements BatchCursor<T> {
5757
private ServerCursor serverCursor;
5858
private List<T> nextBatch;
5959
private int count;
60-
private boolean closed;
60+
private volatile boolean closed;
6161

6262
QueryBatchCursor(final QueryResult<T> firstQueryResult, final int limit, final int batchSize, final Decoder<T> decoder) {
6363
this(firstQueryResult, limit, batchSize, decoder, null);
@@ -107,6 +107,9 @@ public boolean hasNext() {
107107

108108
while (serverCursor != null) {
109109
getMore();
110+
if (closed) {
111+
throw new IllegalStateException("Cursor has been closed");
112+
}
110113
if (nextBatch != null) {
111114
return true;
112115
}

driver-core/src/test/functional/com/mongodb/operation/QueryBatchCursorFunctionalSpecification.groovy

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,27 @@ class QueryBatchCursorFunctionalSpecification extends OperationFunctionalSpecifi
257257
nextBatch.iterator().next().get('_id') == 2
258258
}
259259

260+
@Category(Slow)
261+
def 'hasNext should throw when cursor is closed in another thread'() {
262+
collectionHelper.create(collectionName, new CreateCollectionOptions().capped(true).sizeInBytes(1000))
263+
collectionHelper.insertDocuments(new DocumentCodec(), new Document('_id', 1).append('ts', new BsonTimestamp(5, 0)))
264+
def firstBatch = executeQuery(new BsonDocument('ts', new BsonDocument('$gte', new BsonTimestamp(5, 0))), 0, 2, true, true);
265+
cursor = new QueryBatchCursor<Document>(firstBatch, 0, 2, new DocumentCodec(), connectionSource)
266+
cursor.next()
267+
268+
// wait a second then close the cursor
269+
new Thread({
270+
sleep(1000)
271+
cursor.close()
272+
} as Runnable).start()
273+
274+
when:
275+
cursor.hasNext()
276+
277+
then:
278+
thrown(Exception)
279+
}
280+
260281
@IgnoreIf({ !serverVersionAtLeast(3, 2) || isSharded() })
261282
@Category(Slow)
262283
def 'test maxTimeMS'() {

0 commit comments

Comments
 (0)