IndexCursor::IndexCursor( Collection *cl, const IndexDetails &idx, const BSONObj &startKey, const BSONObj &endKey, bool endKeyInclusive, int direction, int numWanted ) : _cl(cl), _idx(idx), _ordering(Ordering::make(_idx.keyPattern())), _startKey(startKey), _endKey(endKey), _endKeyInclusive(endKeyInclusive), _multiKey(_cl->isMultikey(_cl->idxNo(_idx))), _direction(direction), _bounds(), _boundsMustMatch(true), _nscanned(0), _nscannedObjects(0), _prelock(!cc().opSettings().getJustOne() && numWanted == 0), _cursor(_idx, cursor_flags()), _tailable(false), _ok(false), _getf_iteration(0) { verify( _cl != NULL ); TOKULOG(3) << toString() << ": constructor: bounds " << prettyIndexBounds() << endl; DBC* cursor = _cursor.dbc(); cursor->c_set_check_interrupt_callback(cursor, cursor_check_interrupt, &_interrupt_extra); initializeDBC(); }
IndexCursor::IndexCursor( Collection *cl, const IndexDetails &idx, const shared_ptr< FieldRangeVector > &bounds, int singleIntervalLimit, int direction, int numWanted ) : _cl(cl), _idx(idx), _ordering(Ordering::make(_idx.keyPattern())), _startKey(), _endKey(), _endKeyInclusive(true), _multiKey(_cl->isMultikey(_cl->idxNo(_idx))), _direction(direction), _bounds(bounds), _boundsMustMatch(true), _nscanned(0), _nscannedObjects(0), _prelock(!cc().opSettings().getJustOne() && numWanted == 0), _cursor(_idx, cursor_flags()), _tailable(false), _ok(false), _getf_iteration(0) { verify( _cl != NULL ); _boundsIterator.reset( new FieldRangeVectorIterator( *_bounds , singleIntervalLimit ) ); _boundsIterator->prepDive(); _startKey = _bounds->startKey(); _endKey = _bounds->endKey(); _endKeyInclusive = _bounds->endKeyInclusive(); TOKULOG(3) << toString() << ": constructor: bounds " << prettyIndexBounds() << endl; DBC* cursor = _cursor.dbc(); cursor->c_set_check_interrupt_callback(cursor, cursor_check_interrupt, &_interrupt_extra); initializeDBC(); // Fairly bad hack: // // Primary keys are not skipped properly when a non-inclusive start bound is specified. // See IndexCursor::skipToNextKey() // // Do a single advance here - the PK is unique so the next key is guaranteed to be // strictly greater than the start key. We have to play games with _nscanned because // advance()'s checkCurrentAgainstBounds() is going to increment it by 1 (we don't want that). if (ok() && _cl->isPKIndex(_idx) && !_bounds->startKeyInclusive() && _currKey == _startKey) { const long long oldNScanned = _nscanned; advance(); verify(oldNScanned <= _nscanned); _nscanned = oldNScanned; } DEV { // At this point, the current key should be consistent with // _startKey and _bounds->startKeyInclusive() if (ok() && !_bounds->startKeyInclusive()) { if (forward()) { verify(_currKey.woCompare(_startKey, _ordering) > 0); } else { verify(_currKey.woCompare(_startKey, _ordering) < 0); } } } }