bool IndexBoundsChecker::isValidKey(const BSONObj& key) { BSONObjIterator it(key); size_t curOil = 0; while (it.more()) { BSONElement elt = it.next(); size_t whichInterval; Location loc = findIntervalForField(elt, _bounds->fields[curOil], _expectedDirection[curOil], &whichInterval); if (WITHIN != loc) { return false; } ++curOil; } return true; }
IndexBoundsChecker::KeyState IndexBoundsChecker::checkKey(const BSONObj& key, int* keyEltsToUse, bool* movePastKeyElts, vector<const BSONElement*>* out, vector<bool>* incOut) { verify(_curInterval.size() > 0); verify(out->size() == _curInterval.size()); verify(incOut->size() == _curInterval.size()); // It's useful later to go from a field number to the value for that field. Store these. // TODO: on optimization pass, populate the vector as-needed and keep the vector around as a // member variable vector<BSONElement> keyValues; BSONObjIterator keyIt(key); while (keyIt.more()) { keyValues.push_back(keyIt.next()); } verify(keyValues.size() == _curInterval.size()); size_t firstNonContainedField; Location orientation; if (!findLeftmostProblem(keyValues, &firstNonContainedField, &orientation)) { // All fields in the index are within the current interval. Caller can use the key. return VALID; } // Field number 'firstNonContainedField' of the index key is before its current interval. // Tell the caller to move forward to the start of the current interval. if (BEHIND == orientation) { *keyEltsToUse = firstNonContainedField; *movePastKeyElts = false; for (size_t j = firstNonContainedField; j < _curInterval.size(); ++j) { const OrderedIntervalList& oil = _bounds->fields[j]; (*out)[j] = &oil.intervals[_curInterval[j]].start; (*incOut)[j] = oil.intervals[_curInterval[j]].startInclusive; } return MUST_ADVANCE; } verify(AHEAD == orientation); // Field number 'firstNonContainedField' of the index key is after interval we think it's // in. Fields 0 through 'firstNonContained-1' are within their current intervals and we can // ignore them. while (firstNonContainedField < _curInterval.size()) { // Find the interval that contains our field. size_t newIntervalForField; Location where = findIntervalForField(keyValues[firstNonContainedField], _bounds->fields[firstNonContainedField], _expectedDirection[firstNonContainedField], &newIntervalForField); if (WITHIN == where) { // Found a new interval for field firstNonContainedField. Move our internal choice // of interval to that. _curInterval[firstNonContainedField] = newIntervalForField; // Let's find valid intervals for fields to the right. ++firstNonContainedField; } else if (BEHIND == where) { // firstNonContained field is between the intervals (newIntervalForField-1) and // newIntervalForField. We have to tell the caller to move forward until he at // least hits our new current interval. _curInterval[firstNonContainedField] = newIntervalForField; // All other fields to the right start at their first interval. for (size_t i = firstNonContainedField + 1; i < _curInterval.size(); ++i) { _curInterval[i] = 0; } *keyEltsToUse = firstNonContainedField; *movePastKeyElts = false; for (size_t i = firstNonContainedField; i < _curInterval.size(); ++i) { const OrderedIntervalList& oil = _bounds->fields[i]; (*out)[i] = &oil.intervals[_curInterval[i]].start; (*incOut)[i] = oil.intervals[_curInterval[i]].startInclusive; } return MUST_ADVANCE; } else { verify (AHEAD == where); // Field number 'firstNonContainedField' cannot possibly be placed into an interval, // as it is already past its last possible interval. The caller must move forward // to a key with a greater value for the previous field. // If all fields to the left have hit the end of their intervals, we can't ask them // to move forward and we should stop iterating. if (!spaceLeftToAdvance(firstNonContainedField, keyValues)) { return DONE; } *keyEltsToUse = firstNonContainedField; *movePastKeyElts = true; for (size_t i = firstNonContainedField; i < _curInterval.size(); ++i) { _curInterval[i] = 0; } // If movePastKeyElts is true, we don't examine any fields after the keyEltsToUse // fields of the key. As such we don't populate the out/incOut. return MUST_ADVANCE; } } verify(firstNonContainedField == _curInterval.size()); return VALID; }