diff options
Diffstat (limited to 'src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp')
-rw-r--r-- | src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp | 545 |
1 files changed, 270 insertions, 275 deletions
diff --git a/src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp b/src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp index 422a6441e9a..ce1aa117fef 100644 --- a/src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp +++ b/src/mongo/db/storage/mmap_v1/btree/btree_interface.cpp @@ -39,340 +39,335 @@ namespace mongo { namespace { - using std::unique_ptr; - using std::string; - using std::vector; +using std::unique_ptr; +using std::string; +using std::vector; + +template <class OnDiskFormat> +class BtreeBuilderInterfaceImpl final : public SortedDataBuilderInterface { +public: + BtreeBuilderInterfaceImpl(OperationContext* trans, + typename BtreeLogic<OnDiskFormat>::Builder* builder) + : _builder(builder), _trans(trans) {} + + Status addKey(const BSONObj& key, const RecordId& loc) { + return _builder->addKey(key, DiskLoc::fromRecordId(loc)); + } - template <class OnDiskFormat> - class BtreeBuilderInterfaceImpl final : public SortedDataBuilderInterface { - public: - BtreeBuilderInterfaceImpl(OperationContext* trans, - typename BtreeLogic<OnDiskFormat>::Builder* builder) - : _builder(builder), _trans(trans) { } +private: + std::unique_ptr<typename BtreeLogic<OnDiskFormat>::Builder> _builder; + + // Not owned here. + OperationContext* _trans; +}; + +template <class OnDiskFormat> +class BtreeInterfaceImpl final : public SortedDataInterface { +public: + BtreeInterfaceImpl(HeadManager* headManager, + RecordStore* recordStore, + SavedCursorRegistry* cursorRegistry, + const Ordering& ordering, + const string& indexName) { + _btree.reset(new BtreeLogic<OnDiskFormat>( + headManager, recordStore, cursorRegistry, ordering, indexName)); + } - Status addKey(const BSONObj& key, const RecordId& loc) { - return _builder->addKey(key, DiskLoc::fromRecordId(loc)); - } + virtual ~BtreeInterfaceImpl() {} - private: - std::unique_ptr<typename BtreeLogic<OnDiskFormat>::Builder> _builder; + virtual SortedDataBuilderInterface* getBulkBuilder(OperationContext* txn, bool dupsAllowed) { + return new BtreeBuilderInterfaceImpl<OnDiskFormat>(txn, + _btree->newBuilder(txn, dupsAllowed)); + } - // Not owned here. - OperationContext* _trans; - }; + virtual Status insert(OperationContext* txn, + const BSONObj& key, + const RecordId& loc, + bool dupsAllowed) { + return _btree->insert(txn, key, DiskLoc::fromRecordId(loc), dupsAllowed); + } - template <class OnDiskFormat> - class BtreeInterfaceImpl final : public SortedDataInterface { - public: - BtreeInterfaceImpl(HeadManager* headManager, - RecordStore* recordStore, - SavedCursorRegistry* cursorRegistry, - const Ordering& ordering, - const string& indexName) { - _btree.reset(new BtreeLogic<OnDiskFormat>(headManager, - recordStore, - cursorRegistry, - ordering, - indexName)); - } + virtual void unindex(OperationContext* txn, + const BSONObj& key, + const RecordId& loc, + bool dupsAllowed) { + _btree->unindex(txn, key, DiskLoc::fromRecordId(loc)); + } - virtual ~BtreeInterfaceImpl() { } + virtual void fullValidate(OperationContext* txn, + bool full, + long long* numKeysOut, + BSONObjBuilder* output) const { + *numKeysOut = _btree->fullValidate(txn, NULL, false, false, 0); + } - virtual SortedDataBuilderInterface* getBulkBuilder(OperationContext* txn, - bool dupsAllowed) { + virtual bool appendCustomStats(OperationContext* txn, + BSONObjBuilder* output, + double scale) const { + return false; + } - return new BtreeBuilderInterfaceImpl<OnDiskFormat>( - txn, _btree->newBuilder(txn, dupsAllowed)); - } + virtual long long getSpaceUsedBytes(OperationContext* txn) const { + return _btree->getRecordStore()->dataSize(txn); + } - virtual Status insert(OperationContext* txn, - const BSONObj& key, - const RecordId& loc, - bool dupsAllowed) { + virtual Status dupKeyCheck(OperationContext* txn, const BSONObj& key, const RecordId& loc) { + return _btree->dupKeyCheck(txn, key, DiskLoc::fromRecordId(loc)); + } - return _btree->insert(txn, key, DiskLoc::fromRecordId(loc), dupsAllowed); - } + virtual bool isEmpty(OperationContext* txn) { + return _btree->isEmpty(txn); + } - virtual void unindex(OperationContext* txn, - const BSONObj& key, - const RecordId& loc, - bool dupsAllowed) { + virtual Status touch(OperationContext* txn) const { + return _btree->touch(txn); + } - _btree->unindex(txn, key, DiskLoc::fromRecordId(loc)); - } + class Cursor final : public SortedDataInterface::Cursor { + public: + Cursor(OperationContext* txn, const BtreeLogic<OnDiskFormat>* btree, bool forward) + : _txn(txn), _btree(btree), _direction(forward ? 1 : -1), _ofs(0) {} + + boost::optional<IndexKeyEntry> next(RequestedInfo parts) override { + if (isEOF()) + return {}; + if (_lastMoveWasRestore) { + // Return current position rather than advancing. + _lastMoveWasRestore = false; + } else { + _btree->advance(_txn, &_bucket, &_ofs, _direction); + } - virtual void fullValidate(OperationContext* txn, bool full, long long *numKeysOut, - BSONObjBuilder* output) const { - *numKeysOut = _btree->fullValidate(txn, NULL, false, false, 0); + if (atEndPoint()) + markEOF(); + return curr(parts); } - virtual bool appendCustomStats(OperationContext* txn, BSONObjBuilder* output, double scale) - const { - return false; - } + void setEndPosition(const BSONObj& key, bool inclusive) override { + if (key.isEmpty()) { + // This means scan to end of index. + _endState = {}; + return; + } - virtual long long getSpaceUsedBytes( OperationContext* txn ) const { - return _btree->getRecordStore()->dataSize( txn ); + _endState = {{key, inclusive}}; + seekEndCursor(); // Completes initialization of _endState. } - virtual Status dupKeyCheck(OperationContext* txn, - const BSONObj& key, - const RecordId& loc) { - return _btree->dupKeyCheck(txn, key, DiskLoc::fromRecordId(loc)); - } + boost::optional<IndexKeyEntry> seek(const BSONObj& key, + bool inclusive, + RequestedInfo parts) override { + locate(key, inclusive == forward() ? RecordId::min() : RecordId::max()); + _lastMoveWasRestore = false; - virtual bool isEmpty(OperationContext* txn) { - return _btree->isEmpty(txn); + if (isEOF()) + return {}; + dassert(inclusive ? compareKeys(getKey(), key) >= 0 : compareKeys(getKey(), key) > 0); + return curr(parts); } - virtual Status touch(OperationContext* txn) const{ - return _btree->touch(txn); - } - class Cursor final : public SortedDataInterface::Cursor { - public: - Cursor(OperationContext* txn, - const BtreeLogic<OnDiskFormat>* btree, - bool forward) - : _txn(txn), - _btree(btree), - _direction(forward ? 1 : -1), - _ofs(0) - {} - - boost::optional<IndexKeyEntry> next(RequestedInfo parts) override { - if (isEOF()) return {}; - if (_lastMoveWasRestore) { - // Return current position rather than advancing. - _lastMoveWasRestore = false; - } - else { - _btree->advance(_txn, &_bucket, &_ofs, _direction); - } + boost::optional<IndexKeyEntry> seek(const IndexSeekPoint& seekPoint, + RequestedInfo parts) override { + bool canUseAdvanceTo = false; + if (!isEOF()) { + int cmp = _btree->customBSONCmp(getKey(), seekPoint, _direction); - if (atEndPoint()) markEOF(); - return curr(parts); + // advanceTo requires that we are positioned "earlier" in the index than the + // seek point, in scan order. + canUseAdvanceTo = forward() ? cmp < 0 : cmp > 0; } - void setEndPosition(const BSONObj& key, bool inclusive) override { - if (key.isEmpty()) { - // This means scan to end of index. - _endState = {}; - return; - } - _endState = {{key, inclusive}}; - seekEndCursor(); // Completes initialization of _endState. + if (canUseAdvanceTo) { + // This takes advantage of current location. + _btree->advanceTo(_txn, &_bucket, &_ofs, seekPoint, _direction); + } else { + // Start at root. + _bucket = _btree->getHead(_txn); + _ofs = 0; + _btree->customLocate(_txn, &_bucket, &_ofs, seekPoint, _direction); } - boost::optional<IndexKeyEntry> seek(const BSONObj& key, bool inclusive, - RequestedInfo parts) override { - locate(key, inclusive == forward() ? RecordId::min() : RecordId::max()); - _lastMoveWasRestore = false; - - if (isEOF()) return {}; - dassert(inclusive ? compareKeys(getKey(), key) >= 0 - : compareKeys(getKey(), key) > 0); - return curr(parts); - } + _lastMoveWasRestore = false; + if (atOrPastEndPointAfterSeeking()) + markEOF(); + return curr(parts); + } - boost::optional<IndexKeyEntry> seek(const IndexSeekPoint& seekPoint, - RequestedInfo parts) override { - bool canUseAdvanceTo = false; - if (!isEOF()) { - int cmp = _btree->customBSONCmp(getKey(), seekPoint, _direction); - - // advanceTo requires that we are positioned "earlier" in the index than the - // seek point, in scan order. - canUseAdvanceTo = forward() ? cmp < 0 : cmp > 0; - } + void savePositioned() override { + _txn = nullptr; + if (!_lastMoveWasRestore) + _savedEOF = isEOF(); - if (canUseAdvanceTo) { - // This takes advantage of current location. - _btree->advanceTo(_txn, &_bucket, &_ofs, seekPoint, _direction); - } - else { - // Start at root. - _bucket = _btree->getHead(_txn); - _ofs = 0; - _btree->customLocate(_txn, &_bucket, &_ofs, seekPoint, _direction); + if (!isEOF()) { + _saved.bucket = _bucket; + _btree->savedCursors()->registerCursor(&_saved); + // Don't want to change saved position if we only moved during restore. + if (!_lastMoveWasRestore) { + _saved.key = getKey().getOwned(); + _saved.loc = getDiskLoc(); } + } + // Doing nothing with end cursor since it will do full reseek on restore. + } - _lastMoveWasRestore = false; + void saveUnpositioned() override { + _txn = nullptr; + // Don't leak our registration if savePositioned() was previously called. + if (!_saved.bucket.isNull()) + _btree->savedCursors()->unregisterCursor(&_saved); - if (atOrPastEndPointAfterSeeking()) markEOF(); - return curr(parts); - } + _saved.bucket = DiskLoc(); + _savedEOF = true; + } - void savePositioned() override { - _txn = nullptr; + void restore(OperationContext* txn) override { + // guard against accidental double restore + invariant(!_txn); + _txn = txn; - if (!_lastMoveWasRestore) _savedEOF = isEOF(); + // 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(); - if (!isEOF()) { - _saved.bucket = _bucket; - _btree->savedCursors()->registerCursor(&_saved); - // Don't want to change saved position if we only moved during restore. - if (!_lastMoveWasRestore) { - _saved.key = getKey().getOwned(); - _saved.loc = getDiskLoc(); - } - } - // Doing nothing with end cursor since it will do full reseek on restore. + if (_savedEOF) { + markEOF(); + return; } - void saveUnpositioned() override { - _txn = nullptr; - // Don't leak our registration if savePositioned() was previously called. - if (!_saved.bucket.isNull()) _btree->savedCursors()->unregisterCursor(&_saved); - - _saved.bucket = DiskLoc(); - _savedEOF = true; + if (_btree->savedCursors()->unregisterCursor(&_saved)) { + // We can use the fast restore mechanism. + _btree->restorePosition(_txn, _saved.key, _saved.loc, _direction, &_bucket, &_ofs); + } else { + // Need to find our position from the root. + locate(_saved.key, _saved.loc.toRecordId()); } - void restore(OperationContext* txn) override { - // guard against accidental double restore - invariant(!_txn); - _txn = txn; + _lastMoveWasRestore = isEOF() // We weren't EOF but now are. + || getDiskLoc() != _saved.loc || compareKeys(getKey(), _saved.key) != 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 isEOF() const { + return _bucket.isNull(); + } + void markEOF() { + _bucket = DiskLoc(); + } - if (_savedEOF) { - markEOF(); - return; - } + boost::optional<IndexKeyEntry> curr(RequestedInfo parts) { + if (isEOF()) + return {}; + return {{(parts & kWantKey) ? getKey() : BSONObj(), + (parts & kWantLoc) ? getDiskLoc().toRecordId() : RecordId()}}; + } - if (_btree->savedCursors()->unregisterCursor(&_saved)) { - // We can use the fast restore mechanism. - _btree->restorePosition(_txn, _saved.key, _saved.loc, _direction, - &_bucket, &_ofs); - } - else { - // Need to find our position from the root. - locate(_saved.key, _saved.loc.toRecordId()); - } + bool atEndPoint() const { + return _endState && _bucket == _endState->bucket && (isEOF() || _ofs == _endState->ofs); + } - _lastMoveWasRestore = isEOF() // We weren't EOF but now are. - || getDiskLoc() != _saved.loc - || compareKeys(getKey(), _saved.key) != 0; - } + bool atOrPastEndPointAfterSeeking() const { + if (!_endState) + return false; + if (isEOF()) + return true; - private: - bool isEOF() const { return _bucket.isNull(); } - void markEOF() { _bucket = DiskLoc(); } + int cmp = compareKeys(getKey(), _endState->key); + return _endState->inclusive ? cmp > 0 : cmp >= 0; + } - boost::optional<IndexKeyEntry> curr(RequestedInfo parts) { - if (isEOF()) return {}; - return {{(parts & kWantKey) ? getKey() : BSONObj(), - (parts & kWantLoc) ? getDiskLoc().toRecordId() : RecordId()}}; - } + void locate(const BSONObj& key, const RecordId& loc) { + _btree->locate(_txn, key, DiskLoc::fromRecordId(loc), _direction, &_ofs, &_bucket); + if (atOrPastEndPointAfterSeeking()) + markEOF(); + } - bool atEndPoint() const { - return _endState - && _bucket == _endState->bucket - && (isEOF() || _ofs == _endState->ofs); - } + // 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 = lhs.woCompare(rhs, _btree->ordering(), /*considerFieldName*/ false); + return forward() ? cmp : -cmp; + } - bool atOrPastEndPointAfterSeeking() const { - if (!_endState) return false; - if (isEOF()) return true; - - int cmp = compareKeys(getKey(), _endState->key); - return _endState->inclusive ? cmp > 0 : cmp >= 0; - } + BSONObj getKey() const { + return _btree->getKey(_txn, _bucket, _ofs); + } + DiskLoc getDiskLoc() const { + return _btree->getDiskLoc(_txn, _bucket, _ofs); + } - void locate(const BSONObj& key, const RecordId& loc) { - _btree->locate(_txn, key, DiskLoc::fromRecordId(loc), _direction, &_ofs, &_bucket); - if (atOrPastEndPointAfterSeeking()) markEOF(); - } + void seekEndCursor() { + if (!_endState) + return; + _btree->locate(_txn, + _endState->key, + forward() == _endState->inclusive ? DiskLoc::max() : DiskLoc::min(), + _direction, + &_endState->ofs, + &_endState->bucket); // pure out params. + } - // 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 = lhs.woCompare(rhs, _btree->ordering(), /*considerFieldName*/false); - return forward() ? cmp : -cmp; - } + bool forward() const { + return _direction == 1; + } - BSONObj getKey() const { return _btree->getKey(_txn, _bucket, _ofs); } - DiskLoc getDiskLoc() const { return _btree->getDiskLoc(_txn, _bucket, _ofs); } + OperationContext* _txn; // not owned + const BtreeLogic<OnDiskFormat>* const _btree; + const int _direction; - void seekEndCursor() { - if (!_endState) return; - _btree->locate(_txn, - _endState->key, - forward() == _endState->inclusive ? DiskLoc::max() : DiskLoc::min(), - _direction, - &_endState->ofs, &_endState->bucket); // pure out params. - } + DiskLoc _bucket; + int _ofs; - bool forward() const { return _direction == 1; } - - OperationContext* _txn; // not owned - const BtreeLogic<OnDiskFormat>* const _btree; - const int _direction; - - DiskLoc _bucket; - int _ofs; - - struct EndState { - BSONObj key; - bool inclusive; - DiskLoc bucket; - int ofs; - }; - 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; - - // Only used by save/restore() if _bucket is non-Null. - bool _savedEOF = false; - SavedCursorRegistry::SavedCursor _saved; + struct EndState { + BSONObj key; + bool inclusive; + DiskLoc bucket; + int ofs; }; + boost::optional<EndState> _endState; - virtual std::unique_ptr<SortedDataInterface::Cursor> newCursor( - OperationContext* txn, - bool isForward = true) const { - return stdx::make_unique<Cursor>(txn, _btree.get(), isForward); - } + // 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; - virtual Status initAsEmpty(OperationContext* txn) { - return _btree->initAsEmpty(txn); - } - - private: - unique_ptr<BtreeLogic<OnDiskFormat> > _btree; + // Only used by save/restore() if _bucket is non-Null. + bool _savedEOF = false; + SavedCursorRegistry::SavedCursor _saved; }; -} // namespace - - SortedDataInterface* getMMAPV1Interface(HeadManager* headManager, - RecordStore* recordStore, - SavedCursorRegistry* cursorRegistry, - const Ordering& ordering, - const string& indexName, - int version) { - if (0 == version) { - return new BtreeInterfaceImpl<BtreeLayoutV0>(headManager, - recordStore, - cursorRegistry, - ordering, - indexName); - } - else { - invariant(1 == version); - return new BtreeInterfaceImpl<BtreeLayoutV1>(headManager, - recordStore, - cursorRegistry, - ordering, - indexName); - } + + virtual std::unique_ptr<SortedDataInterface::Cursor> newCursor(OperationContext* txn, + bool isForward = true) const { + return stdx::make_unique<Cursor>(txn, _btree.get(), isForward); + } + + virtual Status initAsEmpty(OperationContext* txn) { + return _btree->initAsEmpty(txn); + } + +private: + unique_ptr<BtreeLogic<OnDiskFormat>> _btree; +}; +} // namespace + +SortedDataInterface* getMMAPV1Interface(HeadManager* headManager, + RecordStore* recordStore, + SavedCursorRegistry* cursorRegistry, + const Ordering& ordering, + const string& indexName, + int version) { + if (0 == version) { + return new BtreeInterfaceImpl<BtreeLayoutV0>( + headManager, recordStore, cursorRegistry, ordering, indexName); + } else { + invariant(1 == version); + return new BtreeInterfaceImpl<BtreeLayoutV1>( + headManager, recordStore, cursorRegistry, ordering, indexName); } +} } // namespace mongo |