summaryrefslogtreecommitdiff
path: root/src/mongo/db/storage/in_memory/in_memory_btree_impl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/storage/in_memory/in_memory_btree_impl.cpp')
-rw-r--r--src/mongo/db/storage/in_memory/in_memory_btree_impl.cpp726
1 files changed, 364 insertions, 362 deletions
diff --git a/src/mongo/db/storage/in_memory/in_memory_btree_impl.cpp b/src/mongo/db/storage/in_memory/in_memory_btree_impl.cpp
index 40da9035fbd..f40dff8e7ff 100644
--- a/src/mongo/db/storage/in_memory/in_memory_btree_impl.cpp
+++ b/src/mongo/db/storage/in_memory/in_memory_btree_impl.cpp
@@ -42,448 +42,450 @@
namespace mongo {
- using std::shared_ptr;
- using std::string;
- using std::vector;
+using std::shared_ptr;
+using std::string;
+using std::vector;
namespace {
- const int TempKeyMaxSize = 1024; // this goes away with SERVER-3372
+const int TempKeyMaxSize = 1024; // this goes away with SERVER-3372
- bool hasFieldNames(const BSONObj& obj) {
- BSONForEach(e, obj) {
- if (e.fieldName()[0])
- return true;
- }
- return false;
+bool hasFieldNames(const BSONObj& obj) {
+ BSONForEach(e, obj) {
+ if (e.fieldName()[0])
+ return true;
}
+ return false;
+}
- BSONObj stripFieldNames(const BSONObj& query) {
- if (!hasFieldNames(query))
- return query;
+BSONObj stripFieldNames(const BSONObj& query) {
+ if (!hasFieldNames(query))
+ return query;
- BSONObjBuilder bb;
- BSONForEach(e, query) {
- bb.appendAs(e, StringData());
- }
- return bb.obj();
+ BSONObjBuilder bb;
+ BSONForEach(e, query) {
+ bb.appendAs(e, StringData());
}
+ return bb.obj();
+}
+
+typedef std::set<IndexKeyEntry, IndexEntryComparison> IndexSet;
+
+// taken from btree_logic.cpp
+Status dupKeyError(const BSONObj& key) {
+ StringBuilder sb;
+ sb << "E11000 duplicate key error ";
+ // sb << "index: " << _indexName << " "; // TODO
+ sb << "dup key: " << key;
+ return Status(ErrorCodes::DuplicateKey, sb.str());
+}
+
+bool isDup(const IndexSet& data, const BSONObj& key, RecordId loc) {
+ const IndexSet::const_iterator it = data.find(IndexKeyEntry(key, RecordId()));
+ if (it == data.end())
+ return false;
- typedef std::set<IndexKeyEntry, IndexEntryComparison> IndexSet;
-
- // taken from btree_logic.cpp
- Status dupKeyError(const BSONObj& key) {
- StringBuilder sb;
- sb << "E11000 duplicate key error ";
- // sb << "index: " << _indexName << " "; // TODO
- sb << "dup key: " << key;
- return Status(ErrorCodes::DuplicateKey, sb.str());
+ // Not a dup if the entry is for the same loc.
+ return it->loc != loc;
+}
+
+class InMemoryBtreeBuilderImpl : public SortedDataBuilderInterface {
+public:
+ InMemoryBtreeBuilderImpl(IndexSet* data, long long* currentKeySize, bool dupsAllowed)
+ : _data(data),
+ _currentKeySize(currentKeySize),
+ _dupsAllowed(dupsAllowed),
+ _comparator(_data->key_comp()) {
+ invariant(_data->empty());
}
- bool isDup(const IndexSet& data, const BSONObj& key, RecordId loc) {
- const IndexSet::const_iterator it = data.find(IndexKeyEntry(key, RecordId()));
- if (it == data.end())
- return false;
+ Status addKey(const BSONObj& key, const RecordId& loc) {
+ // inserts should be in ascending (key, RecordId) order.
- // Not a dup if the entry is for the same loc.
- return it->loc != loc;
- }
-
- class InMemoryBtreeBuilderImpl : public SortedDataBuilderInterface {
- public:
- InMemoryBtreeBuilderImpl(IndexSet* data, long long* currentKeySize, bool dupsAllowed)
- : _data(data),
- _currentKeySize( currentKeySize ),
- _dupsAllowed(dupsAllowed),
- _comparator(_data->key_comp()) {
- invariant(_data->empty());
+ if (key.objsize() >= TempKeyMaxSize) {
+ return Status(ErrorCodes::KeyTooLong, "key too big");
}
- Status addKey(const BSONObj& key, const RecordId& loc) {
- // inserts should be in ascending (key, RecordId) order.
+ invariant(loc.isNormal());
+ invariant(!hasFieldNames(key));
- if ( key.objsize() >= TempKeyMaxSize ) {
- return Status(ErrorCodes::KeyTooLong, "key too big");
+ if (!_data->empty()) {
+ // Compare specified key with last inserted key, ignoring its RecordId
+ int cmp = _comparator.compare(IndexKeyEntry(key, RecordId()), *_last);
+ if (cmp < 0 || (_dupsAllowed && cmp == 0 && loc < _last->loc)) {
+ return Status(ErrorCodes::InternalError,
+ "expected ascending (key, RecordId) order in bulk builder");
+ } else if (!_dupsAllowed && cmp == 0 && loc != _last->loc) {
+ return dupKeyError(key);
}
+ }
- invariant(loc.isNormal());
- invariant(!hasFieldNames(key));
+ BSONObj owned = key.getOwned();
+ _last = _data->insert(_data->end(), IndexKeyEntry(owned, loc));
+ *_currentKeySize += key.objsize();
- if (!_data->empty()) {
- // Compare specified key with last inserted key, ignoring its RecordId
- int cmp = _comparator.compare(IndexKeyEntry(key, RecordId()), *_last);
- if (cmp < 0 || (_dupsAllowed && cmp == 0 && loc < _last->loc)) {
- return Status(ErrorCodes::InternalError,
- "expected ascending (key, RecordId) order in bulk builder");
- }
- else if (!_dupsAllowed && cmp == 0 && loc != _last->loc) {
- return dupKeyError(key);
- }
- }
+ return Status::OK();
+ }
- BSONObj owned = key.getOwned();
- _last = _data->insert(_data->end(), IndexKeyEntry(owned, loc));
- *_currentKeySize += key.objsize();
+private:
+ IndexSet* const _data;
+ long long* _currentKeySize;
+ const bool _dupsAllowed;
- return Status::OK();
- }
+ IndexEntryComparison _comparator; // used by the bulk builder to detect duplicate keys
+ IndexSet::const_iterator _last; // or (key, RecordId) ordering violations
+};
- private:
- IndexSet* const _data;
- long long* _currentKeySize;
- const bool _dupsAllowed;
+class InMemoryBtreeImpl : public SortedDataInterface {
+public:
+ InMemoryBtreeImpl(IndexSet* data) : _data(data) {
+ _currentKeySize = 0;
+ }
- IndexEntryComparison _comparator; // used by the bulk builder to detect duplicate keys
- IndexSet::const_iterator _last; // or (key, RecordId) ordering violations
- };
+ virtual SortedDataBuilderInterface* getBulkBuilder(OperationContext* txn, bool dupsAllowed) {
+ return new InMemoryBtreeBuilderImpl(_data, &_currentKeySize, dupsAllowed);
+ }
- class InMemoryBtreeImpl : public SortedDataInterface {
- public:
- InMemoryBtreeImpl(IndexSet* data)
- : _data(data) {
- _currentKeySize = 0;
+ virtual Status insert(OperationContext* txn,
+ const BSONObj& key,
+ const RecordId& loc,
+ bool dupsAllowed) {
+ invariant(loc.isNormal());
+ invariant(!hasFieldNames(key));
+
+ if (key.objsize() >= TempKeyMaxSize) {
+ string msg = mongoutils::str::stream()
+ << "InMemoryBtree::insert: key too large to index, failing " << ' ' << key.objsize()
+ << ' ' << key;
+ return Status(ErrorCodes::KeyTooLong, msg);
+ }
+
+ // TODO optimization: save the iterator from the dup-check to speed up insert
+ if (!dupsAllowed && isDup(*_data, key, loc))
+ return dupKeyError(key);
+
+ IndexKeyEntry entry(key.getOwned(), loc);
+ if (_data->insert(entry).second) {
+ _currentKeySize += key.objsize();
+ txn->recoveryUnit()->registerChange(new IndexChange(_data, entry, true));
}
+ return Status::OK();
+ }
- virtual SortedDataBuilderInterface* getBulkBuilder(OperationContext* txn,
- bool dupsAllowed) {
- return new InMemoryBtreeBuilderImpl(_data, &_currentKeySize, dupsAllowed);
+ virtual void unindex(OperationContext* txn,
+ const BSONObj& key,
+ const RecordId& loc,
+ bool dupsAllowed) {
+ invariant(loc.isNormal());
+ invariant(!hasFieldNames(key));
+
+ IndexKeyEntry entry(key.getOwned(), loc);
+ const size_t numDeleted = _data->erase(entry);
+ invariant(numDeleted <= 1);
+ if (numDeleted == 1) {
+ _currentKeySize -= key.objsize();
+ txn->recoveryUnit()->registerChange(new IndexChange(_data, entry, false));
}
+ }
- virtual Status insert(OperationContext* txn,
- const BSONObj& key,
- const RecordId& loc,
- bool dupsAllowed) {
+ virtual void fullValidate(OperationContext* txn,
+ bool full,
+ long long* numKeysOut,
+ BSONObjBuilder* output) const {
+ // TODO check invariants?
+ *numKeysOut = _data->size();
+ }
- invariant(loc.isNormal());
- invariant(!hasFieldNames(key));
+ virtual bool appendCustomStats(OperationContext* txn,
+ BSONObjBuilder* output,
+ double scale) const {
+ return false;
+ }
- if ( key.objsize() >= TempKeyMaxSize ) {
- string msg = mongoutils::str::stream()
- << "InMemoryBtree::insert: key too large to index, failing "
- << ' ' << key.objsize() << ' ' << key;
- return Status(ErrorCodes::KeyTooLong, msg);
- }
+ virtual long long getSpaceUsedBytes(OperationContext* txn) const {
+ return _currentKeySize + (sizeof(IndexKeyEntry) * _data->size());
+ }
- // TODO optimization: save the iterator from the dup-check to speed up insert
- if (!dupsAllowed && isDup(*_data, key, loc))
- return dupKeyError(key);
+ virtual Status dupKeyCheck(OperationContext* txn, const BSONObj& key, const RecordId& loc) {
+ invariant(!hasFieldNames(key));
+ if (isDup(*_data, key, loc))
+ return dupKeyError(key);
+ return Status::OK();
+ }
- IndexKeyEntry entry(key.getOwned(), loc);
- if ( _data->insert(entry).second ) {
- _currentKeySize += key.objsize();
- txn->recoveryUnit()->registerChange(new IndexChange(_data, entry, true));
- }
- return Status::OK();
- }
+ virtual bool isEmpty(OperationContext* txn) {
+ return _data->empty();
+ }
- virtual void unindex(OperationContext* txn,
- const BSONObj& key,
- const RecordId& loc,
- bool dupsAllowed) {
- invariant(loc.isNormal());
- invariant(!hasFieldNames(key));
-
- IndexKeyEntry entry(key.getOwned(), loc);
- const size_t numDeleted = _data->erase(entry);
- invariant(numDeleted <= 1);
- if ( numDeleted == 1 ) {
- _currentKeySize -= key.objsize();
- txn->recoveryUnit()->registerChange(new IndexChange(_data, entry, false));
- }
- }
+ virtual Status touch(OperationContext* txn) const {
+ // already in memory...
+ return Status::OK();
+ }
- virtual void fullValidate(OperationContext* txn, bool full, long long *numKeysOut,
- BSONObjBuilder* output) const {
- // TODO check invariants?
- *numKeysOut = _data->size();
- }
+ class Cursor final : public SortedDataInterface::Cursor {
+ public:
+ Cursor(OperationContext* txn, const IndexSet& data, bool isForward)
+ : _txn(txn), _data(data), _forward(isForward), _it(data.end()) {}
- virtual bool appendCustomStats(OperationContext* txn, BSONObjBuilder* output, double scale)
- const {
- return false;
- }
+ boost::optional<IndexKeyEntry> next(RequestedInfo parts) override {
+ if (_lastMoveWasRestore) {
+ // Return current position rather than advancing.
+ _lastMoveWasRestore = false;
+ } else {
+ advance();
+ if (atEndPoint())
+ _isEOF = true;
+ }
- virtual long long getSpaceUsedBytes( OperationContext* txn ) const {
- return _currentKeySize + ( sizeof(IndexKeyEntry) * _data->size() );
+ if (_isEOF)
+ return {};
+ return *_it;
}
- virtual Status dupKeyCheck(OperationContext* txn, const BSONObj& key, const RecordId& loc) {
- invariant(!hasFieldNames(key));
- if (isDup(*_data, key, loc))
- return dupKeyError(key);
- return Status::OK();
+ void setEndPosition(const BSONObj& key, bool inclusive) override {
+ if (key.isEmpty()) {
+ // This means scan to end of index.
+ _endState = {};
+ return;
+ }
+
+ // NOTE: this uses the opposite min/max rules as a normal seek because a forward
+ // scan should land after the key if inclusive and before if exclusive.
+ _endState = EndState(stripFieldNames(key),
+ _forward == inclusive ? RecordId::max() : RecordId::min());
+ seekEndCursor();
}
- virtual bool isEmpty(OperationContext* txn) {
- return _data->empty();
+ boost::optional<IndexKeyEntry> seek(const BSONObj& key,
+ bool inclusive,
+ RequestedInfo parts) override {
+ const BSONObj query = stripFieldNames(key);
+ locate(query, _forward == inclusive ? RecordId::min() : RecordId::max());
+ _lastMoveWasRestore = false;
+ if (_isEOF)
+ return {};
+ dassert(inclusive ? compareKeys(_it->key, query) >= 0
+ : compareKeys(_it->key, query) > 0);
+ return *_it;
}
- virtual Status touch(OperationContext* txn) const{
- // already in memory...
- return Status::OK();
+ boost::optional<IndexKeyEntry> seek(const IndexSeekPoint& seekPoint,
+ RequestedInfo parts) override {
+ // Query encodes exclusive case so it can be treated as an inclusive query.
+ const BSONObj query = IndexEntryComparison::makeQueryObject(seekPoint, _forward);
+ locate(query, _forward ? RecordId::min() : RecordId::max());
+ _lastMoveWasRestore = false;
+ if (_isEOF)
+ return {};
+ dassert(compareKeys(_it->key, query) >= 0);
+ return *_it;
}
- class Cursor final : public SortedDataInterface::Cursor {
- public:
- Cursor(OperationContext* txn, const IndexSet& data, bool isForward)
- : _txn(txn),
- _data(data),
- _forward(isForward),
- _it(data.end())
- {}
-
- boost::optional<IndexKeyEntry> next(RequestedInfo parts) override {
- if (_lastMoveWasRestore) {
- // Return current position rather than advancing.
- _lastMoveWasRestore = false;
- }
- else {
- advance();
- if (atEndPoint()) _isEOF = true;
- }
+ void savePositioned() override {
+ // Keep original position if we haven't moved since the last restore.
+ _txn = nullptr;
+ if (_lastMoveWasRestore)
+ return;
- if (_isEOF) return {};
- return *_it;
- }
-
- void setEndPosition(const BSONObj& key, bool inclusive) override {
- if (key.isEmpty()) {
- // This means scan to end of index.
- _endState = {};
- return;
- }
-
- // NOTE: this uses the opposite min/max rules as a normal seek because a forward
- // scan should land after the key if inclusive and before if exclusive.
- _endState = EndState(stripFieldNames(key),
- _forward == inclusive ? RecordId::max() : RecordId::min());
- seekEndCursor();
+ if (_isEOF) {
+ saveUnpositioned();
+ return;
}
- boost::optional<IndexKeyEntry> seek(const BSONObj& key, bool inclusive,
- RequestedInfo parts) override {
- const BSONObj query = stripFieldNames(key);
- locate(query, _forward == inclusive ? RecordId::min() : RecordId::max());
- _lastMoveWasRestore = false;
- if (_isEOF) return {};
- dassert(inclusive ? compareKeys(_it->key, query) >= 0
- : compareKeys(_it->key, query) > 0);
- return *_it;
- }
+ _savedAtEnd = false;
+ _savedKey = _it->key.getOwned();
+ _savedLoc = _it->loc;
+ // Doing nothing with end cursor since it will do full reseek on restore.
+ }
- boost::optional<IndexKeyEntry> seek(const IndexSeekPoint& seekPoint,
- RequestedInfo parts) override {
- // Query encodes exclusive case so it can be treated as an inclusive query.
- const BSONObj query = IndexEntryComparison::makeQueryObject(seekPoint, _forward);
- locate(query, _forward ? RecordId::min() : RecordId::max());
- _lastMoveWasRestore = false;
- if (_isEOF) return {};
- dassert(compareKeys(_it->key, query) >= 0);
- return *_it;
- }
+ void saveUnpositioned() override {
+ _txn = nullptr;
+ _savedAtEnd = true;
+ // Doing nothing with end cursor since it will do full reseek on restore.
+ }
- void savePositioned() override {
- // Keep original position if we haven't moved since the last restore.
- _txn = nullptr;
- if (_lastMoveWasRestore) return;
+ void restore(OperationContext* txn) override {
+ _txn = txn;
- if (_isEOF) {
- saveUnpositioned();
- return;
- }
+ // Always do a full seek on restore. We cannot use our last position since index
+ // entries may have been inserted closer to our endpoint and we would need to move
+ // over them.
+ seekEndCursor();
- _savedAtEnd = false;
- _savedKey = _it->key.getOwned();
- _savedLoc = _it->loc;
- // Doing nothing with end cursor since it will do full reseek on restore.
+ if (_savedAtEnd) {
+ _isEOF = true;
+ return;
}
- void saveUnpositioned() override {
- _txn = nullptr;
- _savedAtEnd = true;
- // Doing nothing with end cursor since it will do full reseek on restore.
- }
+ // Need to find our position from the root.
+ locate(_savedKey, _savedLoc);
- void restore(OperationContext* txn) override {
- _txn = txn;
+ _lastMoveWasRestore = _isEOF // We weren't EOF but now are.
+ || _data.value_comp().compare(*_it, {_savedKey, _savedLoc}) != 0;
+ }
- // Always do a full seek on restore. We cannot use our last position since index
- // entries may have been inserted closer to our endpoint and we would need to move
- // over them.
- seekEndCursor();
+ private:
+ bool atEndPoint() const {
+ return _endState && _it == _endState->it;
+ }
- if (_savedAtEnd) {
+ // Advances once in the direction of the scan, updating _isEOF as needed.
+ // Does nothing if already _isEOF.
+ void advance() {
+ if (_isEOF)
+ return;
+ if (_forward) {
+ if (_it != _data.end())
+ ++_it;
+ if (_it == _data.end() || atEndPoint())
_isEOF = true;
- return;
+ } else {
+ if (_it == _data.begin() || _data.empty()) {
+ _isEOF = true;
+ } else {
+ --_it;
}
-
- // Need to find our position from the root.
- locate(_savedKey, _savedLoc);
-
- _lastMoveWasRestore = _isEOF // We weren't EOF but now are.
- || _data.value_comp().compare(*_it, {_savedKey, _savedLoc}) != 0;
+ if (atEndPoint())
+ _isEOF = true;
}
+ }
- private:
- bool atEndPoint() const {
- return _endState && _it == _endState->it;
+ bool atOrPastEndPointAfterSeeking() const {
+ if (_isEOF)
+ return true;
+ if (!_endState)
+ return false;
+
+ const int cmp = _data.value_comp().compare(*_it, _endState->query);
+
+ // We set up _endState->query to be in between the last in-range value and the first
+ // out-of-range value. In particular, it is constructed to never equal any legal
+ // index key.
+ dassert(cmp != 0);
+
+ if (_forward) {
+ // We may have landed after the end point.
+ return cmp > 0;
+ } else {
+ // We may have landed before the end point.
+ return cmp < 0;
}
+ }
- // Advances once in the direction of the scan, updating _isEOF as needed.
- // Does nothing if already _isEOF.
- void advance() {
- if (_isEOF) return;
- if (_forward) {
- if (_it != _data.end()) ++_it;
- if (_it == _data.end() || atEndPoint()) _isEOF = true;
- }
- else {
- if (_it == _data.begin() || _data.empty()) {
- _isEOF = true;
- }
- else {
- --_it;
- }
- if (atEndPoint()) _isEOF = true;
- }
+ void locate(const BSONObj& key, const RecordId& loc) {
+ _isEOF = false;
+ const auto query = IndexKeyEntry(key, loc);
+ _it = _data.lower_bound(query);
+ if (_forward) {
+ if (_it == _data.end())
+ _isEOF = true;
+ } else {
+ // lower_bound lands us on or after query. Reverse cursors must be on or before.
+ if (_it == _data.end() || _data.value_comp().compare(*_it, query) > 0)
+ advance(); // sets _isEOF if there is nothing more to return.
}
- bool atOrPastEndPointAfterSeeking() const {
- if (_isEOF) return true;
- if (!_endState) return false;
-
- const int cmp = _data.value_comp().compare(*_it, _endState->query);
+ if (atOrPastEndPointAfterSeeking())
+ _isEOF = true;
+ }
- // We set up _endState->query to be in between the last in-range value and the first
- // out-of-range value. In particular, it is constructed to never equal any legal
- // index key.
- dassert(cmp != 0);
+ // Returns comparison relative to direction of scan. If rhs would be seen later, returns
+ // a positive value.
+ int compareKeys(const BSONObj& lhs, const BSONObj& rhs) const {
+ int cmp = _data.value_comp().compare({lhs, RecordId()}, {rhs, RecordId()});
+ return _forward ? cmp : -cmp;
+ }
- if (_forward) {
- // We may have landed after the end point.
- return cmp > 0;
- }
- else {
- // We may have landed before the end point.
- return cmp < 0;
+ void seekEndCursor() {
+ if (!_endState || _data.empty())
+ return;
+
+ auto it = _data.lower_bound(_endState->query);
+ if (!_forward) {
+ // lower_bound lands us on or after query. Reverse cursors must be on or before.
+ if (it == _data.end() || _data.value_comp().compare(*it, _endState->query) > 0) {
+ if (it == _data.begin()) {
+ it = _data.end(); // all existing data in range.
+ } else {
+ --it;
+ }
}
}
- void locate(const BSONObj& key, const RecordId& loc) {
- _isEOF = false;
- const auto query = IndexKeyEntry(key, loc);
- _it = _data.lower_bound(query);
- if (_forward) {
- if (_it == _data.end()) _isEOF = true;
- }
- else {
- // lower_bound lands us on or after query. Reverse cursors must be on or before.
- if (_it == _data.end() || _data.value_comp().compare(*_it, query) > 0)
- advance(); // sets _isEOF if there is nothing more to return.
- }
+ if (it != _data.end())
+ dassert(compareKeys(it->key, _endState->query.key) >= 0);
+ _endState->it = it;
+ }
- if (atOrPastEndPointAfterSeeking()) _isEOF = true;
- }
+ OperationContext* _txn; // not owned
+ const IndexSet& _data;
+ const bool _forward;
+ bool _isEOF = true;
+ IndexSet::const_iterator _it;
- // Returns comparison relative to direction of scan. If rhs would be seen later, returns
- // a positive value.
- int compareKeys(const BSONObj& lhs, const BSONObj& rhs) const {
- int cmp = _data.value_comp().compare({lhs, RecordId()}, {rhs, RecordId()});
- return _forward ? cmp : -cmp;
- }
+ struct EndState {
+ EndState(BSONObj key, RecordId loc) : query(std::move(key), loc) {}
- void seekEndCursor() {
- if (!_endState || _data.empty()) return;
-
- auto it = _data.lower_bound(_endState->query);
- if (!_forward) {
- // lower_bound lands us on or after query. Reverse cursors must be on or before.
- if (it == _data.end() || _data.value_comp().compare(*it,
- _endState->query) > 0) {
- if (it == _data.begin()) {
- it = _data.end(); // all existing data in range.
- }
- else {
- --it;
- }
- }
- }
+ IndexKeyEntry query;
+ IndexSet::const_iterator it;
+ };
+ boost::optional<EndState> _endState;
- if (it != _data.end()) dassert(compareKeys(it->key, _endState->query.key) >= 0);
- _endState->it = it;
- }
+ // Used by next to decide to return current position rather than moving. Should be reset
+ // to false by any operation that moves the cursor, other than subsequent save/restore
+ // pairs.
+ bool _lastMoveWasRestore = false;
- OperationContext* _txn; // not owned
- const IndexSet& _data;
- const bool _forward;
- bool _isEOF = true;
- IndexSet::const_iterator _it;
-
- struct EndState {
- EndState(BSONObj key, RecordId loc) : query(std::move(key), loc) {}
-
- IndexKeyEntry query;
- IndexSet::const_iterator it;
- };
- boost::optional<EndState> _endState;
-
- // Used by next to decide to return current position rather than moving. Should be reset
- // to false by any operation that moves the cursor, other than subsequent save/restore
- // pairs.
- bool _lastMoveWasRestore = false;
-
- // For save/restore since _it may be invalidated during a yield.
- bool _savedAtEnd = false;
- BSONObj _savedKey;
- RecordId _savedLoc;
- };
+ // For save/restore since _it may be invalidated during a yield.
+ bool _savedAtEnd = false;
+ BSONObj _savedKey;
+ RecordId _savedLoc;
+ };
- virtual std::unique_ptr<SortedDataInterface::Cursor> newCursor(
- OperationContext* txn,
- bool isForward) const {
- return stdx::make_unique<Cursor>(txn, *_data, isForward);
- }
+ virtual std::unique_ptr<SortedDataInterface::Cursor> newCursor(OperationContext* txn,
+ bool isForward) const {
+ return stdx::make_unique<Cursor>(txn, *_data, isForward);
+ }
- virtual Status initAsEmpty(OperationContext* txn) {
- // No-op
- return Status::OK();
+ virtual Status initAsEmpty(OperationContext* txn) {
+ // No-op
+ return Status::OK();
+ }
+
+private:
+ class IndexChange : public RecoveryUnit::Change {
+ public:
+ IndexChange(IndexSet* data, const IndexKeyEntry& entry, bool insert)
+ : _data(data), _entry(entry), _insert(insert) {}
+
+ virtual void commit() {}
+ virtual void rollback() {
+ if (_insert)
+ _data->erase(_entry);
+ else
+ _data->insert(_entry);
}
private:
- class IndexChange : public RecoveryUnit::Change {
- public:
- IndexChange(IndexSet* data, const IndexKeyEntry& entry, bool insert)
- : _data(data), _entry(entry), _insert(insert)
- {}
-
- virtual void commit() {}
- virtual void rollback() {
- if (_insert)
- _data->erase(_entry);
- else
- _data->insert(_entry);
- }
-
- private:
- IndexSet* _data;
- const IndexKeyEntry _entry;
- const bool _insert;
- };
-
IndexSet* _data;
- long long _currentKeySize;
+ const IndexKeyEntry _entry;
+ const bool _insert;
};
-} // namespace
-
- // IndexCatalogEntry argument taken by non-const pointer for consistency with other Btree
- // factories. We don't actually modify it.
- SortedDataInterface* getInMemoryBtreeImpl(const Ordering& ordering,
- std::shared_ptr<void>* dataInOut) {
- invariant(dataInOut);
- if (!*dataInOut) {
- *dataInOut = std::make_shared<IndexSet>(IndexEntryComparison(ordering));
- }
- return new InMemoryBtreeImpl(static_cast<IndexSet*>(dataInOut->get()));
+
+ IndexSet* _data;
+ long long _currentKeySize;
+};
+} // namespace
+
+// IndexCatalogEntry argument taken by non-const pointer for consistency with other Btree
+// factories. We don't actually modify it.
+SortedDataInterface* getInMemoryBtreeImpl(const Ordering& ordering,
+ std::shared_ptr<void>* dataInOut) {
+ invariant(dataInOut);
+ if (!*dataInOut) {
+ *dataInOut = std::make_shared<IndexSet>(IndexEntryComparison(ordering));
}
+ return new InMemoryBtreeImpl(static_cast<IndexSet*>(dataInOut->get()));
+}
} // namespace mongo