@@ -457,13 +457,13 @@ _mongoc_cursor_unwrap_failure (mongoc_cursor_t *cursor)
457457static bool
458458_mongoc_cursor_query (mongoc_cursor_t * cursor )
459459{
460+ mongoc_rpc_t rpc ;
460461 uint32_t hint ;
461462 uint32_t request_id ;
462- mongoc_rpc_t rpc ;
463463
464464 ENTRY ;
465465
466- bson_return_val_if_fail (cursor , false);
466+ bson_return_val_if_fail (cursor , false);
467467
468468 if (!_mongoc_client_warm_up (cursor -> client , & cursor -> error )) {
469469 cursor -> failed = true;
@@ -489,7 +489,7 @@ _mongoc_cursor_query (mongoc_cursor_t *cursor)
489489 cursor -> hint , NULL ,
490490 cursor -> read_prefs ,
491491 & cursor -> error ))) {
492- goto failure ;
492+ GOTO ( failure ) ;
493493 }
494494
495495 cursor -> hint = hint ;
@@ -502,7 +502,7 @@ _mongoc_cursor_query (mongoc_cursor_t *cursor)
502502 & cursor -> buffer ,
503503 hint ,
504504 & cursor -> error )) {
505- goto failure ;
505+ GOTO ( failure ) ;
506506 }
507507
508508 if (cursor -> rpc .header .opcode != MONGOC_OPCODE_REPLY ) {
@@ -528,7 +528,7 @@ _mongoc_cursor_query (mongoc_cursor_t *cursor)
528528 (cursor -> error .code == MONGOC_ERROR_QUERY_NOT_TAILABLE )) {
529529 cursor -> failed = true;
530530 }
531- goto failure ;
531+ GOTO ( failure ) ;
532532 }
533533
534534 if (cursor -> reader ) {
@@ -546,12 +546,14 @@ _mongoc_cursor_query (mongoc_cursor_t *cursor)
546546 cursor -> done = false;
547547 cursor -> end_of_event = false;
548548 cursor -> sent = true;
549- RETURN (true);
549+
550+ RETURN (true);
550551
551552failure :
552553 cursor -> failed = true;
553554 cursor -> done = true;
554- RETURN (false);
555+
556+ RETURN (false);
555557}
556558
557559
@@ -564,9 +566,9 @@ _mongoc_cursor_get_more (mongoc_cursor_t *cursor)
564566
565567 ENTRY ;
566568
567- BSON_ASSERT (cursor );
569+ BSON_ASSERT (cursor );
568570
569- if (! cursor -> in_exhaust ) {
571+ if (!cursor -> in_exhaust ) {
570572 if (!_mongoc_client_warm_up (cursor -> client , & cursor -> error )) {
571573 cursor -> failed = true;
572574 RETURN (false);
@@ -577,7 +579,7 @@ _mongoc_cursor_get_more (mongoc_cursor_t *cursor)
577579 MONGOC_ERROR_CURSOR ,
578580 MONGOC_ERROR_CURSOR_INVALID_CURSOR ,
579581 "No valid cursor was provided." );
580- goto failure ;
582+ GOTO ( failure ) ;
581583 }
582584
583585 rpc .get_more .msg_len = 0 ;
@@ -601,7 +603,7 @@ _mongoc_cursor_get_more (mongoc_cursor_t *cursor)
601603 NULL , cursor -> read_prefs , & cursor -> error )) {
602604 cursor -> done = true;
603605 cursor -> failed = true;
604- RETURN (false);
606+ RETURN (false);
605607 }
606608
607609 request_id = BSON_UINT32_FROM_LE (rpc .header .request_id );
@@ -721,9 +723,13 @@ mongoc_cursor_next (mongoc_cursor_t *cursor,
721723{
722724 bool ret ;
723725
726+ ENTRY ;
727+
724728 BSON_ASSERT (cursor );
725729 BSON_ASSERT (bson );
726730
731+ TRACE ("cursor_id(%" PRId64 ")" , cursor -> rpc .reply .cursor_id );
732+
727733 if (cursor -> iface .next ) {
728734 ret = cursor -> iface .next (cursor , bson );
729735 } else {
@@ -747,52 +753,72 @@ _mongoc_cursor_next (mongoc_cursor_t *cursor,
747753
748754 ENTRY ;
749755
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 );
760757
761758 if (bson ) {
762759 * bson = NULL ;
763760 }
764761
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+ */
765786 if (cursor -> limit && cursor -> count >= cursor -> limit ) {
766- return false;
787+ cursor -> done = true;
788+ RETURN (false);
767789 }
768790
769791 /*
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.
771794 */
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+ }
774802 }
775803
776804 /*
777805 * Check to see if we need to send a GET_MORE for more results.
778806 */
779807 if (!cursor -> sent ) {
780- if (!_mongoc_cursor_query (cursor )) {
781- RETURN (false);
808+ if (!_mongoc_cursor_query (cursor )) {
809+ RETURN (false);
782810 }
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);
786814 }
787815 }
788816
789- /*
790- * Read the next BSON document from the event.
791- */
792817 eof = false;
793- b = bson_reader_read (cursor -> reader , & eof );
818+ b = bson_reader_read (cursor -> reader , & eof );
794819 cursor -> end_of_event = eof ;
795820
821+ complete :
796822 cursor -> done = (cursor -> end_of_event &&
797823 ((cursor -> in_exhaust && !cursor -> rpc .reply .cursor_id ) ||
798824 (!b && !(cursor -> flags & MONGOC_QUERY_TAILABLE_CURSOR ))));
@@ -803,18 +829,18 @@ _mongoc_cursor_next (mongoc_cursor_t *cursor,
803829 */
804830 if (!b && !eof ) {
805831 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);
811837 }
812838
813839 if (bson ) {
814840 * bson = b ;
815841 }
816842
817- RETURN (!!b );
843+ RETURN (!!b );
818844}
819845
820846
0 commit comments