@@ -70,9 +70,15 @@ _mongoc_cursor_new (mongoc_client_t *client,
70
70
71
71
ENTRY ;
72
72
73
- bson_return_val_if_fail (client , NULL );
74
- bson_return_val_if_fail (db_and_collection , NULL );
75
- bson_return_val_if_fail (query , NULL );
73
+ BSON_ASSERT (client );
74
+ BSON_ASSERT (db_and_collection );
75
+ BSON_ASSERT (query );
76
+
77
+ /* we can't have exhaust queries with limits */
78
+ BSON_ASSERT (!((flags & MONGOC_QUERY_EXHAUST ) && limit ));
79
+
80
+ /* we can't have exhaust queries with sharded clusters */
81
+ BSON_ASSERT (!((flags & MONGOC_QUERY_EXHAUST ) && client -> cluster .isdbgrid ));
76
82
77
83
/*
78
84
* Cursors execute their query lazily. This sadly means that we must copy
@@ -180,7 +186,15 @@ _mongoc_cursor_destroy (mongoc_cursor_t *cursor)
180
186
181
187
bson_return_if_fail (cursor );
182
188
183
- if (cursor -> rpc .reply .cursor_id ) {
189
+ if (cursor -> in_exhaust ) {
190
+ cursor -> client -> in_exhaust = FALSE;
191
+
192
+ if (!cursor -> done ) {
193
+ _mongoc_cluster_disconnect_node (
194
+ & cursor -> client -> cluster ,
195
+ & cursor -> client -> cluster .nodes [cursor -> hint - 1 ]);
196
+ }
197
+ } else if (cursor -> rpc .reply .cursor_id ) {
184
198
_mongoc_cursor_kill_cursor (cursor , cursor -> rpc .reply .cursor_id );
185
199
}
186
200
@@ -361,6 +375,11 @@ _mongoc_cursor_query (mongoc_cursor_t *cursor)
361
375
cursor -> reader = bson_reader_new_from_data (cursor -> rpc .reply .documents ,
362
376
cursor -> rpc .reply .documents_len );
363
377
378
+ if (cursor -> flags & MONGOC_QUERY_EXHAUST ) {
379
+ cursor -> in_exhaust = TRUE;
380
+ cursor -> client -> in_exhaust = TRUE;
381
+ }
382
+
364
383
cursor -> done = FALSE;
365
384
cursor -> end_of_event = FALSE;
366
385
cursor -> sent = TRUE;
@@ -382,53 +401,57 @@ _mongoc_cursor_get_more (mongoc_cursor_t *cursor)
382
401
383
402
ENTRY ;
384
403
385
- bson_return_val_if_fail (cursor , FALSE );
404
+ BSON_ASSERT (cursor );
386
405
387
- if (!_mongoc_client_warm_up (cursor -> client , & cursor -> error )) {
388
- cursor -> failed = TRUE;
389
- RETURN (FALSE);
390
- }
406
+ if (! cursor -> in_exhaust ) {
407
+ if (!_mongoc_client_warm_up (cursor -> client , & cursor -> error )) {
408
+ cursor -> failed = TRUE;
409
+ RETURN (FALSE);
410
+ }
391
411
392
- if (!(cursor_id = cursor -> rpc .reply .cursor_id )) {
393
- bson_set_error (& cursor -> error ,
394
- MONGOC_ERROR_CURSOR ,
395
- MONGOC_ERROR_CURSOR_INVALID_CURSOR ,
396
- "No valid cursor was provided." );
397
- goto failure ;
398
- }
412
+ if (!(cursor_id = cursor -> rpc .reply .cursor_id )) {
413
+ bson_set_error (& cursor -> error ,
414
+ MONGOC_ERROR_CURSOR ,
415
+ MONGOC_ERROR_CURSOR_INVALID_CURSOR ,
416
+ "No valid cursor was provided." );
417
+ goto failure ;
418
+ }
419
+
420
+ rpc .get_more .msg_len = 0 ;
421
+ rpc .get_more .request_id = 0 ;
422
+ rpc .get_more .response_to = 0 ;
423
+ rpc .get_more .opcode = MONGOC_OPCODE_GET_MORE ;
424
+ rpc .get_more .zero = 0 ;
425
+ rpc .get_more .collection = cursor -> ns ;
426
+ if ((cursor -> flags & MONGOC_QUERY_TAILABLE_CURSOR )) {
427
+ rpc .get_more .n_return = 0 ;
428
+ } else {
429
+ /*
430
+ * TODO: We need to apply the limit to this so we don't
431
+ * overshoot our target.
432
+ */
433
+ rpc .get_more .n_return = cursor -> batch_size ;
434
+ }
435
+ rpc .get_more .cursor_id = cursor_id ;
399
436
400
- rpc .get_more .msg_len = 0 ;
401
- rpc .get_more .request_id = 0 ;
402
- rpc .get_more .response_to = 0 ;
403
- rpc .get_more .opcode = MONGOC_OPCODE_GET_MORE ;
404
- rpc .get_more .zero = 0 ;
405
- rpc .get_more .collection = cursor -> ns ;
406
- if ((cursor -> flags & MONGOC_QUERY_TAILABLE_CURSOR )) {
407
- rpc .get_more .n_return = 0 ;
408
- } else {
409
437
/*
410
- * TODO: We need to apply the limit to this so we don't
411
- * overshoot our target.
438
+ * TODO: Stamp protections for disconnections.
412
439
*/
413
- rpc .get_more .n_return = cursor -> batch_size ;
414
- }
415
- rpc .get_more .cursor_id = cursor_id ;
416
440
417
- /*
418
- * TODO: Stamp protections for disconnections.
419
- */
441
+ if (!_mongoc_client_sendv (cursor -> client , & rpc , 1 , cursor -> hint ,
442
+ NULL , cursor -> read_prefs , & cursor -> error )) {
443
+ cursor -> done = TRUE;
444
+ cursor -> failed = TRUE;
445
+ RETURN (FALSE);
446
+ }
420
447
421
- if (!_mongoc_client_sendv (cursor -> client , & rpc , 1 , cursor -> hint ,
422
- NULL , cursor -> read_prefs , & cursor -> error )) {
423
- cursor -> done = TRUE;
424
- cursor -> failed = TRUE;
425
- RETURN (FALSE);
448
+ request_id = BSON_UINT32_FROM_LE (rpc .header .request_id );
449
+ } else {
450
+ request_id = BSON_UINT32_FROM_LE (cursor -> rpc .header .request_id );
426
451
}
427
452
428
453
_mongoc_buffer_clear (& cursor -> buffer , FALSE);
429
454
430
- request_id = BSON_UINT32_FROM_LE (rpc .header .request_id );
431
-
432
455
if (!_mongoc_client_recv (cursor -> client ,
433
456
& cursor -> rpc ,
434
457
& cursor -> buffer ,
@@ -536,7 +559,17 @@ _mongoc_cursor_next (mongoc_cursor_t *cursor,
536
559
537
560
ENTRY ;
538
561
539
- bson_return_val_if_fail (cursor , FALSE);
562
+ BSON_ASSERT (cursor );
563
+
564
+
565
+ if (cursor -> client -> in_exhaust && ! cursor -> in_exhaust ) {
566
+ bson_set_error (& cursor -> error ,
567
+ MONGOC_ERROR_CLIENT ,
568
+ MONGOC_ERROR_CLIENT_IN_EXHAUST ,
569
+ "Another cursor derived from this client is in exhaust." );
570
+ cursor -> failed = TRUE;
571
+ RETURN (FALSE);
572
+ }
540
573
541
574
if (bson ) {
542
575
* bson = NULL ;
@@ -568,9 +601,11 @@ _mongoc_cursor_next (mongoc_cursor_t *cursor,
568
601
eof = FALSE;
569
602
b = bson_reader_read (cursor -> reader , & eof );
570
603
cursor -> end_of_event = eof ;
571
- cursor -> done = (cursor -> end_of_event &&
572
- !b &&
573
- !(cursor -> flags & MONGOC_QUERY_TAILABLE_CURSOR ));
604
+
605
+ cursor -> done = cursor -> end_of_event && (
606
+ (cursor -> in_exhaust && !cursor -> rpc .reply .cursor_id ) ||
607
+ (!b && !(cursor -> flags & MONGOC_QUERY_TAILABLE_CURSOR ))
608
+ );
574
609
575
610
/*
576
611
* Do a supplimental check to see if we had a corrupted reply in the
0 commit comments