Uploaded image for project: 'C Driver'
  1. C Driver
  2. CDRIVER-2093

mongoc_cursor_is_alive and mongoc_cursor_more incorrect querying an empty collection

    • Type: Icon: Bug Bug
    • Resolution: Done
    • Priority: Icon: Major - P3 Major - P3
    • 1.7.0
    • Affects Version/s: 1.6.0
    • Component/s: libmongoc
    • Labels:
      None

      On a server using find commands, a query on an empty collection returns a cursor that returns incorrect values from mongoc_cursor_is_alive and mongoc_cursor_more after successive calls to mongoc_cursor_next.

      The attached code has a loop like this:

      for ( int i=1; !mongoc_cursor_error(cursor, NULL); i++ ) {
          printf("Loop iteration %d\n", i);
      
          printf("mongoc_cursor_is_alive: %s\n", ( mongoc_cursor_is_alive(cursor) ? "true" : "false" ));
          printf("mongoc_cursor_more:     %s\n", ( mongoc_cursor_more(cursor) ? "true" : "false" ));
          printf("mongoc_cursor_next:     %s\n", ( mongoc_cursor_next(cursor, &doc) ? "valid" : "null" ));
          printf("mongoc_cursor_error:    '%s'\n", ( mongoc_cursor_error(cursor, &error) ? error.message : "" ));
      
          printf("\n");
      }
      

      On a 2.6 mongod, the (correct) results are as follows:

      Loop iteration 1
      mongoc_cursor_is_alive: true
      mongoc_cursor_more:     true
      mongoc_cursor_next:     null
      mongoc_cursor_error:    ''
      
      Loop iteration 2
      mongoc_cursor_is_alive: false
      mongoc_cursor_more:     false
      mongoc_cursor_next:     null
      mongoc_cursor_error:    'Cannot advance a completed or failed cursor.'
      

      Note that "is_alive" and "more" are true before the first call to "next". The call to "next" returns null, indicating exhaustion. In the second loop iteration, both "is_alive and "more" are false, indicating that the user should not call "next". When "next" is called, an error occurs.

      Now look at the output of the same loop on mongod 3.2:

      Loop iteration 1
      mongoc_cursor_is_alive: true
      mongoc_cursor_more:     true
      mongoc_cursor_next:     null
      mongoc_cursor_error:    ''
      
      Loop iteration 2
      mongoc_cursor_is_alive: true
      mongoc_cursor_more:     true
      mongoc_cursor_next:     null
      mongoc_cursor_error:    ''
      
      Loop iteration 3
      mongoc_cursor_is_alive: false
      mongoc_cursor_more:     true
      mongoc_cursor_next:     null
      mongoc_cursor_error:    'Cannot advance a completed or failed cursor.'
      

      In this case, even though iteration 1 had "next" return null, loop iteration 2 has "is_alive" and "more" true and the second call to "next" does not return an error. Iteration 3 finally has "is_alive" false, but oddly, still has "more" true. This time, the call to "next" returns an error.

      I believe the mongoc_cursor_is_alive error is caused at least in part by these lines, which reset cursor->done because the empty response from the execution of the find command sets done but not end_of_event (whatever that is).

      I believe the further problems of mongoc_cursor_more are also caused by end_of_event not being set. mongoc-cursor-cursorid.c does not provide a more function, causing mongoc_cursor_more to fall back to _mongoc_cursor_more, which checks end_of_event.

            Assignee:
            david.golden@mongodb.com David Golden
            Reporter:
            david.golden@mongodb.com David Golden
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: