diff --git a/src/mongo/SConscript b/src/mongo/SConscript index 1540b24c63b..ee3374dd90e 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -738,11 +738,11 @@ serverOnlyFiles = [ "db/background.cpp", "db/global_environment_d.cpp", "db/index/2d_access_method.cpp", "db/index/btree_access_method.cpp", - "db/index/btree_based_access_method.cpp", - "db/index/btree_index_cursor.cpp", "db/index/fts_access_method.cpp", "db/index/hash_access_method.cpp", "db/index/haystack_access_method.cpp", + "db/index/index_access_method.cpp", + "db/index/index_cursor.cpp", "db/index/s2_access_method.cpp", "db/index_builder.cpp", "db/index_legacy.cpp", diff --git a/src/mongo/db/exec/count_scan.h b/src/mongo/db/exec/count_scan.h index 29c5d030fe7..e626ae4da6c 100644 --- a/src/mongo/db/exec/count_scan.h +++ b/src/mongo/db/exec/count_scan.h @@ -31,7 +31,6 @@ #include #include "mongo/db/exec/plan_stage.h" -#include "mongo/db/index/btree_index_cursor.h" #include "mongo/db/index/index_access_method.h" #include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression.h" diff --git a/src/mongo/db/exec/distinct_scan.h b/src/mongo/db/exec/distinct_scan.h index f22508302c4..aa24ffc1a03 100644 --- a/src/mongo/db/exec/distinct_scan.h +++ b/src/mongo/db/exec/distinct_scan.h @@ -31,7 +31,6 @@ #include #include "mongo/db/exec/plan_stage.h" -#include "mongo/db/index/btree_index_cursor.h" #include "mongo/db/index/index_access_method.h" #include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression.h" diff --git a/src/mongo/db/exec/index_scan.h b/src/mongo/db/exec/index_scan.h index 1712ca33fa1..0e65aae78ad 100644 --- a/src/mongo/db/exec/index_scan.h +++ b/src/mongo/db/exec/index_scan.h @@ -31,7 +31,6 @@ #include #include "mongo/db/exec/plan_stage.h" -#include "mongo/db/index/btree_index_cursor.h" #include "mongo/db/index/index_access_method.h" #include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression.h" diff --git a/src/mongo/db/index/2d_access_method.h b/src/mongo/db/index/2d_access_method.h index 21cbdf2947d..441ad9a1146 100644 --- a/src/mongo/db/index/2d_access_method.h +++ b/src/mongo/db/index/2d_access_method.h @@ -30,7 +30,7 @@ #include "mongo/base/status.h" #include "mongo/db/index/2d_common.h" -#include "mongo/db/index/btree_based_access_method.h" +#include "mongo/db/index/index_access_method.h" #include "mongo/db/jsobj.h" namespace mongo { diff --git a/src/mongo/db/index/btree_access_method.cpp b/src/mongo/db/index/btree_access_method.cpp index b3823c64ce1..3b41f74eea9 100644 --- a/src/mongo/db/index/btree_access_method.cpp +++ b/src/mongo/db/index/btree_access_method.cpp @@ -31,7 +31,6 @@ #include #include "mongo/base/status.h" -#include "mongo/db/index/btree_index_cursor.h" #include "mongo/db/jsobj.h" #include "mongo/db/keypattern.h" diff --git a/src/mongo/db/index/btree_access_method.h b/src/mongo/db/index/btree_access_method.h index 3ccc2fe11d2..31fcbff56e1 100644 --- a/src/mongo/db/index/btree_access_method.h +++ b/src/mongo/db/index/btree_access_method.h @@ -31,7 +31,7 @@ #include #include "mongo/base/status.h" -#include "mongo/db/index/btree_based_access_method.h" +#include "mongo/db/index/index_access_method.h" #include "mongo/db/index/btree_key_generator.h" #include "mongo/db/index/index_access_method.h" #include "mongo/db/jsobj.h" diff --git a/src/mongo/db/index/btree_based_access_method.h b/src/mongo/db/index/btree_based_access_method.h deleted file mode 100644 index b8de19ba36e..00000000000 --- a/src/mongo/db/index/btree_based_access_method.h +++ /dev/null @@ -1,151 +0,0 @@ -/** -* Copyright (C) 2013-2014 MongoDB Inc. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License, version 3, -* as published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see . -* -* As a special exception, the copyright holders give permission to link the -* code of portions of this program with the OpenSSL library under certain -* conditions as described in each individual source file and distribute -* linked combinations including the program with the OpenSSL library. You -* must comply with the GNU Affero General Public License in all respects for -* all of the code used other than as permitted herein. If you modify file(s) -* with this exception, you may extend this exception to your version of the -* file(s), but you are not obligated to do so. If you do not wish to do so, -* delete this exception statement from your version. If you delete this -* exception statement from all source files in the program, then also delete -* it in the license file. -*/ - -#pragma once - -#include -#include - -#include "mongo/base/disallow_copying.h" -#include "mongo/db/index/index_access_method.h" -#include "mongo/db/index/index_cursor.h" -#include "mongo/db/index/index_descriptor.h" -#include "mongo/db/jsobj.h" -#include "mongo/db/record_id.h" -#include "mongo/db/storage/sorted_data_interface.h" -#include "mongo/db/sorter/sorter.h" - -namespace mongo { - - /** - * Any access method that is Btree based subclasses from this. - * - * Subclassers must: - * 1. Call the constructor for this class from their constructors, and - * 2. override getKeys. - * - * XXX: Should really think of the sub-class as providing an expression mapping of the input, - * don't need so many AMs, just really precomputing some data and mapping doc for getKeys(?). - * See SERVER-12397 for tracking. - */ - class BtreeBasedAccessMethod : public IndexAccessMethod { - MONGO_DISALLOW_COPYING( BtreeBasedAccessMethod ); - public: - BtreeBasedAccessMethod( IndexCatalogEntry* btreeState, - SortedDataInterface* btree ); - - virtual ~BtreeBasedAccessMethod() { } - - virtual Status insert(OperationContext* txn, - const BSONObj& obj, - const RecordId& loc, - const InsertDeleteOptions& options, - int64_t* numInserted); - - virtual Status remove(OperationContext* txn, - const BSONObj& obj, - const RecordId& loc, - const InsertDeleteOptions& options, - int64_t* numDeleted); - - virtual Status validateUpdate(OperationContext* txn, - const BSONObj& from, - const BSONObj& to, - const RecordId& loc, - const InsertDeleteOptions& options, - UpdateTicket* ticket); - - virtual Status update(OperationContext* txn, - const UpdateTicket& ticket, - int64_t* numUpdated); - - virtual Status newCursor(OperationContext* txn, - const CursorOptions& opts, - IndexCursor** out) const; - - virtual Status initializeAsEmpty(OperationContext* txn); - - virtual std::unique_ptr initiateBulk(); - - virtual Status commitBulk(OperationContext* txn, - std::unique_ptr bulk, - bool mayInterrupt, - bool dupsAllowed, - std::set* dups); - - virtual Status touch(OperationContext* txn, const BSONObj& obj); - - virtual Status touch(OperationContext* txn) const; - - virtual Status validate(OperationContext* txn, bool full, int64_t* numKeys, - BSONObjBuilder* output); - - virtual bool appendCustomStats(OperationContext* txn, BSONObjBuilder* output, double scale) - const; - virtual long long getSpaceUsedBytes( OperationContext* txn ) const; - - // XXX: consider migrating callers to use IndexCursor instead - virtual RecordId findSingle( OperationContext* txn, const BSONObj& key ) const; - - protected: - // See below for body. - class BtreeBasedPrivateUpdateData; - - // Determines whether it's OK to ignore ErrorCodes::KeyTooLong for this OperationContext - bool ignoreKeyTooLong(OperationContext* txn); - - IndexCatalogEntry* _btreeState; // owned by IndexCatalogEntry - const IndexDescriptor* _descriptor; - - private: - void removeOneKey(OperationContext* txn, - const BSONObj& key, - const RecordId& loc, - bool dupsAllowed); - - const std::unique_ptr _newInterface; - }; - - /** - * What data do we need to perform an update? - */ - class BtreeBasedAccessMethod::BtreeBasedPrivateUpdateData - : public UpdateTicket::PrivateUpdateData { - public: - virtual ~BtreeBasedPrivateUpdateData() { } - - BSONObjSet oldKeys, newKeys; - - // These point into the sets oldKeys and newKeys. - std::vector removed, added; - - RecordId loc; - bool dupsAllowed; - }; - -} // namespace mongo diff --git a/src/mongo/db/index/btree_index_cursor.h b/src/mongo/db/index/btree_index_cursor.h deleted file mode 100644 index be115858289..00000000000 --- a/src/mongo/db/index/btree_index_cursor.h +++ /dev/null @@ -1,106 +0,0 @@ -/** -* Copyright (C) 2013 10gen Inc. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License, version 3, -* as published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see . -* -* As a special exception, the copyright holders give permission to link the -* code of portions of this program with the OpenSSL library under certain -* conditions as described in each individual source file and distribute -* linked combinations including the program with the OpenSSL library. You -* must comply with the GNU Affero General Public License in all respects for -* all of the code used other than as permitted herein. If you modify file(s) -* with this exception, you may extend this exception to your version of the -* file(s), but you are not obligated to do so. If you do not wish to do so, -* delete this exception statement from your version. If you delete this -* exception statement from all source files in the program, then also delete -* it in the license file. -*/ - -#pragma once - -#include -#include - -#include "mongo/base/status.h" -#include "mongo/db/index/index_cursor.h" -#include "mongo/db/index/index_descriptor.h" -#include "mongo/db/jsobj.h" -#include "mongo/db/record_id.h" -#include "mongo/db/storage/sorted_data_interface.h" - -namespace mongo { - - class BtreeIndexCursor : public IndexCursor { - public: - bool isEOF() const; - - virtual Status seek(const BSONObj& position); - - // Btree-specific seeking functions. - Status seek(const std::vector& position, - const std::vector& inclusive); - - /** - * Seek to the key 'position'. If 'afterKey' is true, seeks to the first - * key that is oriented after 'position'. - * - * Btree-specific. - */ - void seek(const BSONObj& position, bool afterKey); - - Status skip(const BSONObj& keyBegin, - int keyBeginLen, - bool afterKey, - const std::vector& keyEnd, - const std::vector& keyEndInclusive); - - virtual BSONObj getKey() const; - virtual RecordId getValue() const; - virtual void next(); - - /** - * BtreeIndexCursor-only. - * Returns true if 'this' points at the same exact key as 'other'. - * Returns false otherwise. - */ - bool pointsAt(const BtreeIndexCursor& other); - - virtual Status savePosition(); - - virtual Status restorePosition(OperationContext* txn); - - virtual std::string toString(); - - private: - // We keep the constructor private and only allow the AM to create us. - friend class BtreeBasedAccessMethod; - - /** - * interface is an abstraction to hide the fact that we have two types of Btrees. - * - * Intentionally private, we're friends with the only class allowed to call it. - */ - BtreeIndexCursor(SortedDataInterface::Cursor* cursor); - - bool isSavedPositionValid(); - - /** - * Move to the next (or previous depending on the direction) key. Used by normal getNext - * and also skipping unused keys. - */ - void advance(); - - boost::scoped_ptr _cursor; - }; - -} // namespace mongo diff --git a/src/mongo/db/index/fts_access_method.h b/src/mongo/db/index/fts_access_method.h index d538301b545..6ef5fbbbfec 100644 --- a/src/mongo/db/index/fts_access_method.h +++ b/src/mongo/db/index/fts_access_method.h @@ -30,7 +30,7 @@ #include "mongo/base/status.h" #include "mongo/db/fts/fts_spec.h" -#include "mongo/db/index/btree_based_access_method.h" +#include "mongo/db/index/index_access_method.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/jsobj.h" diff --git a/src/mongo/db/index/hash_access_method.h b/src/mongo/db/index/hash_access_method.h index fee946046b5..162ccdfd28a 100644 --- a/src/mongo/db/index/hash_access_method.h +++ b/src/mongo/db/index/hash_access_method.h @@ -33,7 +33,7 @@ #include "mongo/base/status.h" #include "mongo/db/hasher.h" // For HashSeed. #include "mongo/db/index/index_descriptor.h" -#include "mongo/db/index/btree_based_access_method.h" +#include "mongo/db/index/index_access_method.h" #include "mongo/db/jsobj.h" namespace mongo { diff --git a/src/mongo/db/index/haystack_access_method.h b/src/mongo/db/index/haystack_access_method.h index 63b3548084e..b5c128f91b5 100644 --- a/src/mongo/db/index/haystack_access_method.h +++ b/src/mongo/db/index/haystack_access_method.h @@ -29,7 +29,7 @@ #pragma once #include "mongo/base/status.h" -#include "mongo/db/index/btree_based_access_method.h" +#include "mongo/db/index/index_access_method.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/jsobj.h" diff --git a/src/mongo/db/index/btree_based_access_method.cpp b/src/mongo/db/index/index_access_method.cpp similarity index 74% rename from src/mongo/db/index/btree_based_access_method.cpp rename to src/mongo/db/index/index_access_method.cpp index 50800f65668..3724992dd9d 100644 --- a/src/mongo/db/index/btree_based_access_method.cpp +++ b/src/mongo/db/index/index_access_method.cpp @@ -36,7 +36,6 @@ #include "mongo/base/status.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/curop.h" -#include "mongo/db/index/btree_index_cursor.h" #include "mongo/db/jsobj.h" #include "mongo/db/keypattern.h" #include "mongo/db/server_parameters.h" @@ -83,25 +82,25 @@ namespace mongo { const int _version; }; - BtreeBasedAccessMethod::BtreeBasedAccessMethod(IndexCatalogEntry* btreeState, - SortedDataInterface* btree) + IndexAccessMethod::IndexAccessMethod(IndexCatalogEntry* btreeState, + SortedDataInterface* btree) : _btreeState(btreeState), _descriptor(btreeState->descriptor()), _newInterface(btree) { verify(0 == _descriptor->version() || 1 == _descriptor->version()); } - bool BtreeBasedAccessMethod::ignoreKeyTooLong(OperationContext *txn) { + bool IndexAccessMethod::ignoreKeyTooLong(OperationContext *txn) { // Ignore this error if we're on a secondary or if the user requested it return !txn->isPrimaryFor(_btreeState->ns()) || !failIndexKeyTooLong; } // Find the keys for obj, put them in the tree pointing to loc - Status BtreeBasedAccessMethod::insert(OperationContext* txn, - const BSONObj& obj, - const RecordId& loc, - const InsertDeleteOptions& options, - int64_t* numInserted) { + Status IndexAccessMethod::insert(OperationContext* txn, + const BSONObj& obj, + const RecordId& loc, + const InsertDeleteOptions& options, + int64_t* numInserted) { *numInserted = 0; BSONObjSet keys; @@ -149,10 +148,10 @@ namespace mongo { return ret; } - void BtreeBasedAccessMethod::removeOneKey(OperationContext* txn, - const BSONObj& key, - const RecordId& loc, - bool dupsAllowed) { + void IndexAccessMethod::removeOneKey(OperationContext* txn, + const BSONObj& key, + const RecordId& loc, + bool dupsAllowed) { try { _newInterface->unindex(txn, key, loc, dupsAllowed); } catch (AssertionException& e) { @@ -165,17 +164,18 @@ namespace mongo { } } - Status BtreeBasedAccessMethod::newCursor(OperationContext* txn, const CursorOptions& opts, IndexCursor** out) const { + Status IndexAccessMethod::newCursor(OperationContext* txn, const CursorOptions& opts, + IndexCursor** out) const { *out = new BtreeIndexCursor(_newInterface->newCursor(txn, opts.direction)); return Status::OK(); } // Remove the provided doc from the index. - Status BtreeBasedAccessMethod::remove(OperationContext* txn, - const BSONObj &obj, - const RecordId& loc, - const InsertDeleteOptions &options, - int64_t* numDeleted) { + Status IndexAccessMethod::remove(OperationContext* txn, + const BSONObj &obj, + const RecordId& loc, + const InsertDeleteOptions &options, + int64_t* numDeleted) { BSONObjSet keys; getKeys(obj, &keys); @@ -209,11 +209,11 @@ namespace mongo { } } - Status BtreeBasedAccessMethod::initializeAsEmpty(OperationContext* txn) { + Status IndexAccessMethod::initializeAsEmpty(OperationContext* txn) { return _newInterface->initAsEmpty(txn); } - Status BtreeBasedAccessMethod::touch(OperationContext* txn, const BSONObj& obj) { + Status IndexAccessMethod::touch(OperationContext* txn, const BSONObj& obj) { BSONObjSet keys; getKeys(obj, &keys); @@ -226,11 +226,11 @@ namespace mongo { } - Status BtreeBasedAccessMethod::touch( OperationContext* txn ) const { + Status IndexAccessMethod::touch( OperationContext* txn ) const { return _newInterface->touch(txn); } - RecordId BtreeBasedAccessMethod::findSingle(OperationContext* txn, const BSONObj& key) const { + RecordId IndexAccessMethod::findSingle(OperationContext* txn, const BSONObj& key) const { boost::scoped_ptr cursor(_newInterface->newCursor(txn, 1)); cursor->locate(key, RecordId::min()); @@ -249,8 +249,8 @@ namespace mongo { return cursor->getRecordId(); } - Status BtreeBasedAccessMethod::validate(OperationContext* txn, bool full, int64_t* numKeys, - BSONObjBuilder* output) { + Status IndexAccessMethod::validate(OperationContext* txn, bool full, int64_t* numKeys, + BSONObjBuilder* output) { // XXX: long long vs int64_t long long keys = 0; _newInterface->fullValidate(txn, full, &keys, output); @@ -258,81 +258,75 @@ namespace mongo { return Status::OK(); } - bool BtreeBasedAccessMethod::appendCustomStats(OperationContext* txn, - BSONObjBuilder* output, - double scale) const { + bool IndexAccessMethod::appendCustomStats(OperationContext* txn, + BSONObjBuilder* output, + double scale) const { return _newInterface->appendCustomStats(txn, output, scale); } - long long BtreeBasedAccessMethod::getSpaceUsedBytes( OperationContext* txn ) const { + long long IndexAccessMethod::getSpaceUsedBytes( OperationContext* txn ) const { return _newInterface->getSpaceUsedBytes( txn ); } - Status BtreeBasedAccessMethod::validateUpdate(OperationContext* txn, - const BSONObj &from, - const BSONObj &to, - const RecordId &record, - const InsertDeleteOptions &options, - UpdateTicket* status) { + Status IndexAccessMethod::validateUpdate(OperationContext* txn, + const BSONObj &from, + const BSONObj &to, + const RecordId &record, + const InsertDeleteOptions &options, + UpdateTicket* ticket) { - BtreeBasedPrivateUpdateData *data = new BtreeBasedPrivateUpdateData(); - status->_indexSpecificUpdateData.reset(data); + getKeys(from, &ticket->oldKeys); + getKeys(to, &ticket->newKeys); + ticket->loc = record; + ticket->dupsAllowed = options.dupsAllowed; - getKeys(from, &data->oldKeys); - getKeys(to, &data->newKeys); - data->loc = record; - data->dupsAllowed = options.dupsAllowed; + setDifference(ticket->oldKeys, ticket->newKeys, &ticket->removed); + setDifference(ticket->newKeys, ticket->oldKeys, &ticket->added); - setDifference(data->oldKeys, data->newKeys, &data->removed); - setDifference(data->newKeys, data->oldKeys, &data->added); - - status->_isValid = true; + ticket->_isValid = true; return Status::OK(); } - Status BtreeBasedAccessMethod::update(OperationContext* txn, - const UpdateTicket& ticket, - int64_t* numUpdated) { + Status IndexAccessMethod::update(OperationContext* txn, + const UpdateTicket& ticket, + int64_t* numUpdated) { if (!ticket._isValid) { return Status(ErrorCodes::InternalError, "Invalid UpdateTicket in update"); } - BtreeBasedPrivateUpdateData* data = - static_cast(ticket._indexSpecificUpdateData.get()); - - if (data->oldKeys.size() + data->added.size() - data->removed.size() > 1) { + if (ticket.oldKeys.size() + ticket.added.size() - ticket.removed.size() > 1) { _btreeState->setMultikey( txn ); } - for (size_t i = 0; i < data->removed.size(); ++i) { + for (size_t i = 0; i < ticket.removed.size(); ++i) { _newInterface->unindex(txn, - *data->removed[i], - data->loc, - data->dupsAllowed); + *ticket.removed[i], + ticket.loc, + ticket.dupsAllowed); } - for (size_t i = 0; i < data->added.size(); ++i) { + for (size_t i = 0; i < ticket.added.size(); ++i) { Status status = _newInterface->insert(txn, - *data->added[i], - data->loc, - data->dupsAllowed); + *ticket.added[i], + ticket.loc, + ticket.dupsAllowed); if ( !status.isOK() ) { return status; } } - *numUpdated = data->added.size(); + *numUpdated = ticket.added.size(); return Status::OK(); } - std::unique_ptr BtreeBasedAccessMethod::initiateBulk() { + std::unique_ptr IndexAccessMethod::initiateBulk() { return std::unique_ptr(new BulkBuilder(this, _descriptor)); } - IndexAccessMethod::BulkBuilder::BulkBuilder(const BtreeBasedAccessMethod* index, + IndexAccessMethod::BulkBuilder::BulkBuilder(const IndexAccessMethod* index, const IndexDescriptor* descriptor) : _sorter(Sorter::make(SortOptions().TempDir(storageGlobalParams.dbpath + "/_tmp") .ExtSortAllowed() @@ -364,11 +358,12 @@ namespace mongo { return Status::OK(); } - Status BtreeBasedAccessMethod::commitBulk(OperationContext* txn, - std::unique_ptr bulk, - bool mayInterrupt, - bool dupsAllowed, - set* dupsToDrop) { + + Status IndexAccessMethod::commitBulk(OperationContext* txn, + std::unique_ptr bulk, + bool mayInterrupt, + bool dupsAllowed, + set* dupsToDrop) { Timer timer; diff --git a/src/mongo/db/index/index_access_method.h b/src/mongo/db/index/index_access_method.h index a371f65b33c..5d4b21d785a 100644 --- a/src/mongo/db/index/index_access_method.h +++ b/src/mongo/db/index/index_access_method.h @@ -28,22 +28,22 @@ #pragma once -#include #include +#include "mongo/base/disallow_copying.h" #include "mongo/db/index/index_cursor.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/jsobj.h" #include "mongo/db/operation_context.h" #include "mongo/db/record_id.h" #include "mongo/db/sorter/sorter.h" +#include "mongo/db/storage/sorted_data_interface.h" namespace mongo { class BSONObjBuilder; class UpdateTicket; struct InsertDeleteOptions; - class BtreeBasedAccessMethod; /** * An IndexAccessMethod is the interface through which all the mutation, lookup, and @@ -56,7 +56,10 @@ namespace mongo { * */ class IndexAccessMethod { + MONGO_DISALLOW_COPYING(IndexAccessMethod); public: + + IndexAccessMethod(IndexCatalogEntry* btreeState, SortedDataInterface* btree); virtual ~IndexAccessMethod() { } // @@ -71,21 +74,21 @@ namespace mongo { * * The behavior of the insertion can be specified through 'options'. */ - virtual Status insert(OperationContext* txn, - const BSONObj& obj, - const RecordId& loc, - const InsertDeleteOptions& options, - int64_t* numInserted) = 0; + Status insert(OperationContext* txn, + const BSONObj& obj, + const RecordId& loc, + const InsertDeleteOptions& options, + int64_t* numInserted); /** * Analogous to above, but remove the records instead of inserting them. If not NULL, * numDeleted will be set to the number of keys removed from the index for the document. */ - virtual Status remove(OperationContext* txn, - const BSONObj& obj, - const RecordId& loc, - const InsertDeleteOptions& options, - int64_t* numDeleted) = 0; + Status remove(OperationContext* txn, + const BSONObj& obj, + const RecordId& loc, + const InsertDeleteOptions& options, + int64_t* numDeleted); /** * Checks whether the index entries for the document 'from', which is placed at location @@ -97,12 +100,12 @@ namespace mongo { * * There is no obligation to perform the update after performing validation. */ - virtual Status validateUpdate(OperationContext* txn, - const BSONObj& from, - const BSONObj& to, - const RecordId& loc, - const InsertDeleteOptions& options, - UpdateTicket* ticket) = 0; + Status validateUpdate(OperationContext* txn, + const BSONObj& from, + const BSONObj& to, + const RecordId& loc, + const InsertDeleteOptions& options, + UpdateTicket* ticket); /** * Perform a validated update. The keys for the 'from' object will be removed, and the keys @@ -112,15 +115,13 @@ namespace mongo { * called. If the index was changed, we may return an error, as our ticket may have been * invalidated. */ - virtual Status update(OperationContext* txn, - const UpdateTicket& ticket, - int64_t* numUpdated) = 0; + Status update(OperationContext* txn, const UpdateTicket& ticket, int64_t* numUpdated); /** * Fills in '*out' with an IndexCursor. Return a status indicating success or reason of * failure. If the latter, '*out' contains NULL. See index_cursor.h for IndexCursor usage. */ - virtual Status newCursor(OperationContext* txn, const CursorOptions& opts, IndexCursor** out) const = 0; + Status newCursor(OperationContext* txn, const CursorOptions& opts, IndexCursor** out) const; // ------ index level operations ------ @@ -130,7 +131,7 @@ namespace mongo { * only called once for the lifetime of the index * if called multiple times, is an error */ - virtual Status initializeAsEmpty(OperationContext* txn) = 0; + Status initializeAsEmpty(OperationContext* txn); /** * Try to page-in the pages that contain the keys generated from 'obj'. @@ -138,12 +139,12 @@ namespace mongo { * appropriate pages are not swapped out. * See prefetch.cpp. */ - virtual Status touch(OperationContext* txn, const BSONObj& obj) = 0; + Status touch(OperationContext* txn, const BSONObj& obj); /** * this pages in the entire index */ - virtual Status touch(OperationContext* txn) const = 0; + Status touch(OperationContext* txn) const; /** * Walk the entire index, checking the internal structure for consistency. @@ -157,8 +158,7 @@ namespace mongo { * Currently wasserts that the index is invalid. This could/should be changed in * the future to return a Status. */ - virtual Status validate(OperationContext* txn, bool full, int64_t* numKeys, - BSONObjBuilder* output) = 0; + Status validate(OperationContext* txn, bool full, int64_t* numKeys, BSONObjBuilder* output); /** * Add custom statistics about this index to BSON object builder, for display. @@ -167,14 +167,16 @@ namespace mongo { * * Returns true if stats were appended. */ - virtual bool appendCustomStats(OperationContext* txn, BSONObjBuilder* result, double scale) - const = 0; + bool appendCustomStats(OperationContext* txn, BSONObjBuilder* result, double scale) const; /** * @return The number of bytes consumed by this index. * Exactly what is counted is not defined based on padding, re-use, etc... */ - virtual long long getSpaceUsedBytes( OperationContext* txn ) const = 0; + long long getSpaceUsedBytes( OperationContext* txn ) const; + + // XXX: consider migrating callers to use IndexCursor instead + RecordId findSingle( OperationContext* txn, const BSONObj& key ) const; // // Bulk operations support @@ -192,14 +194,14 @@ namespace mongo { int64_t* numInserted); private: - friend class BtreeBasedAccessMethod; + friend class IndexAccessMethod; using Sorter = mongo::Sorter; - BulkBuilder(const BtreeBasedAccessMethod* index, const IndexDescriptor* descriptor); + BulkBuilder(const IndexAccessMethod* index, const IndexDescriptor* descriptor); std::unique_ptr _sorter; - const BtreeBasedAccessMethod* _real; + const IndexAccessMethod* _real; int64_t _keysInserted = 0; bool _isMultiKey = false; }; @@ -211,7 +213,7 @@ namespace mongo { * * It is only legal to initiate bulk when the index is new and empty. */ - virtual std::unique_ptr initiateBulk() = 0; + std::unique_ptr initiateBulk(); /** * Call this when you are ready to finish your bulk work. @@ -222,41 +224,56 @@ namespace mongo { * @param dups - if NULL, error out on dups if not allowed * if not NULL, put the bad RecordIds there */ - virtual Status commitBulk( OperationContext* txn, - std::unique_ptr bulk, - bool mayInterrupt, - bool dupsAllowed, - std::set* dups ) = 0; + Status commitBulk(OperationContext* txn, + std::unique_ptr bulk, + bool mayInterrupt, + bool dupsAllowed, + std::set* dups); /** * Fills 'keys' with the keys that should be generated for 'obj' on this index. */ virtual void getKeys(const BSONObj &obj, BSONObjSet *keys) const = 0; + + protected: + // Determines whether it's OK to ignore ErrorCodes::KeyTooLong for this OperationContext + bool ignoreKeyTooLong(OperationContext* txn); + + IndexCatalogEntry* _btreeState; // owned by IndexCatalogEntry + const IndexDescriptor* _descriptor; + + private: + void removeOneKey(OperationContext* txn, + const BSONObj& key, + const RecordId& loc, + bool dupsAllowed); + + const std::unique_ptr _newInterface; }; + // Temporary typedef to old name + using BtreeBasedAccessMethod = IndexAccessMethod; + /** * Updates are two steps: verify that it's a valid update, and perform it. * validateUpdate fills out the UpdateStatus and update actually applies it. */ class UpdateTicket { - public: - UpdateTicket() : _isValid(false) { } - - protected: - // These friends are the classes that actually fill out an UpdateStatus. - friend class BtreeBasedAccessMethod; - - class PrivateUpdateData; + // No public interface + private: + friend class IndexAccessMethod; bool _isValid; - // This is meant to be filled out only by the friends above. - boost::scoped_ptr _indexSpecificUpdateData; - }; + BSONObjSet oldKeys; + BSONObjSet newKeys; - class UpdateTicket::PrivateUpdateData { - public: - virtual ~PrivateUpdateData() { } + // These point into the sets oldKeys and newKeys. + std::vector removed; + std::vector added; + + RecordId loc; + bool dupsAllowed; }; /** diff --git a/src/mongo/db/index/btree_index_cursor.cpp b/src/mongo/db/index/index_cursor.cpp similarity index 72% rename from src/mongo/db/index/btree_index_cursor.cpp rename to src/mongo/db/index/index_cursor.cpp index 05ffe8d65bc..de09e7c1d3d 100644 --- a/src/mongo/db/index/btree_index_cursor.cpp +++ b/src/mongo/db/index/index_cursor.cpp @@ -26,7 +26,7 @@ * it in the license file. */ -#include "mongo/db/index/btree_index_cursor.h" +#include "mongo/db/index/index_cursor.h" #include @@ -42,27 +42,27 @@ namespace mongo { using std::string; using std::vector; - BtreeIndexCursor::BtreeIndexCursor(SortedDataInterface::Cursor* cursor) : _cursor(cursor) { } + IndexCursor::IndexCursor(SortedDataInterface::Cursor* cursor) : _cursor(cursor) { } - bool BtreeIndexCursor::isEOF() const { return _cursor->isEOF(); } + bool IndexCursor::isEOF() const { return _cursor->isEOF(); } - Status BtreeIndexCursor::seek(const BSONObj& position) { + Status IndexCursor::seek(const BSONObj& position) { _cursor->locate(position, 1 == _cursor->getDirection() ? RecordId::min() : RecordId::max()); return Status::OK(); } - void BtreeIndexCursor::seek(const BSONObj& position, bool afterKey) { + void IndexCursor::seek(const BSONObj& position, bool afterKey) { const bool forward = (1 == _cursor->getDirection()); _cursor->locate(position, (afterKey == forward) ? RecordId::max() : RecordId::min()); } - bool BtreeIndexCursor::pointsAt(const BtreeIndexCursor& other) { + bool IndexCursor::pointsAt(const IndexCursor& other) { return _cursor->pointsToSamePlaceAs(*other._cursor); } - Status BtreeIndexCursor::seek(const vector& position, - const vector& inclusive) { + Status IndexCursor::seek(const vector& position, + const vector& inclusive) { BSONObj emptyObj; @@ -74,11 +74,11 @@ namespace mongo { return Status::OK(); } - Status BtreeIndexCursor::skip(const BSONObj &keyBegin, - int keyBeginLen, - bool afterKey, - const vector& keyEnd, - const vector& keyEndInclusive) { + Status IndexCursor::skip(const BSONObj &keyBegin, + int keyBeginLen, + bool afterKey, + const vector& keyEnd, + const vector& keyEndInclusive) { _cursor->advanceTo(keyBegin, keyBeginLen, @@ -88,35 +88,35 @@ namespace mongo { return Status::OK(); } - BSONObj BtreeIndexCursor::getKey() const { + BSONObj IndexCursor::getKey() const { return _cursor->getKey(); } - RecordId BtreeIndexCursor::getValue() const { + RecordId IndexCursor::getValue() const { return _cursor->getRecordId(); } - void BtreeIndexCursor::next() { + void IndexCursor::next() { advance(); } - Status BtreeIndexCursor::savePosition() { + Status IndexCursor::savePosition() { _cursor->savePosition(); return Status::OK(); } - Status BtreeIndexCursor::restorePosition(OperationContext* txn) { + Status IndexCursor::restorePosition(OperationContext* txn) { _cursor->restorePosition(txn); return Status::OK(); } - string BtreeIndexCursor::toString() { + string IndexCursor::toString() { // TODO: is this ever called? return "I AM A BTREE INDEX CURSOR!\n"; } // Move to the next/prev. key. Used by normal getNext and also skipping unused keys. - void BtreeIndexCursor::advance() { + void IndexCursor::advance() { _cursor->advance(); } diff --git a/src/mongo/db/index/index_cursor.h b/src/mongo/db/index/index_cursor.h index 36fb78ed497..896cde2b331 100644 --- a/src/mongo/db/index/index_cursor.h +++ b/src/mongo/db/index/index_cursor.h @@ -28,16 +28,23 @@ #pragma once +#include #include +#include "mongo/base/status.h" +#include "mongo/db/index/index_cursor.h" +#include "mongo/db/index/index_descriptor.h" #include "mongo/db/jsobj.h" #include "mongo/db/record_id.h" +#include "mongo/db/storage/sorted_data_interface.h" namespace mongo { struct CursorOptions; /** + * TODO remove this class in favor of direct usage of SortedDataInterface::Cursor. + * * An IndexCursor is the interface through which one traverses the entries of a given * index. The internal structure of an index is kept isolated. * @@ -53,7 +60,6 @@ namespace mongo { */ class IndexCursor { public: - virtual ~IndexCursor() { } /** * A cursor doesn't point anywhere by default. You must seek to the start position. @@ -65,27 +71,50 @@ namespace mongo { * 2. Success: seeked to 'closest' key oriented according to the cursor's direction. * 3. Error: can't seek to the position. */ - virtual Status seek(const BSONObj& position) = 0; + Status seek(const BSONObj& position); + + Status seek(const std::vector& position, + const std::vector& inclusive); + + /** + * Seek to the key 'position'. If 'afterKey' is true, seeks to the first + * key that is oriented after 'position'. + * + * Btree-specific. + */ + void seek(const BSONObj& position, bool afterKey); + + Status skip(const BSONObj& keyBegin, + int keyBeginLen, + bool afterKey, + const std::vector& keyEnd, + const std::vector& keyEndInclusive); + + /** + * Returns true if 'this' points at the same exact key as 'other'. + * Returns false otherwise. + */ + bool pointsAt(const IndexCursor& other); // // Iteration support // // Are we out of documents? - virtual bool isEOF() const = 0; + bool isEOF() const; // Move to the next key/value pair. Assumes !isEOF(). - virtual void next() = 0; + void next(); // // Accessors // // Current key we point at. Assumes !isEOF(). - virtual BSONObj getKey() const = 0; + BSONObj getKey() const; // Current value we point at. Assumes !isEOF(). - virtual RecordId getValue() const = 0; + RecordId getValue() const; // // Yielding support @@ -106,24 +135,44 @@ namespace mongo { /** * Save our current position in the index. */ - virtual Status savePosition() = 0; + Status savePosition(); /** * Restore the saved position. Errors if there is no saved position. * The cursor may be EOF after a restore. */ - virtual Status restorePosition(OperationContext* txn) = 0; - - // Return a std::string describing the cursor. - virtual std::string toString() = 0; + Status restorePosition(OperationContext* txn); /** - * Add debugging info to the provided builder. - * TODO(hk): We can do this better, perhaps with a more structured format. + * Return a std::string describing the cursor. */ - virtual void explainDetails(BSONObjBuilder* b) { } + std::string toString(); + + private: + // We keep the constructor private and only allow the AM to create us. + friend class IndexAccessMethod; + + /** + * interface is an abstraction to hide the fact that we have two types of Btrees. + * + * Intentionally private, we're friends with the only class allowed to call it. + */ + IndexCursor(SortedDataInterface::Cursor* cursor); + + bool isSavedPositionValid(); + + /** + * Move to the next (or previous depending on the direction) key. Used by normal getNext + * and also skipping unused keys. + */ + void advance(); + + const std::unique_ptr _cursor; }; + // Temporary typedef to old name + using BtreeIndexCursor = IndexCursor; + // All the options we might want to set on a cursor. struct CursorOptions { // Set the direction of the scan. Ignored if the cursor doesn't have directions (geo). diff --git a/src/mongo/db/index/s2_access_method.h b/src/mongo/db/index/s2_access_method.h index 6954d8a4939..fe343e77fad 100644 --- a/src/mongo/db/index/s2_access_method.h +++ b/src/mongo/db/index/s2_access_method.h @@ -30,7 +30,7 @@ #include "mongo/base/status.h" #include "mongo/db/index/s2_common.h" -#include "mongo/db/index/btree_based_access_method.h" +#include "mongo/db/index/index_access_method.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/jsobj.h" diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp index afd0a2b2efa..06d89b5da4c 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp @@ -38,7 +38,7 @@ #include "mongo/db/catalog/index_catalog_entry.h" #include "mongo/db/index/2d_access_method.h" #include "mongo/db/index/btree_access_method.h" -#include "mongo/db/index/btree_based_access_method.h" +#include "mongo/db/index/index_access_method.h" #include "mongo/db/index/fts_access_method.h" #include "mongo/db/index/hash_access_method.h" #include "mongo/db/index/haystack_access_method.h"