void FindingStartCursor::next() { if ( !_findingStartCursor || !_findingStartCursor->ok() ) { _findingStart = false; _c = _qp.newCursor(); // on error, start from beginning destroyClientCursor(); return; } switch( _findingStartMode ) { case Initial: { if ( !_matcher->matchesCurrent( _findingStartCursor->c() ) ) { _findingStart = false; // found first record out of query range, so scan normally _c = _qp.newCursor( _findingStartCursor->currLoc() ); destroyClientCursor(); return; } _findingStartCursor->advance(); RARELY { if ( _findingStartTimer.seconds() >= __findingStartInitialTimeout ) { createClientCursor( startLoc( _findingStartCursor->currLoc() ) ); _findingStartMode = FindExtent; return; } } return; } case FindExtent: { if ( !_matcher->matchesCurrent( _findingStartCursor->c() ) ) { _findingStartMode = InExtent; return; } DiskLoc prev = prevLoc( _findingStartCursor->currLoc() ); if ( prev.isNull() ) { // hit beginning, so start scanning from here createClientCursor(); _findingStartMode = InExtent; return; } // There might be a more efficient implementation than creating new cursor & client cursor each time, // not worrying about that for now createClientCursor( prev ); return; } case InExtent: { if ( _matcher->matchesCurrent( _findingStartCursor->c() ) ) { _findingStart = false; // found first record in query range, so scan normally _c = _qp.newCursor( _findingStartCursor->currLoc() ); destroyClientCursor(); return; } _findingStartCursor->advance(); return; } default: { massert( 14038, "invalid _findingStartMode", false ); } } }
void FindingStartCursor::next() { if ( !_findingStartCursor || !_findingStartCursor->ok() ) { _findingStart = false; _c = _qp.newCursor(); // on error, start from beginning destroyClientCursor(); return; } switch( _findingStartMode ) { // Initial mode: scan backwards from end of collection case Initial: { if ( !_matcher->matchesCurrent( _findingStartCursor->c() ) ) { _findingStart = false; // found first record out of query range, so scan normally _c = _qp.newCursor( _findingStartCursor->currLoc() ); destroyClientCursor(); return; } _findingStartCursor->advance(); RARELY { if ( _findingStartTimer.seconds() >= __findingStartInitialTimeout ) { // If we've scanned enough, switch to find extent mode. createClientCursor( extentFirstLoc( _findingStartCursor->currLoc() ) ); _findingStartMode = FindExtent; return; } } return; } // FindExtent mode: moving backwards through extents, check first // document of each extent. case FindExtent: { if ( !_matcher->matchesCurrent( _findingStartCursor->c() ) ) { _findingStartMode = InExtent; return; } DiskLoc prev = prevExtentFirstLoc( _findingStartCursor->currLoc() ); if ( prev.isNull() ) { // hit beginning, so start scanning from here createClientCursor(); _findingStartMode = InExtent; return; } // There might be a more efficient implementation than creating new cursor & client cursor each time, // not worrying about that for now createClientCursor( prev ); return; } // InExtent mode: once an extent is chosen, find starting doc in the extent. case InExtent: { if ( _matcher->matchesCurrent( _findingStartCursor->c() ) ) { _findingStart = false; // found first record in query range, so scan normally _c = _qp.newCursor( _findingStartCursor->currLoc() ); destroyClientCursor(); return; } _findingStartCursor->advance(); return; } default: { massert( 14038, "invalid _findingStartMode", false ); } } }