@@ -457,13 +457,13 @@ _mongoc_cursor_unwrap_failure (mongoc_cursor_t *cursor)
457
457
static bool
458
458
_mongoc_cursor_query (mongoc_cursor_t * cursor )
459
459
{
460
+ mongoc_rpc_t rpc ;
460
461
uint32_t hint ;
461
462
uint32_t request_id ;
462
- mongoc_rpc_t rpc ;
463
463
464
464
ENTRY ;
465
465
466
- bson_return_val_if_fail (cursor , false);
466
+ bson_return_val_if_fail (cursor , false);
467
467
468
468
if (!_mongoc_client_warm_up (cursor -> client , & cursor -> error )) {
469
469
cursor -> failed = true;
@@ -489,7 +489,7 @@ _mongoc_cursor_query (mongoc_cursor_t *cursor)
489
489
cursor -> hint , NULL ,
490
490
cursor -> read_prefs ,
491
491
& cursor -> error ))) {
492
- goto failure ;
492
+ GOTO ( failure ) ;
493
493
}
494
494
495
495
cursor -> hint = hint ;
@@ -502,7 +502,7 @@ _mongoc_cursor_query (mongoc_cursor_t *cursor)
502
502
& cursor -> buffer ,
503
503
hint ,
504
504
& cursor -> error )) {
505
- goto failure ;
505
+ GOTO ( failure ) ;
506
506
}
507
507
508
508
if (cursor -> rpc .header .opcode != MONGOC_OPCODE_REPLY ) {
@@ -528,7 +528,7 @@ _mongoc_cursor_query (mongoc_cursor_t *cursor)
528
528
(cursor -> error .code == MONGOC_ERROR_QUERY_NOT_TAILABLE )) {
529
529
cursor -> failed = true;
530
530
}
531
- goto failure ;
531
+ GOTO ( failure ) ;
532
532
}
533
533
534
534
if (cursor -> reader ) {
@@ -546,12 +546,14 @@ _mongoc_cursor_query (mongoc_cursor_t *cursor)
546
546
cursor -> done = false;
547
547
cursor -> end_of_event = false;
548
548
cursor -> sent = true;
549
- RETURN (true);
549
+
550
+ RETURN (true);
550
551
551
552
failure :
552
553
cursor -> failed = true;
553
554
cursor -> done = true;
554
- RETURN (false);
555
+
556
+ RETURN (false);
555
557
}
556
558
557
559
@@ -564,9 +566,9 @@ _mongoc_cursor_get_more (mongoc_cursor_t *cursor)
564
566
565
567
ENTRY ;
566
568
567
- BSON_ASSERT (cursor );
569
+ BSON_ASSERT (cursor );
568
570
569
- if (! cursor -> in_exhaust ) {
571
+ if (!cursor -> in_exhaust ) {
570
572
if (!_mongoc_client_warm_up (cursor -> client , & cursor -> error )) {
571
573
cursor -> failed = true;
572
574
RETURN (false);
@@ -577,7 +579,7 @@ _mongoc_cursor_get_more (mongoc_cursor_t *cursor)
577
579
MONGOC_ERROR_CURSOR ,
578
580
MONGOC_ERROR_CURSOR_INVALID_CURSOR ,
579
581
"No valid cursor was provided." );
580
- goto failure ;
582
+ GOTO ( failure ) ;
581
583
}
582
584
583
585
rpc .get_more .msg_len = 0 ;
@@ -601,7 +603,7 @@ _mongoc_cursor_get_more (mongoc_cursor_t *cursor)
601
603
NULL , cursor -> read_prefs , & cursor -> error )) {
602
604
cursor -> done = true;
603
605
cursor -> failed = true;
604
- RETURN (false);
606
+ RETURN (false);
605
607
}
606
608
607
609
request_id = BSON_UINT32_FROM_LE (rpc .header .request_id );
@@ -721,9 +723,13 @@ mongoc_cursor_next (mongoc_cursor_t *cursor,
721
723
{
722
724
bool ret ;
723
725
726
+ ENTRY ;
727
+
724
728
BSON_ASSERT (cursor );
725
729
BSON_ASSERT (bson );
726
730
731
+ TRACE ("cursor_id(%" PRId64 ")" , cursor -> rpc .reply .cursor_id );
732
+
727
733
if (cursor -> iface .next ) {
728
734
ret = cursor -> iface .next (cursor , bson );
729
735
} else {
@@ -747,52 +753,72 @@ _mongoc_cursor_next (mongoc_cursor_t *cursor,
747
753
748
754
ENTRY ;
749
755
750
- BSON_ASSERT (cursor );
751
-
752
- if (cursor -> client -> in_exhaust && ! cursor -> in_exhaust ) {
753
- bson_set_error (& cursor -> error ,
754
- MONGOC_ERROR_CLIENT ,
755
- MONGOC_ERROR_CLIENT_IN_EXHAUST ,
756
- "Another cursor derived from this client is in exhaust." );
757
- cursor -> failed = true;
758
- RETURN (false);
759
- }
756
+ BSON_ASSERT (cursor );
760
757
761
758
if (bson ) {
762
759
* bson = NULL ;
763
760
}
764
761
762
+ if (cursor -> done || cursor -> failed ) {
763
+ bson_set_error (& cursor -> error ,
764
+ MONGOC_ERROR_CURSOR ,
765
+ MONGOC_ERROR_CURSOR_INVALID_CURSOR ,
766
+ "Cannot advance a completed or failed cursor." );
767
+ RETURN (false);
768
+ }
769
+
770
+ /*
771
+ * We cannot proceed if another cursor is receiving results in exhaust mode.
772
+ */
773
+ if (cursor -> client -> in_exhaust && !cursor -> in_exhaust ) {
774
+ bson_set_error (& cursor -> error ,
775
+ MONGOC_ERROR_CLIENT ,
776
+ MONGOC_ERROR_CLIENT_IN_EXHAUST ,
777
+ "Another cursor derived from this client is in exhaust." );
778
+ cursor -> failed = true;
779
+ RETURN (false);
780
+ }
781
+
782
+ /*
783
+ * If we reached our limit, make sure we mark this as done and do not try to
784
+ * make further progress.
785
+ */
765
786
if (cursor -> limit && cursor -> count >= cursor -> limit ) {
766
- return false;
787
+ cursor -> done = true;
788
+ RETURN (false);
767
789
}
768
790
769
791
/*
770
- * Short circuit if we are finished already.
792
+ * Try to read the next document from the reader if it exists, we might
793
+ * get NULL back and EOF, in which case we need to submit a getmore.
771
794
*/
772
- if (BSON_UNLIKELY (cursor -> done )) {
773
- RETURN (false);
795
+ if (cursor -> reader ) {
796
+ eof = false;
797
+ b = bson_reader_read (cursor -> reader , & eof );
798
+ cursor -> end_of_event = eof ;
799
+ if (b ) {
800
+ GOTO (complete );
801
+ }
774
802
}
775
803
776
804
/*
777
805
* Check to see if we need to send a GET_MORE for more results.
778
806
*/
779
807
if (!cursor -> sent ) {
780
- if (!_mongoc_cursor_query (cursor )) {
781
- RETURN (false);
808
+ if (!_mongoc_cursor_query (cursor )) {
809
+ RETURN (false);
782
810
}
783
- } else if (BSON_UNLIKELY (cursor -> end_of_event )) {
784
- if (!_mongoc_cursor_get_more (cursor )) {
785
- RETURN (false);
811
+ } else if (BSON_UNLIKELY (cursor -> end_of_event ) && cursor -> rpc . reply . cursor_id ) {
812
+ if (!_mongoc_cursor_get_more (cursor )) {
813
+ RETURN (false);
786
814
}
787
815
}
788
816
789
- /*
790
- * Read the next BSON document from the event.
791
- */
792
817
eof = false;
793
- b = bson_reader_read (cursor -> reader , & eof );
818
+ b = bson_reader_read (cursor -> reader , & eof );
794
819
cursor -> end_of_event = eof ;
795
820
821
+ complete :
796
822
cursor -> done = (cursor -> end_of_event &&
797
823
((cursor -> in_exhaust && !cursor -> rpc .reply .cursor_id ) ||
798
824
(!b && !(cursor -> flags & MONGOC_QUERY_TAILABLE_CURSOR ))));
@@ -803,18 +829,18 @@ _mongoc_cursor_next (mongoc_cursor_t *cursor,
803
829
*/
804
830
if (!b && !eof ) {
805
831
cursor -> failed = true;
806
- bson_set_error (& cursor -> error ,
807
- MONGOC_ERROR_CURSOR ,
808
- MONGOC_ERROR_PROTOCOL_INVALID_REPLY ,
809
- "The reply was corrupt." );
810
- RETURN (false);
832
+ bson_set_error (& cursor -> error ,
833
+ MONGOC_ERROR_CURSOR ,
834
+ MONGOC_ERROR_PROTOCOL_INVALID_REPLY ,
835
+ "The reply was corrupt." );
836
+ RETURN (false);
811
837
}
812
838
813
839
if (bson ) {
814
840
* bson = b ;
815
841
}
816
842
817
- RETURN (!!b );
843
+ RETURN (!!b );
818
844
}
819
845
820
846
0 commit comments