summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorEliot Horowitz <eliot@10gen.com>2014-05-19 16:05:41 -0400
committerEliot Horowitz <eliot@10gen.com>2014-05-19 16:05:41 -0400
commitdb0e1a91fdce2fa43584408a87d637cfe4bcc2ec (patch)
tree8cbefae4f2f43f41f4a512f5b8f250b1662dfbbf /src/mongo/db
parentf2bfd36a6f3eb7e7e2587268be3cc12636703d42 (diff)
downloadmongo-db0e1a91fdce2fa43584408a87d637cfe4bcc2ec.tar.gz
SERVER-13637: add CollectionCatalogEntry, start Database layer
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/catalog/collection.cpp187
-rw-r--r--src/mongo/db/catalog/collection.h55
-rw-r--r--src/mongo/db/catalog/collection_catalog_entry.h97
-rw-r--r--src/mongo/db/catalog/database.cpp207
-rw-r--r--src/mongo/db/catalog/database.h37
-rw-r--r--src/mongo/db/catalog/database_holder.cpp1
-rw-r--r--src/mongo/db/catalog/index_catalog.cpp271
-rw-r--r--src/mongo/db/catalog/index_catalog.h25
-rw-r--r--src/mongo/db/catalog/index_catalog_entry.cpp51
-rw-r--r--src/mongo/db/catalog/index_catalog_entry.h24
-rw-r--r--src/mongo/db/catalog/index_create.cpp6
-rw-r--r--src/mongo/db/commands/dbhash.cpp3
-rw-r--r--src/mongo/db/db.cpp11
-rw-r--r--src/mongo/db/dbcommands.cpp44
-rw-r--r--src/mongo/db/dbhelpers.h4
-rw-r--r--src/mongo/db/exec/2d.cpp6
-rw-r--r--src/mongo/db/exec/2dcommon.cpp16
-rw-r--r--src/mongo/db/exec/2dcommon.h9
-rw-r--r--src/mongo/db/exec/2dnear.cpp15
-rw-r--r--src/mongo/db/exec/2dnear.h6
-rw-r--r--src/mongo/db/geo/haystack.cpp2
-rw-r--r--src/mongo/db/index/2d_access_method.cpp5
-rw-r--r--src/mongo/db/index/2d_access_method.h3
-rw-r--r--src/mongo/db/index/btree_access_method.cpp4
-rw-r--r--src/mongo/db/index/btree_access_method.h3
-rw-r--r--src/mongo/db/index/btree_based_access_method.cpp25
-rw-r--r--src/mongo/db/index/btree_based_access_method.h14
-rw-r--r--src/mongo/db/index/btree_based_bulk_access_method.cpp2
-rw-r--r--src/mongo/db/index/btree_based_bulk_access_method.h2
-rw-r--r--src/mongo/db/index/fts_access_method.cpp4
-rw-r--r--src/mongo/db/index/fts_access_method.h2
-rw-r--r--src/mongo/db/index/hash_access_method.cpp4
-rw-r--r--src/mongo/db/index/hash_access_method.h2
-rw-r--r--src/mongo/db/index/haystack_access_method.cpp11
-rw-r--r--src/mongo/db/index/haystack_access_method.h7
-rw-r--r--src/mongo/db/index/index_access_method.h2
-rw-r--r--src/mongo/db/index/s2_access_method.cpp4
-rw-r--r--src/mongo/db/index/s2_access_method.h2
-rw-r--r--src/mongo/db/index_rebuilder.cpp3
-rw-r--r--src/mongo/db/namespace_string.h1
-rw-r--r--src/mongo/db/operation_context.h6
-rw-r--r--src/mongo/db/operation_context_impl.cpp6
-rw-r--r--src/mongo/db/operation_context_impl.h2
-rw-r--r--src/mongo/db/operation_context_noop.h4
-rw-r--r--src/mongo/db/repair_database.cpp1
-rw-r--r--src/mongo/db/storage/mmap_v1/mmap_v1_engine.cpp333
-rw-r--r--src/mongo/db/storage/mmap_v1/mmap_v1_engine.h111
-rw-r--r--src/mongo/db/structure/btree/btree_logic.h1
-rw-r--r--src/mongo/db/structure/catalog/namespace_details.cpp239
-rw-r--r--src/mongo/db/structure/catalog/namespace_details.h153
-rw-r--r--src/mongo/db/structure/catalog/namespace_details_collection_entry.cpp325
-rw-r--r--src/mongo/db/structure/catalog/namespace_details_collection_entry.h104
-rw-r--r--src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.cpp225
-rw-r--r--src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.h118
-rw-r--r--src/mongo/db/structure/catalog/namespace_index.cpp4
-rw-r--r--src/mongo/db/structure/catalog/namespace_index.h8
-rw-r--r--src/mongo/db/structure/record_store.h53
-rw-r--r--src/mongo/db/structure/record_store_v1_base.cpp137
-rw-r--r--src/mongo/db/structure/record_store_v1_base.h33
-rw-r--r--src/mongo/db/structure/record_store_v1_capped.h4
-rw-r--r--src/mongo/db/structure/record_store_v1_test_help.cpp24
-rw-r--r--src/mongo/db/structure/record_store_v1_test_help.h5
62 files changed, 1883 insertions, 1190 deletions
diff --git a/src/mongo/db/catalog/collection.cpp b/src/mongo/db/catalog/collection.cpp
index d2f4f5f7190..861a3bbb02f 100644
--- a/src/mongo/db/catalog/collection.cpp
+++ b/src/mongo/db/catalog/collection.cpp
@@ -35,6 +35,7 @@
#include "mongo/db/clientcursor.h"
#include "mongo/db/commands/server_status_metric.h"
#include "mongo/db/curop.h"
+#include "mongo/db/catalog/collection_catalog_entry.h"
#include "mongo/db/catalog/database.h"
#include "mongo/db/catalog/index_create.h"
#include "mongo/db/dbhelpers.h"
@@ -44,11 +45,9 @@
#include "mongo/db/structure/catalog/namespace_details.h"
#include "mongo/db/structure/catalog/namespace_details_rsv1_metadata.h"
#include "mongo/db/structure/record_store_v1_capped.h"
-#include "mongo/db/structure/record_store_v1_simple.h"
#include "mongo/db/repl/rs.h"
#include "mongo/db/storage/extent.h"
#include "mongo/db/storage/extent_manager.h"
-#include "mongo/db/storage/mmap_v1/mmap_v1_extent_manager.h"
#include "mongo/db/storage/record.h"
#include "mongo/db/auth/user_document_parser.h" // XXX-ANDY
@@ -78,33 +77,20 @@ namespace mongo {
Collection::Collection( OperationContext* txn,
const StringData& fullNS,
- NamespaceDetails* details,
+ CollectionCatalogEntry* details,
+ RecordStore* recordStore,
Database* database )
: _ns( fullNS ),
+ _details( details ),
+ _recordStore( recordStore ),
+ _database( database ),
_infoCache( this ),
- _indexCatalog( this, details ),
+ _indexCatalog( this ),
_cursorCache( fullNS ) {
-
- _details = details;
- _database = database;
-
- if ( details->isCapped() ) {
- _recordStore.reset( new CappedRecordStoreV1( txn,
- this,
- _ns.ns(),
- new NamespaceDetailsRSV1MetaData( details ),
- database->getExtentManager(),
- _ns.coll() == "system.indexes" ) );
- }
- else {
- _recordStore.reset( new SimpleRecordStoreV1( txn,
- _ns.ns(),
- new NamespaceDetailsRSV1MetaData( details ),
- database->getExtentManager(),
- _ns.coll() == "system.indexes" ) );
- }
_magic = 1357924;
_indexCatalog.init(txn);
+ if ( isCapped() )
+ _recordStore->setCappedDeleteCallback( this );
}
Collection::~Collection() {
@@ -203,12 +189,7 @@ namespace mongo {
return StatusWith<DiskLoc>( ret );
}
- StatusWith<DiskLoc> status = _insertDocument( txn, docToInsert, enforceQuota );
- if ( status.isOK() ) {
- _details->paddingFits( txn );
- }
-
- return status;
+ return _insertDocument( txn, docToInsert, enforceQuota );
}
StatusWith<DiskLoc> Collection::insertDocument( OperationContext* txn,
@@ -364,21 +345,21 @@ namespace mongo {
}
}
- if ( oldRecord->netLength() < objNew.objsize() ) {
- // doesn't fit, have to move to new location
+ // this can callback into Collection::recordStoreGoingToMove
+ StatusWith<DiskLoc> newLocation = _recordStore->updateRecord( txn,
+ oldLocation,
+ objNew.objdata(),
+ objNew.objsize(),
+ enforceQuota ? largestFileNumberInQuota() : 0,
+ this );
- if ( isCapped() )
- return StatusWith<DiskLoc>( ErrorCodes::InternalError,
- "failing update: objects in a capped ns cannot grow",
- 10003 );
+ if ( !newLocation.isOK() ) {
+ return newLocation;
+ }
- moveCounter.increment();
- _details->paddingTooSmall( txn );
+ _infoCache.notifyOfWriteOp();
- // unindex old record, don't delete
- // this way, if inserting new doc fails, we can re-index this one
- _cursorCache.invalidateDocument(oldLocation, INVALIDATION_DELETION);
- _indexCatalog.unindexRecord(txn, objOld, oldLocation, true);
+ if ( newLocation.getValue() != oldLocation ) {
if ( debug ) {
if (debug->nmoved == -1) // default of -1 rather than 0
@@ -387,24 +368,11 @@ namespace mongo {
debug->nmoved += 1;
}
- StatusWith<DiskLoc> loc = _insertDocument( txn, objNew, enforceQuota );
-
- if ( loc.isOK() ) {
- // insert successful, now lets deallocate the old location
- // remember its already unindexed
- _recordStore->deleteRecord( txn, oldLocation );
- }
- else {
- // new doc insert failed, so lets re-index the old document and location
- _indexCatalog.indexRecord(txn, objOld, oldLocation);
- }
+ _indexCatalog.indexRecord(txn, objNew, newLocation.getValue());
- return loc;
+ return newLocation;
}
- _infoCache.notifyOfWriteOp();
- _details->paddingFits( txn );
-
if ( debug )
debug->keyUpdates = 0;
@@ -424,13 +392,20 @@ namespace mongo {
// Broadcast the mutation so that query results stay correct.
_cursorCache.invalidateDocument(oldLocation, INVALIDATION_MUTATION);
- // update in place
- int sz = objNew.objsize();
- memcpy(txn->recoveryUnit()->writingPtr(oldRecord->data(), sz), objNew.objdata(), sz);
+ return newLocation;
+ }
- return StatusWith<DiskLoc>( oldLocation );
+ Status Collection::recordStoreGoingToMove( OperationContext* txn,
+ const DiskLoc& oldLocation,
+ const char* oldBuffer,
+ size_t oldSize ) {
+ moveCounter.increment();
+ _cursorCache.invalidateDocument(oldLocation, INVALIDATION_DELETION);
+ _indexCatalog.unindexRecord(txn, BSONObj(oldBuffer), oldLocation, true);
+ return Status::OK();
}
+
Status Collection::updateDocumentWithDamages( OperationContext* txn,
const DiskLoc& loc,
const char* damangeSource,
@@ -438,36 +413,7 @@ namespace mongo {
// Broadcast the mutation so that query results stay correct.
_cursorCache.invalidateDocument(loc, INVALIDATION_MUTATION);
-
- _details->paddingFits( txn );
-
- Record* rec = _recordStore->recordFor( loc );
- char* root = rec->data();
-
- // All updates were in place. Apply them via durability and writing pointer.
- mutablebson::DamageVector::const_iterator where = damages.begin();
- const mutablebson::DamageVector::const_iterator end = damages.end();
- for( ; where != end; ++where ) {
- const char* sourcePtr = damangeSource + where->sourceOffset;
- void* targetPtr = txn->recoveryUnit()->writingPtr(root + where->targetOffset, where->size);
- std::memcpy(targetPtr, sourcePtr, where->size);
- }
-
- return Status::OK();
- }
-
- ExtentManager* Collection::getExtentManager() {
- verify( ok() );
- return _database->getExtentManager();
- }
-
- const ExtentManager* Collection::getExtentManager() const {
- verify( ok() );
- return _database->getExtentManager();
- }
-
- void Collection::increaseStorageSize(OperationContext* txn, int size, bool enforceQuota) {
- _recordStore->increaseStorageSize(txn, size, enforceQuota ? largestFileNumberInQuota() : 0);
+ return _recordStore->updateWithDamages( txn, loc, damangeSource, damages );
}
int Collection::largestFileNumberInQuota() const {
@@ -483,19 +429,8 @@ namespace mongo {
return storageGlobalParams.quotaFiles;
}
- void Collection::appendCustomStats( BSONObjBuilder* result, double scale ) const {
- result->append( "lastExtentSize", _details->lastExtentSize() / scale );
- result->append( "paddingFactor", _details->paddingFactor() );
- result->append( "userFlags", _details->userFlags() );
-
- if ( isCapped() ) {
- result->appendBool( "capped", true );
- result->appendNumber( "max", _details->maxCappedDocs() );
- }
- }
-
bool Collection::isCapped() const {
- return _details->isCapped();
+ return _recordStore->isCapped();
}
uint64_t Collection::numRecords() const {
@@ -643,52 +578,4 @@ namespace mongo {
return Status::OK();
}
- bool Collection::isUserFlagSet( int flag ) const {
- return _details->isUserFlagSet( flag );
- }
-
- bool Collection::setUserFlag( OperationContext* txn, int flag ) {
- if ( !_details->setUserFlag( txn, flag ) )
- return false;
- _syncUserFlags(txn);
- return true;
- }
-
- bool Collection::clearUserFlag( OperationContext* txn, int flag ) {
- if ( !_details->clearUserFlag( txn, flag ) )
- return false;
- _syncUserFlags(txn);
- return true;
- }
-
- void Collection::_syncUserFlags(OperationContext* txn) {
- if ( _ns.coll() == "system.namespaces" )
- return;
- string system_namespaces = _ns.getSisterNS( "system.namespaces" );
- Collection* coll = _database->getCollection( txn, system_namespaces );
-
- DiskLoc oldLocation = Helpers::findOne( coll, BSON( "name" << _ns.ns() ), false );
- fassert( 17247, !oldLocation.isNull() );
-
- BSONObj oldEntry = coll->docFor( oldLocation );
-
- BSONObj newEntry = applyUpdateOperators( oldEntry,
- BSON( "$set" <<
- BSON( "options.flags" <<
- _details->userFlags() ) ) );
-
- StatusWith<DiskLoc> loc = coll->updateDocument( txn, oldLocation, newEntry, false, NULL );
- if ( !loc.isOK() ) {
- // TODO: should this be an fassert?
- error() << "syncUserFlags failed! "
- << " ns: " << _ns
- << " error: " << loc.toString();
- }
-
- }
-
- void Collection::setMaxCappedDocs( OperationContext* txn, long long max ) {
- _details->setMaxCappedDocs( txn, max );
- }
-
}
diff --git a/src/mongo/db/catalog/collection.h b/src/mongo/db/catalog/collection.h
index 8cccf53dc4a..bad0a78ae10 100644
--- a/src/mongo/db/catalog/collection.h
+++ b/src/mongo/db/catalog/collection.h
@@ -46,9 +46,9 @@
namespace mongo {
+ class CollectionCatalogEntry;
class Database;
class ExtentManager;
- class NamespaceDetails;
class IndexCatalog;
class MultiIndexBlock;
class OperationContext;
@@ -100,19 +100,20 @@ namespace mongo {
* this is NOT safe through a yield right now
* not sure if it will be, or what yet
*/
- class Collection : CappedDocumentDeleteCallback {
+ class Collection : CappedDocumentDeleteCallback, UpdateMoveNotifier {
public:
Collection( OperationContext* txn,
const StringData& fullNS,
- NamespaceDetails* details,
- Database* database );
+ CollectionCatalogEntry* details, // takes ownership
+ RecordStore* recordStore, // takes ownership
+ Database* database ); // does not own
~Collection();
bool ok() const { return _magic == 1357924; }
- NamespaceDetails* detailsWritable() { return _details; } // TODO: remove
- const NamespaceDetails* detailsDeprecated() const { return _details; }
+ CollectionCatalogEntry* getCatalogEntry() { return _details.get(); }
+ const CollectionCatalogEntry* getCatalogEntry() const { return _details.get(); }
CollectionInfoCache* infoCache() { return &_infoCache; }
const CollectionInfoCache* infoCache() const { return &_infoCache; }
@@ -123,6 +124,7 @@ namespace mongo {
IndexCatalog* getIndexCatalog() { return &_indexCatalog; }
const RecordStore* getRecordStore() const { return _recordStore.get(); }
+ RecordStore* getRecordStore() { return _recordStore.get(); }
CollectionCursorCache* cursorCache() const { return &_cursorCache; }
@@ -236,23 +238,10 @@ namespace mongo {
// -----------
-
- // this is temporary, moving up from DB for now
- // this will add a new extent the collection
- // the new extent will be returned
- // it will have been added to the linked list already
- void increaseStorageSize( OperationContext* txn, int size, bool enforceQuota );
-
//
// Stats
//
- /**
- * @param scaleSize - amount by which to scale size metrics
- * appends any custom stats from the RecordStore or other unique stats
- */
- void appendCustomStats( BSONObjBuilder* resuits, double scaleSize = 1 ) const;
-
bool isCapped() const;
uint64_t numRecords() const;
@@ -266,16 +255,15 @@ namespace mongo {
return static_cast<int>( dataSize() / n );
}
- // TODO(erh) - below till next mark are suspect
- bool isUserFlagSet( int flag ) const;
- bool setUserFlag( OperationContext* txn, int flag );
- bool clearUserFlag( OperationContext* txn, int flag );
-
- void setMaxCappedDocs( OperationContext* txn, long long max );
// --- end suspect things
private:
+ Status recordStoreGoingToMove( OperationContext* txn,
+ const DiskLoc& oldLocation,
+ const char* oldBuffer,
+ size_t oldSize );
+
Status aboutToDeleteCapped( OperationContext* txn, const DiskLoc& loc );
/**
@@ -287,28 +275,15 @@ namespace mongo {
const BSONObj& doc,
bool enforceQuota );
- void _compactExtent(OperationContext* txn,
- const DiskLoc diskloc,
- int extentNumber,
- MultiIndexBlock& indexesToInsertTo,
- const CompactOptions* compactOptions,
- CompactStats* stats );
-
- void _syncUserFlags(OperationContext* txn); // TODO: this is bizarre, should go away
-
-
// @return 0 for inf., otherwise a number of files
int largestFileNumberInQuota() const;
- ExtentManager* getExtentManager();
- const ExtentManager* getExtentManager() const;
-
int _magic;
NamespaceString _ns;
- NamespaceDetails* _details;
- Database* _database;
+ scoped_ptr<CollectionCatalogEntry> _details;
scoped_ptr<RecordStore> _recordStore;
+ Database* _database;
CollectionInfoCache _infoCache;
IndexCatalog _indexCatalog;
diff --git a/src/mongo/db/catalog/collection_catalog_entry.h b/src/mongo/db/catalog/collection_catalog_entry.h
new file mode 100644
index 00000000000..b3c6b2c890c
--- /dev/null
+++ b/src/mongo/db/catalog/collection_catalog_entry.h
@@ -0,0 +1,97 @@
+// collection_catalog_entry.h
+
+/**
+ * Copyright (C) 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 "mongo/base/string_data.h"
+#include "mongo/db/diskloc.h"
+#include "mongo/db/namespace_string.h"
+
+namespace mongo {
+
+ class IndexDescriptor;
+ class OperationContext;
+
+ class CollectionCatalogEntry {
+ public:
+ CollectionCatalogEntry( const StringData& ns )
+ : _ns( ns ){
+ }
+ virtual ~CollectionCatalogEntry(){}
+
+ const NamespaceString& ns() const { return _ns; }
+
+ // ------- indexes ----------
+
+ virtual int getTotalIndexCount() const = 0;
+
+ virtual int getCompletedIndexCount() const = 0;
+
+ virtual int getMaxAllowedIndexes() const = 0;
+
+ virtual void getAllIndexes( std::vector<std::string>* names ) const = 0;
+
+ virtual BSONObj getIndexSpec( const StringData& idxName ) const = 0;
+
+ virtual bool isIndexMultikey( const StringData& indexName) const = 0;
+
+ virtual bool setIndexIsMultikey(OperationContext* txn,
+ const StringData& indexName,
+ bool multikey = true) = 0;
+
+ virtual DiskLoc getIndexHead( const StringData& indexName ) const = 0;
+
+ virtual void setIndexHead( OperationContext* txn,
+ const StringData& indexName,
+ const DiskLoc& newHead ) = 0;
+
+ virtual bool isIndexReady( const StringData& indexName ) const = 0;
+
+ virtual Status removeIndex( OperationContext* txn,
+ const StringData& indexName ) = 0;
+
+ virtual Status prepareForIndexBuild( OperationContext* txn,
+ const IndexDescriptor* spec ) = 0;
+
+ virtual void indexBuildSuccess( OperationContext* txn,
+ const StringData& indexName ) = 0;
+
+ /* Updates the expireAfterSeconds field of the given index to the value in newExpireSecs.
+ * The specified index must already contain an expireAfterSeconds field, and the value in
+ * that field and newExpireSecs must both be numeric.
+ */
+ virtual void updateTTLSetting( OperationContext* txn,
+ const StringData& idxName,
+ long long newExpireSeconds ) = 0;
+ private:
+ NamespaceString _ns;
+ };
+
+}
diff --git a/src/mongo/db/catalog/database.cpp b/src/mongo/db/catalog/database.cpp
index 37d82ac8550..d224e3a2a64 100644
--- a/src/mongo/db/catalog/database.cpp
+++ b/src/mongo/db/catalog/database.cpp
@@ -39,6 +39,7 @@
#include "mongo/db/auth/auth_index_d.h"
#include "mongo/db/background.h"
#include "mongo/db/clientcursor.h"
+#include "mongo/db/catalog/collection_catalog_entry.h"
#include "mongo/db/catalog/database_holder.h"
#include "mongo/db/dbhelpers.h"
#include "mongo/db/structure/catalog/index_details.h"
@@ -52,6 +53,7 @@
#include "mongo/db/storage/extent.h"
#include "mongo/db/storage/extent_manager.h"
#include "mongo/db/operation_context_impl.h"
+#include "mongo/db/storage/mmap_v1/mmap_v1_engine.h"
#include "mongo/db/storage/mmap_v1/mmap_v1_extent_manager.h"
#include "mongo/db/storage_options.h"
#include "mongo/db/structure/catalog/namespace_details.h"
@@ -59,8 +61,6 @@
namespace mongo {
- MONGO_EXPORT_SERVER_PARAMETER(newCollectionsUsePowerOf2Sizes, bool, true);
-
Status CollectionOptions::parse( const BSONObj& options ) {
reset();
@@ -198,8 +198,7 @@ namespace mongo {
Database::Database(OperationContext* txn, const char *nm, bool& newDb, const string& path )
: _name(nm), _path(path),
- _namespaceIndex( _path, _name ),
- _extentManager(new MmapV1ExtentManager(_name, _path, storageGlobalParams.directoryperdb)),
+ _dbEntry(new MMAP1DatabaseCatalogEntry( txn, _name, _path, storageGlobalParams.directoryperdb) ),
_profileName(_name + ".system.profile"),
_namespacesName(_name + ".system.namespaces"),
_indexesName(_name + ".system.indexes"),
@@ -211,54 +210,11 @@ namespace mongo {
uasserted( 10028, status.toString() );
}
- try {
- newDb = _namespaceIndex.exists();
- _profile = serverGlobalParams.defaultProfile;
- checkDuplicateUncasedNames(true);
-
- // If already exists, open. Otherwise behave as if empty until
- // there's a write, then open.
- if (!newDb) {
- _namespaceIndex.init( txn );
- openAllFiles(txn);
-
- // upgrade freelist
- string oldFreeList = _name + ".$freelist";
- NamespaceDetails* details = _namespaceIndex.details( oldFreeList );
- if ( details ) {
- if ( !details->firstExtent().isNull() ) {
- _extentManager->freeExtents(txn,
- details->firstExtent(),
- details->lastExtent());
- }
- _namespaceIndex.kill_ns( txn, oldFreeList );
- }
- }
- _magic = 781231;
- }
- catch(std::exception& e) {
- log() << "warning database " << path << " " << nm << " could not be opened" << endl;
- DBException* dbe = dynamic_cast<DBException*>(&e);
- if ( dbe != 0 ) {
- log() << "DBException " << dbe->getCode() << ": " << e.what() << endl;
- }
- else {
- log() << e.what() << endl;
- }
- _extentManager.reset();
- throw;
- }
+ _profile = serverGlobalParams.defaultProfile;
+ _magic = 781231;
+ newDb = !_dbEntry->exists();
}
- void Database::checkDuplicateUncasedNames(bool inholderlock) const {
- string duplicate = duplicateUncasedName(inholderlock, _name, _path );
- if ( !duplicate.empty() ) {
- stringstream ss;
- ss << "db already exists with different case already have: [" << duplicate
- << "] trying to create [" << _name << "]";
- uasserted( DatabaseDifferCaseCode , ss.str() );
- }
- }
/*static*/
string Database::duplicateUncasedName( bool inholderlock, const string &name, const string &path, set< string > *duplicates ) {
@@ -296,17 +252,6 @@ namespace mongo {
return "";
}
- // todo : we stop once a datafile dne.
- // if one datafile were missing we should keep going for
- // repair purposes yet we do not.
- void Database::openAllFiles(OperationContext* txn) {
- verify(this);
- Status s = _extentManager->init(txn);
- if ( !s.isOK() ) {
- msgasserted( 16966, str::stream() << "_extentManager.init failed: " << s.toString() );
- }
- }
-
void Database::clearTmpCollections(OperationContext* txn) {
Lock::assertWriteLocked( _name );
@@ -347,11 +292,11 @@ namespace mongo {
}
}
- long long Database::fileSize() const { return _extentManager->fileSize(); }
+ long long Database::fileSize() const { return getExtentManager()->fileSize(); }
- int Database::numFiles() const { return _extentManager->numFiles(); }
+ int Database::numFiles() const { return getExtentManager()->numFiles(); }
- void Database::flushFiles( bool sync ) { return _extentManager->flushFiles( sync ); }
+ void Database::flushFiles( bool sync ) { return getExtentManager()->flushFiles( sync ); }
bool Database::setProfilingLevel( OperationContext* txn, int newLevel , string& errmsg ) {
if ( _profile == newLevel )
@@ -472,7 +417,7 @@ namespace mongo {
}
Collection* Database::getCollection( OperationContext* txn, const StringData& ns ) {
- verify( _name == nsToDatabaseSubstring( ns ) );
+ invariant( _name == nsToDatabaseSubstring( ns ) );
scoped_lock lk( _collectionLock );
@@ -480,24 +425,28 @@ namespace mongo {
if ( it != _collections.end() ) {
if ( it->second ) {
DEV {
- NamespaceDetails* details = _namespaceIndex.details( ns );
+ /* XXX put back?
+ NamespaceDetails* details = _dbEntry->namespaceIndex().details( ns );
if ( details != it->second->_details ) {
log() << "about to crash for mismatch on ns: " << ns
<< " current: " << (void*)details
<< " cached: " << (void*)it->second->_details;
}
verify( details == it->second->_details );
+ */
}
return it->second;
}
}
- NamespaceDetails* details = _namespaceIndex.details( ns );
- if ( !details ) {
+ auto_ptr<CollectionCatalogEntry> catalogEntry( _dbEntry->getCollectionCatalogEntry( txn, ns ) );
+ if ( !catalogEntry.get() )
return NULL;
- }
- Collection* c = new Collection( txn, ns, details, this );
+ auto_ptr<RecordStore> rs( _dbEntry->getRecordStore( txn, ns ) );
+ invariant( rs.get() ); // if catalogEntry exists, so should this
+
+ Collection* c = new Collection( txn, ns, catalogEntry.release(), rs.release(), this );
_collections[ns] = c;
return c;
}
@@ -514,7 +463,7 @@ namespace mongo {
if ( !s.isOK() )
return s;
- NamespaceDetails* details = _namespaceIndex.details( toNS );
+ NamespaceDetails* details = _dbEntry->namespaceIndex().details( toNS );
verify( details );
audit::logRenameCollection( currentClient.get(), fromNS, toNS );
@@ -578,17 +527,16 @@ namespace mongo {
const StringData& fromNS,
const StringData& toNS,
bool stayTemp ) {
-
// TODO: make it so we dont't need to do this
string fromNSString = fromNS.toString();
string toNSString = toNS.toString();
// some sanity checking
- NamespaceDetails* fromDetails = _namespaceIndex.details( fromNS );
+ NamespaceDetails* fromDetails = _dbEntry->namespaceIndex().details( fromNS );
if ( !fromDetails )
return Status( ErrorCodes::BadValue, "from namespace doesn't exist" );
- if ( _namespaceIndex.details( toNS ) )
+ if ( _dbEntry->namespaceIndex().details( toNS ) )
return Status( ErrorCodes::BadValue, "to namespace already exists" );
// remove anything cached
@@ -605,25 +553,25 @@ namespace mongo {
// ----
// this could throw, but if it does we're ok
- _namespaceIndex.add_ns( txn, toNS, fromDetails );
- NamespaceDetails* toDetails = _namespaceIndex.details( toNS );
+ _dbEntry->namespaceIndex().add_ns( txn, toNS, fromDetails );
+ NamespaceDetails* toDetails = _dbEntry->namespaceIndex().details( toNS );
try {
toDetails->copyingFrom(txn,
toNSString.c_str(),
- _namespaceIndex,
+ _dbEntry->namespaceIndex(),
fromDetails); // fixes extraOffset
}
catch( DBException& ) {
// could end up here if .ns is full - if so try to clean up / roll back a little
- _namespaceIndex.kill_ns( txn, toNSString );
+ _dbEntry->namespaceIndex().kill_ns( txn, toNSString );
_clearCollectionCache(toNSString);
throw;
}
// at this point, code .ns stuff moved
- _namespaceIndex.kill_ns( txn, fromNSString );
+ _dbEntry->namespaceIndex().kill_ns( txn, fromNSString );
_clearCollectionCache(fromNSString);
fromDetails = NULL;
@@ -671,24 +619,13 @@ namespace mongo {
return c;
}
- namespace {
- int _massageExtentSize( const ExtentManager* em, long long size ) {
- if ( size < em->minSize() )
- return em->minSize();
- if ( size > em->maxSize() )
- return em->maxSize();
- return static_cast<int>( size );
- }
- }
-
Collection* Database::createCollection( OperationContext* txn,
const StringData& ns,
const CollectionOptions& options,
bool allocateDefaultSpace,
bool createIdIndex ) {
- massert( 17399, "collection already exists", _namespaceIndex.details( ns ) == NULL );
+ massert( 17399, "collection already exists", _dbEntry->namespaceIndex().details( ns ) == NULL );
massertNamespaceNotIndex( ns, "createCollection" );
- _namespaceIndex.init( txn );
if ( serverGlobalParams.configsvr &&
!( ns.startsWith( "config." ) ||
@@ -709,55 +646,13 @@ namespace mongo {
audit::logCreateCollection( currentClient.get(), ns );
- _namespaceIndex.add_ns( txn, ns, DiskLoc(), options.capped );
- BSONObj optionsAsBSON = options.toBSON();
- _addNamespaceToCatalog( txn, ns, &optionsAsBSON );
+ Status status = _dbEntry->createCollection( txn, ns,
+ options, allocateDefaultSpace );
+ massertStatusOK( status );
- Collection* collection = getCollection( txn, ns );
- massert( 17400, "_namespaceIndex.add_ns failed?", collection );
- // allocation strategy set explicitly in flags or by server-wide default
- if ( !options.capped ) {
- if ( options.flagsSet ) {
- collection->setUserFlag( txn, options.flags );
- }
- else if ( newCollectionsUsePowerOf2Sizes ) {
- collection->setUserFlag( txn, NamespaceDetails::Flag_UsePowerOf2Sizes );
- }
- }
-
- if ( options.cappedMaxDocs > 0 )
- collection->setMaxCappedDocs( txn, options.cappedMaxDocs );
-
- if ( allocateDefaultSpace ) {
- if ( options.initialNumExtents > 0 ) {
- int size = _massageExtentSize( _extentManager.get(),
- options.cappedSize );
- for ( int i = 0; i < options.initialNumExtents; i++ ) {
- collection->increaseStorageSize( txn, size, false );
- }
- }
- else if ( !options.initialExtentSizes.empty() ) {
- for ( size_t i = 0; i < options.initialExtentSizes.size(); i++ ) {
- int size = options.initialExtentSizes[i];
- size = _massageExtentSize( _extentManager.get(),
- size );
- collection->increaseStorageSize( txn, size, false );
- }
- }
- else if ( options.capped ) {
- // normal
- while ( collection->getRecordStore()->storageSize() < options.cappedSize ) {
- int sz = _massageExtentSize( _extentManager.get(),
- options.cappedSize - collection->getRecordStore()->storageSize() );
- sz &= 0xffffff00;
- collection->increaseStorageSize( txn, sz, true );
- }
- }
- else {
- collection->increaseStorageSize( txn, _extentManager->initialSize( 128 ), false );
- }
- }
+ Collection* collection = getCollection( txn, ns );
+ invariant( collection );
if ( createIdIndex ) {
if ( collection->requiresIdIndex() ) {
@@ -801,7 +696,7 @@ namespace mongo {
Status Database::_dropNS( OperationContext* txn, const StringData& ns ) {
- NamespaceDetails* d = _namespaceIndex.details( ns );
+ NamespaceDetails* d = _dbEntry->namespaceIndex().details( ns );
if ( !d )
return Status( ErrorCodes::NamespaceNotFound,
str::stream() << "ns not found: " << ns );
@@ -815,28 +710,48 @@ namespace mongo {
}
// free extents
- if( !d->firstExtent().isNull() ) {
- _extentManager->freeExtents(txn, d->firstExtent(), d->lastExtent());
- d->setFirstExtentInvalid(txn);
- d->setLastExtentInvalid(txn);
+ if( !d->firstExtent.isNull() ) {
+ getExtentManager()->freeExtents(txn, d->firstExtent, d->lastExtent);
+ *txn->recoveryUnit()->writing( &d->firstExtent ) = DiskLoc().setInvalid();
+ *txn->recoveryUnit()->writing( &d->lastExtent ) = DiskLoc().setInvalid();
}
// remove from the catalog hashtable
- _namespaceIndex.kill_ns( txn, ns );
+ _dbEntry->namespaceIndex().kill_ns( txn, ns );
return Status::OK();
}
void Database::getFileFormat( int* major, int* minor ) {
- if ( _extentManager->numFiles() == 0 ) {
+ if ( getExtentManager()->numFiles() == 0 ) {
*major = 0;
*minor = 0;
return;
}
OperationContextImpl txn; // TODO get rid of this once reads need transactions
- const DataFile* df = _extentManager->getFile( &txn, 0 );
+ const DataFile* df = getExtentManager()->getFile( &txn, 0 );
*major = df->getHeader()->version;
*minor = df->getHeader()->versionMinor;
}
+ MmapV1ExtentManager* Database::getExtentManager() {
+ return _dbEntry->getExtentManager();
+ }
+
+ const MmapV1ExtentManager* Database::getExtentManager() const {
+ return _dbEntry->getExtentManager();
+ }
+
+ const NamespaceIndex* Database::namespaceIndex() const {
+ return &_dbEntry->namespaceIndex();
+ }
+
+ NamespaceIndex* Database::namespaceIndex() {
+ return &_dbEntry->namespaceIndex();
+ }
+
+ bool Database::isEmpty() {
+ return !_dbEntry->namespaceIndex().allocated();
+ }
+
} // namespace mongo
diff --git a/src/mongo/db/catalog/database.h b/src/mongo/db/catalog/database.h
index 33d9b198517..27b7aeacab0 100644
--- a/src/mongo/db/catalog/database.h
+++ b/src/mongo/db/catalog/database.h
@@ -30,9 +30,11 @@
#pragma once
+#include "mongo/bson/bsonobj.h"
#include "mongo/db/namespace_string.h"
-#include "mongo/db/structure/catalog/namespace_index.h"
#include "mongo/db/storage_options.h"
+#include "mongo/util/concurrency/mutex.h"
+#include "mongo/util/mongoutils/str.h"
#include "mongo/util/string_map.h"
namespace mongo {
@@ -41,8 +43,10 @@ namespace mongo {
class DataFile;
class ExtentManager;
class IndexCatalog;
+ class MMAP1DatabaseCatalogEntry;
class MmapV1ExtentManager;
class NamespaceDetails;
+ class NamespaceIndex;
class OperationContext;
struct CollectionOptions {
@@ -118,7 +122,7 @@ namespace mongo {
*/
bool isOk() const { return _magic == 781231; }
- bool isEmpty() { return ! _namespaceIndex.allocated(); }
+ bool isEmpty();
/**
* total file size of Database in bytes
@@ -141,7 +145,7 @@ namespace mongo {
* ns=foo.bar, db=foo returns true
*/
bool ownsNS( const std::string& ns ) const {
- if ( ! startsWith( ns , _name ) )
+ if ( ! mongoutils::str::startsWith( ns , _name ) )
return false;
return ns[_name.size()] == '.';
}
@@ -149,12 +153,12 @@ namespace mongo {
int getProfilingLevel() const { return _profile; }
const char* getProfilingNS() const { return _profileName.c_str(); }
- const NamespaceIndex& namespaceIndex() const { return _namespaceIndex; }
- NamespaceIndex& namespaceIndex() { return _namespaceIndex; }
+ const NamespaceIndex* namespaceIndex() const;
+ NamespaceIndex* namespaceIndex();
// TODO: do not think this method should exist, so should try and encapsulate better
- MmapV1ExtentManager* getExtentManager() { return _extentManager.get(); }
- const MmapV1ExtentManager* getExtentManager() const { return _extentManager.get(); }
+ MmapV1ExtentManager* getExtentManager();
+ const MmapV1ExtentManager* getExtentManager() const;
Status dropCollection( OperationContext* txn, const StringData& fullns );
@@ -191,8 +195,12 @@ namespace mongo {
* @return name of an existing database with same text name but different
* casing, if one exists. Otherwise the empty std::string is returned. If
* 'duplicates' is specified, it is filled with all duplicate names.
+ // TODO move???
*/
- static std::string duplicateUncasedName( bool inholderlockalready, const std::string &name, const std::string &path, std::set< std::string > *duplicates = 0 );
+ static string duplicateUncasedName( bool inholderlockalready,
+ const std::string &name,
+ const std::string &path,
+ std::set< std::string > *duplicates = 0 );
static Status validateDBName( const StringData& dbname );
@@ -218,14 +226,6 @@ namespace mongo {
*/
Status _dropNS( OperationContext* txn, const StringData& ns );
- /**
- * @throws DatabaseDifferCaseCode if the name is a duplicate based on
- * case insensitive matching.
- */
- void checkDuplicateUncasedNames(bool inholderlockalready) const;
-
- void openAllFiles(OperationContext* txn);
-
Status _renameSingleNamespace( OperationContext* txn,
const StringData& fromNS,
const StringData& toNS,
@@ -234,8 +234,7 @@ namespace mongo {
const std::string _name; // "alleyinsider"
const std::string _path; // "/data/db"
- NamespaceIndex _namespaceIndex;
- boost::scoped_ptr<MmapV1ExtentManager> _extentManager;
+ boost::scoped_ptr<MMAP1DatabaseCatalogEntry> _dbEntry;
const std::string _profileName; // "alleyinsider.system.profile"
const std::string _namespacesName; // "alleyinsider.system.namespaces"
@@ -250,7 +249,7 @@ namespace mongo {
// but it points to a much more useful data structure
typedef StringMap< Collection* > CollectionMap;
CollectionMap _collections;
- mutex _collectionLock;
+ mongo::mutex _collectionLock;
friend class Collection;
friend class NamespaceDetails;
diff --git a/src/mongo/db/catalog/database_holder.cpp b/src/mongo/db/catalog/database_holder.cpp
index a944ce18631..3516cc06a09 100644
--- a/src/mongo/db/catalog/database_holder.cpp
+++ b/src/mongo/db/catalog/database_holder.cpp
@@ -37,6 +37,7 @@
#include "mongo/db/catalog/database_holder.h"
#include "mongo/db/d_concurrency.h"
#include "mongo/db/operation_context_impl.h"
+#include "mongo/db/storage/mmap_v1/dur.h"
namespace mongo {
diff --git a/src/mongo/db/catalog/index_catalog.cpp b/src/mongo/db/catalog/index_catalog.cpp
index 140b98f5bc4..9a804f7e5ae 100644
--- a/src/mongo/db/catalog/index_catalog.cpp
+++ b/src/mongo/db/catalog/index_catalog.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/audit.h"
#include "mongo/db/background.h"
+#include "mongo/db/catalog/collection_catalog_entry.h"
#include "mongo/db/catalog/collection.h"
#include "mongo/db/catalog/index_create.h"
#include "mongo/db/catalog/index_key_validate.h"
@@ -41,15 +42,8 @@
#include "mongo/db/clientcursor.h"
#include "mongo/db/curop.h"
#include "mongo/db/field_ref.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/fts_access_method.h"
-#include "mongo/db/index/hash_access_method.h"
-#include "mongo/db/index/haystack_access_method.h"
#include "mongo/db/index/index_access_method.h"
#include "mongo/db/index/index_descriptor.h"
-#include "mongo/db/index/s2_access_method.h"
#include "mongo/db/index_legacy.h"
#include "mongo/db/index_names.h"
#include "mongo/db/jsobj.h"
@@ -60,14 +54,14 @@
#include "mongo/db/repl/rs.h" // this is ugly
#include "mongo/db/storage/data_file.h"
#include "mongo/db/storage/extent_manager.h"
-#include "mongo/db/storage/mmap_v1/mmap_v1_extent_manager.h"
#include "mongo/db/operation_context.h"
-#include "mongo/db/structure/catalog/namespace_details.h"
-#include "mongo/db/structure/catalog/namespace_details_rsv1_metadata.h"
-#include "mongo/db/structure/record_store_v1_simple.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/log.h"
+#include "mongo/db/storage/mmap_v1/mmap_v1_engine.h" // XXX
+#include "mongo/db/storage/mmap_v1/mmap_v1_extent_manager.h" // XXX
+#include "mongo/db/storage/extent_manager.h" // XXX
+
namespace mongo {
static const int INDEX_CATALOG_INIT = 283711;
@@ -80,8 +74,8 @@ namespace mongo {
// -------------
- IndexCatalog::IndexCatalog( Collection* collection, NamespaceDetails* details )
- : _magic(INDEX_CATALOG_UNINIT), _collection( collection ), _details( details ) {
+ IndexCatalog::IndexCatalog( Collection* collection )
+ : _magic(INDEX_CATALOG_UNINIT), _collection( collection ) {
}
IndexCatalog::~IndexCatalog() {
@@ -93,23 +87,23 @@ namespace mongo {
}
Status IndexCatalog::init(OperationContext* txn) {
+ vector<string> indexNames;
+ _collection->getCatalogEntry()->getAllIndexes( &indexNames );
- NamespaceDetails::IndexIterator ii = _details->ii(true);
- while ( ii.more() ) {
- const IndexDetails& id = ii.next();
- int idxNo = ii.pos() - 1;
+ for ( size_t i = 0; i < indexNames.size(); i++ ) {
+ const string& indexName = indexNames[i];
+ BSONObj spec = _collection->getCatalogEntry()->getIndexSpec( indexName ).getOwned();
- if ( idxNo >= _details->getCompletedIndexCount() ) {
- _unfinishedIndexes.push_back(_collection->docFor(id.info).getOwned());
+ if ( !_collection->getCatalogEntry()->isIndexReady( indexName ) ) {
+ _unfinishedIndexes.push_back( spec );
continue;
}
- BSONObj ownedInfoObj = _collection->docFor(id.info).getOwned();
- BSONObj keyPattern = ownedInfoObj.getObjectField("key");
+ BSONObj keyPattern = spec.getObjectField("key");
IndexDescriptor* descriptor = new IndexDescriptor( _collection,
_getAccessMethodName(keyPattern),
- ownedInfoObj );
- IndexCatalogEntry* entry = _setupInMemoryStructures(txn, descriptor );
+ spec );
+ IndexCatalogEntry* entry = _setupInMemoryStructures( txn, descriptor );
fassert( 17340, entry->isReady() );
}
@@ -129,25 +123,14 @@ namespace mongo {
IndexDescriptor* descriptor) {
auto_ptr<IndexDescriptor> descriptorCleanup( descriptor );
- NamespaceDetails* indexMetadata =
- _collection->_database->namespaceIndex().details( descriptor->indexNamespace() );
-
- massert( 17329,
- str::stream() << "no NamespaceDetails for index: " << descriptor->toString(),
- indexMetadata );
-
- auto_ptr<RecordStore> recordStore( new SimpleRecordStoreV1( txn,
- descriptor->indexNamespace(),
- new NamespaceDetailsRSV1MetaData( indexMetadata ),
- _collection->getExtentManager(),
- false ) );
-
- auto_ptr<IndexCatalogEntry> entry( new IndexCatalogEntry( _collection,
+ auto_ptr<IndexCatalogEntry> entry( new IndexCatalogEntry( _collection->ns().ns(),
+ _collection->getCatalogEntry(),
descriptorCleanup.release(),
- recordStore.release() ) );
+ _collection->infoCache() ) );
- entry->init( _createAccessMethod( entry->descriptor(),
- entry.get() ) );
+ entry->init( _collection->_database->_dbEntry->getIndex( txn,
+ _collection->getCatalogEntry(),
+ entry.get() ) );
IndexCatalogEntry* save = entry.get();
_entries.add( entry.release() );
@@ -155,21 +138,6 @@ namespace mongo {
invariant( save == _entries.find( descriptor ) );
invariant( save == _entries.find( descriptor->indexName() ) );
- // check index to see if wants us to do special things
-
- { // power of 2
- bool requirePowerOf2 = false;
- if ( IndexNames::findPluginName( descriptor->keyPattern() ) == IndexNames::TEXT )
- requirePowerOf2 = true;
-
- if ( descriptor->getInfoElement("expireAfterSeconds").isNumber() )
- requirePowerOf2 = true;
-
- if ( requirePowerOf2 ) {
- _collection->setUserFlag(txn, NamespaceDetails::Flag_UsePowerOf2Sizes);
- }
- }
-
return save;
}
@@ -346,7 +314,6 @@ namespace mongo {
string idxName = descriptor->indexName(); // out copy for yields, etc...
invariant( entry == _entries.find( descriptor ) );
- invariant(_details->_catalogFindIndexByName(_collection, idxName, true) >= 0);
try {
Client& client = cc();
@@ -364,8 +331,7 @@ namespace mongo {
_inProgressIndexes.erase(it);
// sanity check
- int idxNo = _details->_catalogFindIndexByName(_collection, idxName, true);
- invariant( idxNo < numIndexesReady() );
+ invariant( _collection->getCatalogEntry()->isIndexReady( idxName ) );
return Status::OK();
}
@@ -428,54 +394,14 @@ namespace mongo {
/// ---------- setup on disk structures ----------------
- Database* db = _collection->_database;
-
- // 1) insert into system.indexes
-
- Collection* systemIndexes = db->getOrCreateCollection( db->_indexesName );
- invariant( systemIndexes );
-
- StatusWith<DiskLoc> systemIndexesEntry = systemIndexes->insertDocument( _txn, _spec, false );
- if ( !systemIndexesEntry.isOK() )
- return systemIndexesEntry.getStatus();
-
- // 2) collection's NamespaceDetails
- IndexDetails& indexDetails =
- _collection->detailsWritable()->getNextIndexDetails( _txn, _collection );
-
- try {
- *_txn->recoveryUnit()->writing( &indexDetails.info ) = systemIndexesEntry.getValue();
- *_txn->recoveryUnit()->writing( &indexDetails.head ) = DiskLoc();
- }
- catch ( DBException& e ) {
- log() << "got exception trying to assign loc to IndexDetails" << e;
- _catalog->_removeFromSystemIndexes(_txn, descriptor->indexName());
- return Status( ErrorCodes::InternalError, e.toString() );
- }
-
- int before = _collection->detailsDeprecated()->_indexBuildsInProgress;
- try {
- _txn->recoveryUnit()->writingInt( _collection->detailsWritable()->_indexBuildsInProgress ) += 1;
- }
- catch ( DBException& e ) {
- log() << "got exception trying to incrementStats _indexBuildsInProgress: " << e;
- fassert( 17344, before == _collection->detailsDeprecated()->_indexBuildsInProgress );
- _catalog->_removeFromSystemIndexes(_txn, descriptor->indexName());
- return Status( ErrorCodes::InternalError, e.toString() );
- }
+ Status status = _collection->getCatalogEntry()->prepareForIndexBuild( _txn, descriptor );
+ if ( !status.isOK() )
+ return status;
// at this point we can do normal clean up procedure, so we mark ourselves
// as in progress.
_inProgress = true;
- // 3) indexes entry in .ns file
- NamespaceIndex& nsi = db->namespaceIndex();
- invariant( nsi.details( descriptor->indexNamespace() ) == NULL );
- nsi.add_ns( _txn, descriptor->indexNamespace(), DiskLoc(), false );
-
- // 4) system.namespaces entry index ns
- db->_addNamespaceToCatalog(_txn, descriptor->indexNamespace(), NULL);
-
/// ---------- setup in memory structures ----------------
_entry = _catalog->_setupInMemoryStructures(_txn, descriptorCleaner.release());
@@ -513,9 +439,6 @@ namespace mongo {
_inProgress = false; // defensive
fassert( 17204, _catalog->_collection->ok() ); // defensive
- int idxNo = _collection->detailsDeprecated()->_catalogFindIndexByName(_collection, _indexName, true);
- fassert( 17205, idxNo >= 0 );
-
IndexCatalogEntry* entry = _catalog->_entries.find( _indexName );
invariant( entry == _entry );
@@ -525,8 +448,7 @@ namespace mongo {
else {
_catalog->_deleteIndexFromDisk( _txn,
_indexName,
- _indexNamespace,
- idxNo );
+ _indexNamespace );
}
}
@@ -542,25 +464,7 @@ namespace mongo {
fassert( 17207, _catalog->_collection->ok() );
- NamespaceDetails* nsd = _collection->detailsWritable();
-
- int idxNo = nsd->_catalogFindIndexByName(_collection, _indexName, true);
- fassert( 17202, idxNo >= 0 );
-
- // Make sure the newly created index is relocated to nIndexes, if it isn't already there
- if ( idxNo != nsd->getCompletedIndexCount() ) {
- log() << "switching indexes at position " << idxNo << " and "
- << nsd->getCompletedIndexCount() << endl;
-
- int toIdxNo = nsd->getCompletedIndexCount();
-
- nsd->swapIndex( _txn, idxNo, toIdxNo );
-
- idxNo = nsd->getCompletedIndexCount();
- }
-
- _txn->recoveryUnit()->writingInt( nsd->_indexBuildsInProgress ) -= 1;
- _txn->recoveryUnit()->writingInt( nsd->_nIndexes ) += 1;
+ _catalog->_collection->getCatalogEntry()->indexBuildSuccess( _txn, _indexName );
_catalog->_collection->infoCache()->addedIndex();
@@ -691,7 +595,8 @@ namespace mongo {
}
}
- if ( _details->getTotalIndexCount() >= NamespaceDetails::NIndexesMax ) {
+ if ( _collection->getCatalogEntry()->getTotalIndexCount() >=
+ _collection->getCatalogEntry()->getMaxAllowedIndexes() ) {
string s = str::stream() << "add index fails, too many indexes for "
<< _collection->ns().ns() << " key:" << key.toString();
log() << s;
@@ -863,9 +768,6 @@ namespace mongo {
string indexNamespace = entry->descriptor()->indexNamespace();
string indexName = entry->descriptor()->indexName();
- int idxNo = _details->_catalogFindIndexByName(_collection, indexName, true);
- invariant( idxNo >= 0 );
-
// --------- START REAL WORK ----------
audit::logDropIndex( currentClient.get(), indexName, _collection->ns().ns() );
@@ -878,8 +780,7 @@ namespace mongo {
// **** this is the first disk change ****
_deleteIndexFromDisk( txn,
indexName,
- indexNamespace,
- idxNo );
+ indexNamespace );
}
catch ( std::exception& ) {
// this is bad, and we don't really know state
@@ -903,11 +804,7 @@ namespace mongo {
void IndexCatalog::_deleteIndexFromDisk( OperationContext* txn,
const string& indexName,
- const string& indexNamespace,
- int idxNo ) {
- invariant( idxNo >= 0 );
- invariant(_details->_catalogFindIndexByName(_collection, indexName, true) == idxNo);
-
+ const string& indexNamespace ) {
// data + system.namespacesa
Status status = _collection->_database->_dropNS( txn, indexNamespace );
if ( status.code() == ErrorCodes::NamespaceNotFound ) {
@@ -917,29 +814,11 @@ namespace mongo {
warning() << "couldn't drop extents for " << indexNamespace << " " << status.toString();
}
- // all info in the .ns file
- _details->_removeIndexFromMe( txn, idxNo );
-
- // remove from system.indexes
- // n is how many things were removed from this
- // probably should clean this up
- int n = _removeFromSystemIndexes(txn, indexName);
- wassert( n == 1 );
- }
-
- int IndexCatalog::_removeFromSystemIndexes(OperationContext* txn,
- const StringData& indexName) {
- BSONObjBuilder b;
- b.append( "ns", _collection->ns() );
- b.append( "name", indexName );
- BSONObj cond = b.obj(); // e.g.: { name: "ts_1", ns: "foo.coll" }
- return static_cast<int>( deleteObjects( txn,
- _collection->_database,
- _collection->_database->_indexesName,
- cond,
- false,
- false,
- true ) );
+ status = _collection->getCatalogEntry()->removeIndex( txn, indexName );
+ if ( !status.isOK() ) {
+ warning() << "couldn't remove index from catalog " << indexNamespace
+ << " " << status.toString();
+ }
}
vector<BSONObj> IndexCatalog::getAndClearUnfinishedIndexes(OperationContext* txn) {
@@ -951,48 +830,13 @@ namespace mongo {
BSONObj keyPattern = spec.getObjectField("key");
IndexDescriptor desc( _collection, _getAccessMethodName(keyPattern), spec );
- int idxNo = _details->_catalogFindIndexByName(_collection, desc.indexName(), true);
- invariant( idxNo >= 0 );
- invariant( idxNo >= numIndexesReady() );
-
_deleteIndexFromDisk( txn,
desc.indexName(),
- desc.indexNamespace(),
- idxNo );
+ desc.indexNamespace() );
}
return toReturn;
}
- void IndexCatalog::updateTTLSetting( OperationContext* txn,
- const IndexDescriptor* idx,
- long long newExpireSeconds ) {
- IndexDetails* indexDetails = _getIndexDetails( idx );
-
- const BSONElement oldExpireSecs =
- _collection->docFor(indexDetails->info).getField("expireAfterSeconds");
-
- // Important that we set the new value in-place. We are writing directly to the
- // object here so must be careful not to overwrite with a longer numeric type.
-
- char* nonConstPtr = const_cast<char*>(oldExpireSecs.value());
- switch( oldExpireSecs.type() ) {
- case EOO:
- massert( 16631, "index does not have an 'expireAfterSeconds' field", false );
- break;
- case NumberInt:
- *txn->recoveryUnit()->writing(reinterpret_cast<int*>(nonConstPtr)) = newExpireSeconds;
- break;
- case NumberDouble:
- *txn->recoveryUnit()->writing(reinterpret_cast<double*>(nonConstPtr)) = newExpireSeconds;
- break;
- case NumberLong:
- *txn->recoveryUnit()->writing(reinterpret_cast<long long*>(nonConstPtr)) = newExpireSeconds;
- break;
- default:
- massert( 16632, "current 'expireAfterSeconds' is not a number", false );
- }
- }
-
bool IndexCatalog::isMultikey( const IndexDescriptor* idx ) {
IndexCatalogEntry* entry = _entries.find( idx );
invariant( entry );
@@ -1003,11 +847,11 @@ namespace mongo {
// ---------------------------
int IndexCatalog::numIndexesTotal() const {
- return _details->getTotalIndexCount();
+ return _collection->getCatalogEntry()->getTotalIndexCount();
}
int IndexCatalog::numIndexesReady() const {
- return _details->getCompletedIndexCount();
+ return _collection->getCatalogEntry()->getCompletedIndexCount();
}
bool IndexCatalog::haveIdIndex() const {
@@ -1142,39 +986,6 @@ namespace mongo {
return entry;
}
- IndexAccessMethod* IndexCatalog::_createAccessMethod( const IndexDescriptor* desc,
- IndexCatalogEntry* entry ) {
- const string& type = desc->getAccessMethodName();
-
- if (IndexNames::HASHED == type)
- return new HashAccessMethod( entry );
-
- if (IndexNames::GEO_2DSPHERE == type)
- return new S2AccessMethod( entry );
-
- if (IndexNames::TEXT == type)
- return new FTSAccessMethod( entry );
-
- if (IndexNames::GEO_HAYSTACK == type)
- return new HaystackAccessMethod( entry );
-
- if ("" == type)
- return new BtreeAccessMethod( entry );
-
- if (IndexNames::GEO_2D == type)
- return new TwoDAccessMethod( entry );
-
- log() << "Can't find index for keyPattern " << desc->keyPattern();
- invariant(0);
- return NULL;
- }
-
- IndexDetails* IndexCatalog::_getIndexDetails( const IndexDescriptor* descriptor ) const {
- int idxNo = _details->_catalogFindIndexByName(_collection, descriptor->indexName(), true);
- invariant( idxNo >= 0 );
- return &_details->idx( idxNo );
- }
-
// ---------------------------
Status IndexCatalog::_indexRecord(OperationContext* txn,
diff --git a/src/mongo/db/catalog/index_catalog.h b/src/mongo/db/catalog/index_catalog.h
index b45a056cc1a..e33202dcbdf 100644
--- a/src/mongo/db/catalog/index_catalog.h
+++ b/src/mongo/db/catalog/index_catalog.h
@@ -42,10 +42,8 @@ namespace mongo {
class Client;
class Collection;
- class NamespaceDetails;
class IndexDescriptor;
- struct IndexDetails;
class IndexAccessMethod;
/**
@@ -54,7 +52,7 @@ namespace mongo {
*/
class IndexCatalog {
public:
- IndexCatalog( Collection* collection, NamespaceDetails* details );
+ IndexCatalog( Collection* collection );
~IndexCatalog();
// must be called before used
@@ -178,14 +176,6 @@ namespace mongo {
// ---- modify single index
- /* Updates the expireAfterSeconds field of the given index to the value in newExpireSecs.
- * The specified index must already contain an expireAfterSeconds field, and the value in
- * that field and newExpireSecs must both be numeric.
- */
- void updateTTLSetting( OperationContext* txn,
- const IndexDescriptor* idx,
- long long newExpireSeconds );
-
bool isMultikey( const IndexDescriptor* idex );
// --- these probably become private?
@@ -274,13 +264,6 @@ namespace mongo {
private:
typedef unordered_map<IndexDescriptor*, Client*> InProgressIndexesMap;
- // creates a new thing, no caching
- IndexAccessMethod* _createAccessMethod( const IndexDescriptor* desc,
- IndexCatalogEntry* entry );
-
- int _removeFromSystemIndexes(OperationContext* txn,
- const StringData& indexName );
-
bool _shouldOverridePlugin( const BSONObj& keyPattern ) const;
/**
@@ -290,8 +273,6 @@ namespace mongo {
*/
std::string _getAccessMethodName(const BSONObj& keyPattern) const;
- IndexDetails* _getIndexDetails( const IndexDescriptor* descriptor ) const;
-
void _checkMagic() const;
@@ -320,8 +301,7 @@ namespace mongo {
// doesn't change memory state, etc...
void _deleteIndexFromDisk( OperationContext* txn,
const std::string& indexName,
- const std::string& indexNamespace,
- int idxNo );
+ const std::string& indexNamespace );
// descriptor ownership passes to _setupInMemoryStructures
IndexCatalogEntry* _setupInMemoryStructures(OperationContext* txn,
@@ -335,7 +315,6 @@ namespace mongo {
int _magic;
Collection* _collection;
- NamespaceDetails* _details;
IndexCatalogEntryContainer _entries;
diff --git a/src/mongo/db/catalog/index_catalog_entry.cpp b/src/mongo/db/catalog/index_catalog_entry.cpp
index 31436041f3d..9b6f5f63d6d 100644
--- a/src/mongo/db/catalog/index_catalog_entry.cpp
+++ b/src/mongo/db/catalog/index_catalog_entry.cpp
@@ -30,6 +30,7 @@
#include "mongo/db/catalog/index_catalog_entry.h"
+#include "mongo/db/catalog/collection_catalog_entry.h"
#include "mongo/db/index/index_access_method.h"
#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/operation_context.h"
@@ -56,12 +57,14 @@ namespace mongo {
IndexCatalogEntry* _catalogEntry;
};
- IndexCatalogEntry::IndexCatalogEntry( Collection* collection,
+ IndexCatalogEntry::IndexCatalogEntry( const StringData& ns,
+ CollectionCatalogEntry* collection,
IndexDescriptor* descriptor,
- RecordStore* recordstore )
- : _collection( collection ),
+ CollectionInfoCache* infoCache )
+ : _ns( ns.toString() ),
+ _collection( collection ),
_descriptor( descriptor ),
- _recordStore( recordstore ),
+ _infoCache( infoCache ),
_accessMethod( NULL ),
_headManager(new HeadManagerImpl(this)),
_ordering( Ordering::make( descriptor->keyPattern() ) ),
@@ -74,7 +77,6 @@ namespace mongo {
delete _headManager;
delete _accessMethod;
- delete _recordStore;
delete _descriptor;
}
@@ -110,22 +112,23 @@ namespace mongo {
}
void IndexCatalogEntry::setHead( OperationContext* txn, DiskLoc newHead ) {
- NamespaceDetails* nsd = _collection->detailsWritable();
- int idxNo = _indexNo();
- IndexDetails& id = nsd->idx( idxNo );
- *txn->recoveryUnit()->writing(&id.head) = newHead;
+ _collection->setIndexHead( txn,
+ _descriptor->indexName(),
+ newHead );
_head = newHead;
}
void IndexCatalogEntry::setMultikey( OperationContext* txn ) {
if ( isMultikey() )
return;
- NamespaceDetails* nsd = _collection->detailsWritable();
- int idxNo = _indexNo();
- if ( nsd->setIndexIsMultikey( txn, idxNo, true ) ) {
- LOG(1) << _collection->ns().ns() << ": clearing plan cache - index "
- << _descriptor->keyPattern() << " set to multi key.";
- _collection->infoCache()->clearQueryCache();
+ if ( _collection->setIndexIsMultikey( txn,
+ _descriptor->indexName(),
+ true ) ) {
+ if ( _infoCache ) {
+ LOG(1) << _ns << ": clearing plan cache - index "
+ << _descriptor->keyPattern() << " set to multi key.";
+ _infoCache->clearQueryCache();
+ }
}
_isMultikey = true;
}
@@ -133,29 +136,17 @@ namespace mongo {
// ----
bool IndexCatalogEntry::_catalogIsReady() const {
- return _indexNo() < _collection->getIndexCatalog()->numIndexesReady();
+ return _collection->isIndexReady( _descriptor->indexName() );
}
DiskLoc IndexCatalogEntry::_catalogHead() const {
- const NamespaceDetails* nsd = _collection->detailsDeprecated();
- int idxNo = _indexNo();
- return nsd->idx( idxNo ).head;
+ return _collection->getIndexHead( _descriptor->indexName() );
}
bool IndexCatalogEntry::_catalogIsMultikey() const {
- const NamespaceDetails* nsd = _collection->detailsDeprecated();
- int idxNo = _indexNo();
- return nsd->isMultikey( idxNo );
+ return _collection->isIndexMultikey( _descriptor->indexName() );
}
- int IndexCatalogEntry::_indexNo() const {
- int idxNo = _collection->detailsDeprecated()->_catalogFindIndexByName(_collection,
- _descriptor->indexName(), true);
- fassert( 17341, idxNo >= 0 );
- return idxNo;
- }
-
-
// ------------------
const IndexCatalogEntry* IndexCatalogEntryContainer::find( const IndexDescriptor* desc ) const {
diff --git a/src/mongo/db/catalog/index_catalog_entry.h b/src/mongo/db/catalog/index_catalog_entry.h
index e5b835405be..77f19c8d99b 100644
--- a/src/mongo/db/catalog/index_catalog_entry.h
+++ b/src/mongo/db/catalog/index_catalog_entry.h
@@ -38,25 +38,26 @@
namespace mongo {
- class Collection;
+ class CollectionCatalogEntry;
+ class CollectionInfoCache;
class HeadManager;
class IndexAccessMethod;
class IndexDescriptor;
- class RecordStore;
class OperationContext;
class IndexCatalogEntry {
MONGO_DISALLOW_COPYING( IndexCatalogEntry );
public:
- IndexCatalogEntry( Collection* collection,
+ IndexCatalogEntry( const StringData& ns,
+ CollectionCatalogEntry* collection, // not owned
IndexDescriptor* descriptor, // ownership passes to me
- RecordStore* recordStore ); // ownership passes to me
+ CollectionInfoCache* infoCache ); // not owned, optional
~IndexCatalogEntry();
- void init( IndexAccessMethod* accessMethod );
+ const string& ns() const { return _ns; }
- const Collection* collection() const { return _collection; }
+ void init( IndexAccessMethod* accessMethod );
IndexDescriptor* descriptor() { return _descriptor; }
const IndexDescriptor* descriptor() const { return _descriptor; }
@@ -64,9 +65,6 @@ namespace mongo {
IndexAccessMethod* accessMethod() { return _accessMethod; }
const IndexAccessMethod* accessMethod() const { return _accessMethod; }
- RecordStore* recordStore() { return _recordStore; }
- const RecordStore* recordStore() const { return _recordStore; }
-
const Ordering& ordering() const { return _ordering; }
/// ---------------------
@@ -90,19 +88,19 @@ namespace mongo {
private:
- int _indexNo() const;
-
bool _catalogIsReady() const;
DiskLoc _catalogHead() const;
bool _catalogIsMultikey() const;
// -----
- Collection* _collection; // not owned here
+ string _ns;
+
+ CollectionCatalogEntry* _collection; // not owned here
IndexDescriptor* _descriptor; // owned here
- RecordStore* _recordStore; // owned here
+ CollectionInfoCache* _infoCache; // not owned here
IndexAccessMethod* _accessMethod; // owned here
diff --git a/src/mongo/db/catalog/index_create.cpp b/src/mongo/db/catalog/index_create.cpp
index e28bc4b7ec3..0243a74891a 100644
--- a/src/mongo/db/catalog/index_create.cpp
+++ b/src/mongo/db/catalog/index_create.cpp
@@ -233,7 +233,9 @@ namespace mongo {
<< status.toString(),
status.isOK() );
- IndexAccessMethod* bulk = doInBackground ? NULL : btreeState->accessMethod()->initiateBulk(txn);
+ IndexAccessMethod* bulk = doInBackground ?
+ NULL : btreeState->accessMethod()->initiateBulk(txn,
+ collection->numRecords());
scoped_ptr<IndexAccessMethod> bulkHolder(bulk);
IndexAccessMethod* iam = bulk ? bulk : btreeState->accessMethod();
@@ -341,7 +343,7 @@ namespace mongo {
if ( !status.isOK() )
return status;
- state.bulk = state.real->initiateBulk(_txn);
+ state.bulk = state.real->initiateBulk(_txn, _collection->numRecords() );
_states.push_back( state );
}
diff --git a/src/mongo/db/commands/dbhash.cpp b/src/mongo/db/commands/dbhash.cpp
index 183813f196b..df10255418e 100644
--- a/src/mongo/db/commands/dbhash.cpp
+++ b/src/mongo/db/commands/dbhash.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/commands.h"
#include "mongo/db/catalog/database.h"
#include "mongo/db/query/internal_plans.h"
+#include "mongo/db/structure/catalog/namespace_index.h"
#include "mongo/util/md5.hpp"
#include "mongo/util/timer.h"
@@ -147,7 +148,7 @@ namespace mongo {
Client::ReadContext ctx(ns);
Database* db = ctx.ctx().db();
if ( db )
- db->namespaceIndex().getNamespaces( colls );
+ db->namespaceIndex()->getNamespaces( colls );
colls.sort();
result.appendNumber( "numCollections" , (long long)colls.size() );
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index 245d02d2c02..44a5b3bf461 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -38,9 +38,9 @@
#include "mongo/base/initializer.h"
#include "mongo/base/status.h"
#include "mongo/db/auth/auth_index_d.h"
-#include "mongo/db/auth/authz_manager_external_state_d.h"
#include "mongo/db/auth/authorization_manager.h"
#include "mongo/db/auth/authorization_manager_global.h"
+#include "mongo/db/auth/authz_manager_external_state_d.h"
#include "mongo/db/catalog/index_catalog.h"
#include "mongo/db/catalog/index_key_validate.h"
#include "mongo/db/client.h"
@@ -52,7 +52,6 @@
#include "mongo/db/db.h"
#include "mongo/db/dbmessage.h"
#include "mongo/db/dbwebserver.h"
-#include "mongo/db/storage/mmap_v1/dur.h"
#include "mongo/db/index_names.h"
#include "mongo/db/index_rebuilder.h"
#include "mongo/db/initialize_server_global_state.h"
@@ -62,12 +61,13 @@
#include "mongo/db/kill_current_op.h"
#include "mongo/db/log_process_details.h"
#include "mongo/db/mongod_options.h"
+#include "mongo/db/operation_context_impl.h"
#include "mongo/db/pdfile_version.h"
#include "mongo/db/query/internal_plans.h"
#include "mongo/db/range_deleter_service.h"
#include "mongo/db/repair_database.h"
-#include "mongo/db/repl/repl_start.h"
#include "mongo/db/repl/repl_settings.h"
+#include "mongo/db/repl/repl_start.h"
#include "mongo/db/repl/rs.h"
#include "mongo/db/restapi.h"
#include "mongo/db/startup_warnings.h"
@@ -75,9 +75,10 @@
#include "mongo/db/stats/snapshots.h"
#include "mongo/db/storage/data_file.h"
#include "mongo/db/storage/extent_manager.h"
-#include "mongo/db/operation_context_impl.h"
+#include "mongo/db/storage/mmap_v1/dur.h"
#include "mongo/db/storage/mmap_v1/mmap_v1_extent_manager.h"
#include "mongo/db/storage_options.h"
+#include "mongo/db/structure/catalog/namespace_index.h"
#include "mongo/db/ttl.h"
#include "mongo/platform/process_id.h"
#include "mongo/s/d_writeback.h"
@@ -327,7 +328,7 @@ namespace mongo {
}
list<string> collections;
- db->namespaceIndex().getNamespaces( collections );
+ db->namespaceIndex()->getNamespaces( collections );
// for each collection, ensure there is a $_id_ index
for (list<string>::iterator i = collections.begin(); i != collections.end(); ++i) {
diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp
index 126866dc82b..9661ccfc0ae 100644
--- a/src/mongo/db/dbcommands.cpp
+++ b/src/mongo/db/dbcommands.cpp
@@ -70,6 +70,7 @@
#include "mongo/db/storage/extent_manager.h"
#include "mongo/db/storage/mmap_v1/mmap_v1_extent_manager.h"
#include "mongo/db/storage/record.h"
+#include "mongo/db/catalog/collection_catalog_entry.h"
#include "mongo/db/structure/catalog/namespace_details.h"
#include "mongo/db/write_concern.h"
#include "mongo/s/d_logic.h"
@@ -170,7 +171,7 @@ namespace mongo {
const BSONObj& cmdObj) {
invariant(db);
std::list<std::string> collections;
- db->namespaceIndex().getNamespaces(collections, true /* onlyCollections */);
+ db->namespaceIndex()->getNamespaces(collections, true /* onlyCollections */);
std::vector<BSONObj> allKilledIndexes;
for (std::list<std::string>::iterator it = collections.begin();
@@ -256,7 +257,7 @@ namespace mongo {
const BSONObj& cmdObj) {
invariant(db);
std::list<std::string> collections;
- db->namespaceIndex().getNamespaces(collections, true /* onlyCollections */);
+ db->namespaceIndex()->getNamespaces(collections, true /* onlyCollections */);
std::vector<BSONObj> allKilledIndexes;
for (std::list<std::string>::iterator it = collections.begin();
@@ -1110,7 +1111,7 @@ namespace mongo {
scale );
result.append( "nindexes" , collection->getIndexCatalog()->numIndexesReady() );
- collection->appendCustomStats( &result, scale );
+ collection->getRecordStore()->appendCustomStats( &result, scale );
BSONObjBuilder indexSizes;
result.appendNumber( "totalIndexSize" , getIndexSizeForCollection(dbname, ns, &indexSizes, scale) / scale );
@@ -1165,22 +1166,6 @@ namespace mongo {
else if ( LiteParsedQuery::cmdOptionMaxTimeMS == e.fieldNameStringData() ) {
// no-op
}
- else if ( str::equals( "usePowerOf2Sizes", e.fieldName() ) ) {
- bool oldPowerOf2 = coll->isUserFlagSet(NamespaceDetails::Flag_UsePowerOf2Sizes);
- bool newPowerOf2 = e.trueValue();
-
- if ( oldPowerOf2 != newPowerOf2 ) {
- // change userFlags
- result.appendBool( "usePowerOf2Sizes_old", oldPowerOf2 );
-
- if ( newPowerOf2 )
- coll->setUserFlag( txn, NamespaceDetails::Flag_UsePowerOf2Sizes );
- else
- coll->clearUserFlag( txn, NamespaceDetails::Flag_UsePowerOf2Sizes );
-
- result.appendBool( "usePowerOf2Sizes_new", newPowerOf2 );
- }
- }
else if ( str::equals( "index", e.fieldName() ) ) {
BSONObj indexObj = e.Obj();
BSONObj keyPattern = indexObj.getObjectField( "keyPattern" );
@@ -1225,13 +1210,24 @@ namespace mongo {
if ( oldExpireSecs != newExpireSecs ) {
// change expireAfterSeconds
result.appendAs( oldExpireSecs, "expireAfterSeconds_old" );
- coll->getIndexCatalog()->updateTTLSetting( txn, idx, newExpireSecs.numberLong() );
+ coll->getCatalogEntry()->updateTTLSetting( txn,
+ idx->indexName(),
+ newExpireSecs.numberLong() );
result.appendAs( newExpireSecs , "expireAfterSeconds_new" );
}
}
else {
- errmsg = str::stream() << "unknown option to collMod: " << e.fieldName();
- ok = false;
+ Status s = coll->getRecordStore()->setCustomOption( txn, e, &result );
+ if ( s.isOK() ) {
+ // no-op
+ }
+ else if ( s.code() == ErrorCodes::InvalidOptions ) {
+ errmsg = str::stream() << "unknown option to collMod: " << e.fieldName();
+ ok = false;
+ }
+ else {
+ return appendCommandStatus( result, s );
+ }
}
}
@@ -1290,7 +1286,7 @@ namespace mongo {
d = NULL;
if ( d )
- d->namespaceIndex().getNamespaces( collections );
+ d->namespaceIndex()->getNamespaces( collections );
long long ncollections = 0;
long long objects = 0;
@@ -1333,7 +1329,7 @@ namespace mongo {
result.appendNumber( "indexSize" , indexSize / scale );
if ( d ) {
result.appendNumber( "fileSize" , d->fileSize() / scale );
- result.appendNumber( "nsSizeMB", (int) d->namespaceIndex().fileLength() / 1024 / 1024 );
+ result.appendNumber( "nsSizeMB", (int) d->namespaceIndex()->fileLength() / 1024 / 1024 );
}
else {
result.appendNumber( "fileSize" , 0 );
diff --git a/src/mongo/db/dbhelpers.h b/src/mongo/db/dbhelpers.h
index 758491e0297..a5e9947f918 100644
--- a/src/mongo/db/dbhelpers.h
+++ b/src/mongo/db/dbhelpers.h
@@ -28,11 +28,9 @@
#pragma once
-// TODO: Remove
-#include "mongo/pch.h"
-
#include "mongo/db/client.h"
#include "mongo/db/db.h"
+#include "mongo/db/diskloc.h"
#include "mongo/db/keypattern.h"
#include "mongo/s/range_arithmetic.h"
diff --git a/src/mongo/db/exec/2d.cpp b/src/mongo/db/exec/2d.cpp
index 5142beb7195..758f17f825b 100644
--- a/src/mongo/db/exec/2d.cpp
+++ b/src/mongo/db/exec/2d.cpp
@@ -160,7 +160,7 @@ namespace twod_exec {
//
GeoCircleBrowse::GeoCircleBrowse(const TwoDParams& params, TwoDAccessMethod* accessMethod)
- : GeoBrowse(accessMethod, "circle", params.filter) {
+ : GeoBrowse(params.collection, accessMethod, "circle", params.filter) {
_converter = accessMethod->getParams().geoHashConverter;
@@ -231,7 +231,7 @@ namespace twod_exec {
//
GeoBoxBrowse::GeoBoxBrowse(const TwoDParams& params, TwoDAccessMethod* accessMethod)
- : GeoBrowse(accessMethod, "box", params.filter) {
+ : GeoBrowse(params.collection, accessMethod, "box", params.filter) {
_converter = accessMethod->getParams().geoHashConverter;
@@ -273,7 +273,7 @@ namespace twod_exec {
//
GeoPolygonBrowse::GeoPolygonBrowse(const TwoDParams& params, TwoDAccessMethod* accessMethod)
- : GeoBrowse(accessMethod, "polygon", params.filter) {
+ : GeoBrowse(params.collection, accessMethod, "polygon", params.filter) {
_converter = accessMethod->getParams().geoHashConverter;
diff --git a/src/mongo/db/exec/2dcommon.cpp b/src/mongo/db/exec/2dcommon.cpp
index a469c591c40..fc2529258f7 100644
--- a/src/mongo/db/exec/2dcommon.cpp
+++ b/src/mongo/db/exec/2dcommon.cpp
@@ -104,8 +104,11 @@ namespace twod_exec {
// GeoAccumulator
//
- GeoAccumulator::GeoAccumulator(TwoDAccessMethod* accessMethod, MatchExpression* filter)
- : _accessMethod(accessMethod), _converter(accessMethod->getParams().geoHashConverter),
+ GeoAccumulator::GeoAccumulator(Collection* collection,
+ TwoDAccessMethod* accessMethod,
+ MatchExpression* filter)
+ : _collection(collection),
+ _accessMethod(accessMethod), _converter(accessMethod->getParams().geoHashConverter),
_filter(filter),
_lookedAt(0), _matchesPerfd(0), _objectsLoaded(0), _pointsLoaded(0), _found(0) { }
@@ -135,7 +138,7 @@ namespace twod_exec {
GeoMatchableDocument md(_accessMethod->getDescriptor()->keyPattern(),
node._key,
node.recordLoc,
- _accessMethod->collection(),
+ _collection,
&fetched);
bool good = _filter->matches(&md);
@@ -306,14 +309,15 @@ namespace twod_exec {
// GeoBrowse
//
- GeoBrowse::GeoBrowse(TwoDAccessMethod* accessMethod, string type, MatchExpression* filter)
- : GeoAccumulator(accessMethod, filter),
+ GeoBrowse::GeoBrowse(Collection* collection,
+ TwoDAccessMethod* accessMethod, string type, MatchExpression* filter)
+ : GeoAccumulator(collection, accessMethod, filter),
_type(type), _firstCall(true), _nscanned(),
_centerPrefix(0, 0, 0),
_descriptor(accessMethod->getDescriptor()),
_converter(accessMethod->getParams().geoHashConverter),
_params(accessMethod->getParams()),
- _collection(accessMethod->collection()) {
+ _collection(collection) {
// Set up the initial expand state
_state = START;
diff --git a/src/mongo/db/exec/2dcommon.h b/src/mongo/db/exec/2dcommon.h
index 6986e3d4a7b..67307038482 100644
--- a/src/mongo/db/exec/2dcommon.h
+++ b/src/mongo/db/exec/2dcommon.h
@@ -141,7 +141,8 @@ namespace twod_exec {
class GeoAccumulator {
public:
- GeoAccumulator(TwoDAccessMethod* accessMethod, MatchExpression* filter);
+ GeoAccumulator(Collection* collection,
+ TwoDAccessMethod* accessMethod, MatchExpression* filter);
virtual ~GeoAccumulator();
@@ -159,6 +160,7 @@ namespace twod_exec {
virtual KeyResult approxKeyCheck(const Point& p, double& keyD) = 0;
+ Collection* _collection;
TwoDAccessMethod* _accessMethod;
shared_ptr<GeoHashConverter> _converter;
std::map<DiskLoc, bool> _matched;
@@ -185,7 +187,10 @@ namespace twod_exec {
DONE
} _state;
- GeoBrowse(TwoDAccessMethod* accessMethod, std::string type, MatchExpression* filter);
+ GeoBrowse(Collection* collection,
+ TwoDAccessMethod* accessMethod,
+ std::string type,
+ MatchExpression* filter);
virtual bool ok();
virtual bool advance();
diff --git a/src/mongo/db/exec/2dnear.cpp b/src/mongo/db/exec/2dnear.cpp
index 7c4c4dd8598..dda74d064e3 100644
--- a/src/mongo/db/exec/2dnear.cpp
+++ b/src/mongo/db/exec/2dnear.cpp
@@ -65,7 +65,8 @@ namespace mongo {
TwoDAccessMethod* am = static_cast<TwoDAccessMethod*>( indexCatalog->getIndex( desc ) );
auto_ptr<twod_exec::GeoSearch> search;
- search.reset(new twod_exec::GeoSearch(am,
+ search.reset(new twod_exec::GeoSearch(_params.collection,
+ am,
_params.nearQuery.centroid.oldPoint,
_params.numWanted,
_params.filter,
@@ -162,13 +163,14 @@ namespace twod_exec {
// GeoHopper
//
- GeoHopper::GeoHopper(TwoDAccessMethod* accessMethod,
+ GeoHopper::GeoHopper(Collection* collection,
+ TwoDAccessMethod* accessMethod,
unsigned max,
const Point& n,
MatchExpression* filter,
double maxDistance,
GeoDistType type)
- : GeoBrowse(accessMethod, "search", filter),
+ : GeoBrowse(collection, accessMethod, "search", filter),
_max(max),
_near(n),
_maxDistance(maxDistance),
@@ -177,7 +179,7 @@ namespace twod_exec {
? accessMethod->getParams().geoHashConverter->getError()
: accessMethod->getParams().geoHashConverter->getErrorSphere()),
_farthest(0),
- _collection(accessMethod->collection()) {}
+ _collection(collection) {}
GeoAccumulator:: KeyResult GeoHopper::approxKeyCheck(const Point& p, double& d) {
// Always check approximate distance, since it lets us avoid doing
@@ -294,13 +296,14 @@ namespace twod_exec {
// GeoSearch
//
- GeoSearch::GeoSearch(TwoDAccessMethod* accessMethod,
+ GeoSearch::GeoSearch(Collection* collection,
+ TwoDAccessMethod* accessMethod,
const Point& startPt,
int numWanted,
MatchExpression* filter,
double maxDistance,
GeoDistType type)
- : GeoHopper(accessMethod, numWanted, startPt, filter, maxDistance, type),
+ : GeoHopper(collection, accessMethod, numWanted, startPt, filter, maxDistance, type),
_start(accessMethod->getParams().geoHashConverter->hash(startPt.x, startPt.y)),
_numWanted(numWanted),
_type(type),
diff --git a/src/mongo/db/exec/2dnear.h b/src/mongo/db/exec/2dnear.h
index f7bc255a3ef..6d3ac4254d8 100644
--- a/src/mongo/db/exec/2dnear.h
+++ b/src/mongo/db/exec/2dnear.h
@@ -106,7 +106,8 @@ namespace twod_exec {
public:
typedef multiset<GeoPoint> Holder;
- GeoHopper(TwoDAccessMethod* accessMethod,
+ GeoHopper(Collection* collection,
+ TwoDAccessMethod* accessMethod,
unsigned max,
const Point& n,
MatchExpression* filter,
@@ -146,7 +147,8 @@ namespace twod_exec {
class GeoSearch : public GeoHopper {
public:
- GeoSearch(TwoDAccessMethod* accessMethod,
+ GeoSearch(Collection* collection,
+ TwoDAccessMethod* accessMethod,
const Point& startPt,
int numWanted = 100,
MatchExpression* filter = NULL,
diff --git a/src/mongo/db/geo/haystack.cpp b/src/mongo/db/geo/haystack.cpp
index 13eb964376d..b5c61765b79 100644
--- a/src/mongo/db/geo/haystack.cpp
+++ b/src/mongo/db/geo/haystack.cpp
@@ -111,7 +111,7 @@ namespace mongo {
IndexDescriptor* desc = idxs[0];
HaystackAccessMethod* ham =
static_cast<HaystackAccessMethod*>( collection->getIndexCatalog()->getIndex(desc) );
- ham->searchCommand(nearElt.Obj(), maxDistance.numberDouble(), search.Obj(),
+ ham->searchCommand(collection, nearElt.Obj(), maxDistance.numberDouble(), search.Obj(),
&result, limit);
return 1;
}
diff --git a/src/mongo/db/index/2d_access_method.cpp b/src/mongo/db/index/2d_access_method.cpp
index 7a5cbc9ff0b..8823c3a08c9 100644
--- a/src/mongo/db/index/2d_access_method.cpp
+++ b/src/mongo/db/index/2d_access_method.cpp
@@ -41,8 +41,9 @@
namespace mongo {
- TwoDAccessMethod::TwoDAccessMethod(IndexCatalogEntry* btreeState)
- : BtreeBasedAccessMethod(btreeState) {
+ TwoDAccessMethod::TwoDAccessMethod(IndexCatalogEntry* btreeState,
+ RecordStore* rs)
+ : BtreeBasedAccessMethod(btreeState, rs) {
const IndexDescriptor* descriptor = btreeState->descriptor();
diff --git a/src/mongo/db/index/2d_access_method.h b/src/mongo/db/index/2d_access_method.h
index e7796ea0b4d..2f8eea41959 100644
--- a/src/mongo/db/index/2d_access_method.h
+++ b/src/mongo/db/index/2d_access_method.h
@@ -68,7 +68,8 @@ namespace mongo {
public:
using BtreeBasedAccessMethod::_descriptor;
- TwoDAccessMethod(IndexCatalogEntry* btreeState);
+ TwoDAccessMethod(IndexCatalogEntry* btreeState,
+ RecordStore* rs);
virtual ~TwoDAccessMethod() { }
private:
diff --git a/src/mongo/db/index/btree_access_method.cpp b/src/mongo/db/index/btree_access_method.cpp
index 91a76c42f82..f9baf4e94d0 100644
--- a/src/mongo/db/index/btree_access_method.cpp
+++ b/src/mongo/db/index/btree_access_method.cpp
@@ -40,8 +40,8 @@
namespace mongo {
// Standard Btree implementation below.
- BtreeAccessMethod::BtreeAccessMethod(IndexCatalogEntry* btreeState)
- : BtreeBasedAccessMethod(btreeState) {
+ BtreeAccessMethod::BtreeAccessMethod(IndexCatalogEntry* btreeState, RecordStore* rs )
+ : BtreeBasedAccessMethod(btreeState, rs) {
// The key generation wants these values.
vector<const char*> fieldNames;
diff --git a/src/mongo/db/index/btree_access_method.h b/src/mongo/db/index/btree_access_method.h
index d40bc013767..74c4cdfc997 100644
--- a/src/mongo/db/index/btree_access_method.h
+++ b/src/mongo/db/index/btree_access_method.h
@@ -51,7 +51,8 @@ namespace mongo {
// superclass and subclasses (like this) can use them.
using BtreeBasedAccessMethod::_descriptor;
- BtreeAccessMethod(IndexCatalogEntry* btreeState );
+ BtreeAccessMethod(IndexCatalogEntry* btreeState,
+ RecordStore* rs );
virtual ~BtreeAccessMethod() { }
private:
diff --git a/src/mongo/db/index/btree_based_access_method.cpp b/src/mongo/db/index/btree_based_access_method.cpp
index 6d16f375dc0..8258c23f347 100644
--- a/src/mongo/db/index/btree_based_access_method.cpp
+++ b/src/mongo/db/index/btree_based_access_method.cpp
@@ -41,8 +41,6 @@
#include "mongo/db/kill_current_op.h"
#include "mongo/db/pdfile.h"
#include "mongo/db/pdfile_private.h"
-#include "mongo/db/repl/is_master.h"
-#include "mongo/db/repl/rs.h"
#include "mongo/db/server_parameters.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/structure/btree/btree_interface.h"
@@ -66,12 +64,15 @@ namespace mongo {
static InvalidateCursorsNotification invalidateCursors;
- BtreeBasedAccessMethod::BtreeBasedAccessMethod(IndexCatalogEntry* btreeState)
- : _btreeState(btreeState), _descriptor(btreeState->descriptor()) {
+ BtreeBasedAccessMethod::BtreeBasedAccessMethod(IndexCatalogEntry* btreeState,
+ RecordStore* recordStore)
+ : _btreeState(btreeState),
+ _recordStore( recordStore ),
+ _descriptor(btreeState->descriptor()) {
verify(0 == _descriptor->version() || 1 == _descriptor->version());
_newInterface.reset(BtreeInterface::getInterface(btreeState->headManager(),
- btreeState->recordStore(),
+ recordStore,
btreeState->ordering(),
_descriptor->indexNamespace(),
_descriptor->version(),
@@ -104,7 +105,7 @@ namespace mongo {
if (ErrorCodes::KeyTooLong == status.code()) {
// Ignore this error if we're on a secondary.
- if (!isMasterNs(collection()->ns().ns().c_str())) {
+ if (!txn->isPrimaryFor(_btreeState->ns())) {
continue;
}
@@ -149,7 +150,6 @@ namespace mongo {
problem() << "Assertion failure: _unindex failed "
<< _descriptor->indexNamespace() << endl;
out() << "Assertion failure: _unindex failed: " << e.what() << '\n';
- out() << " obj:" << _btreeState->collection()->docFor(loc).toString() << '\n';
out() << " key:" << key.toString() << '\n';
out() << " dl:" << loc.toString() << endl;
logContext();
@@ -182,8 +182,7 @@ namespace mongo {
++*numDeleted;
} else if (options.logIfError) {
log() << "unindex failed (key too big?) " << _descriptor->indexNamespace()
- << " key: " << *i << " "
- << _btreeState->collection()->docFor(loc)["_id"] << endl;
+ << " key: " << *i;
}
}
@@ -227,8 +226,9 @@ namespace mongo {
return Status::OK();
}
+
Status BtreeBasedAccessMethod::touch( OperationContext* txn ) const {
- return _btreeState->recordStore()->touch( txn, NULL );
+ return _recordStore->touch( txn, NULL );
}
DiskLoc BtreeBasedAccessMethod::findSingle(const BSONObj& key) const {
@@ -323,7 +323,8 @@ namespace mongo {
return Status::OK();
}
- IndexAccessMethod* BtreeBasedAccessMethod::initiateBulk(OperationContext* txn) {
+ IndexAccessMethod* BtreeBasedAccessMethod::initiateBulk(OperationContext* txn,
+ int64_t numRecords ) {
// If there's already data in the index, don't do anything.
if (!_newInterface->isEmpty()) {
return NULL;
@@ -333,7 +334,7 @@ namespace mongo {
this,
_newInterface.get(),
_descriptor,
- _btreeState->collection()->numRecords());
+ static_cast<int>( numRecords ) );
}
Status BtreeBasedAccessMethod::commitBulk(IndexAccessMethod* bulkRaw,
diff --git a/src/mongo/db/index/btree_based_access_method.h b/src/mongo/db/index/btree_based_access_method.h
index decfbb0bc9a..c54c71d401f 100644
--- a/src/mongo/db/index/btree_based_access_method.h
+++ b/src/mongo/db/index/btree_based_access_method.h
@@ -41,6 +41,7 @@
namespace mongo {
class ExternalSortComparison;
+ class RecordStore;
/**
* Any access method that is Btree based subclasses from this.
@@ -56,7 +57,8 @@ namespace mongo {
class BtreeBasedAccessMethod : public IndexAccessMethod {
MONGO_DISALLOW_COPYING( BtreeBasedAccessMethod );
public:
- BtreeBasedAccessMethod( IndexCatalogEntry* btreeState );
+ BtreeBasedAccessMethod( IndexCatalogEntry* btreeState,
+ RecordStore* recordStore );
virtual ~BtreeBasedAccessMethod() { }
@@ -86,7 +88,7 @@ namespace mongo {
virtual Status initializeAsEmpty(OperationContext* txn);
- virtual IndexAccessMethod* initiateBulk(OperationContext* txn) ;
+ virtual IndexAccessMethod* initiateBulk(OperationContext* txn, int64_t numRecords );
virtual Status commitBulk( IndexAccessMethod* bulk,
bool mayInterrupt,
@@ -111,15 +113,9 @@ namespace mongo {
virtual void getKeys(const BSONObj &obj, BSONObjSet *keys) = 0;
IndexCatalogEntry* _btreeState; // owned by IndexCatalogEntry
+ scoped_ptr<RecordStore> _recordStore; // owned by us
const IndexDescriptor* _descriptor;
- /**
- * The collection is needed for resolving record locations to actual objects.
- */
- const Collection* collection() const {
- return _btreeState->collection();
- }
-
private:
bool removeOneKey(OperationContext* txn,
const BSONObj& key,
diff --git a/src/mongo/db/index/btree_based_bulk_access_method.cpp b/src/mongo/db/index/btree_based_bulk_access_method.cpp
index 5d2f0906564..ca6e6022d53 100644
--- a/src/mongo/db/index/btree_based_bulk_access_method.cpp
+++ b/src/mongo/db/index/btree_based_bulk_access_method.cpp
@@ -141,7 +141,7 @@ namespace mongo {
// XXX: do we expect the tree to be empty but have a head set? Looks like so from old code.
invariant(!oldHead.isNull());
_real->_btreeState->setHead(_txn, DiskLoc());
- _real->_btreeState->recordStore()->deleteRecord(_txn, oldHead);
+ _real->_recordStore->deleteRecord(_txn, oldHead);
if (_isMultiKey) {
_real->_btreeState->setMultikey( _txn );
diff --git a/src/mongo/db/index/btree_based_bulk_access_method.h b/src/mongo/db/index/btree_based_bulk_access_method.h
index cedf1eedf80..856a1c3b1de 100644
--- a/src/mongo/db/index/btree_based_bulk_access_method.h
+++ b/src/mongo/db/index/btree_based_bulk_access_method.h
@@ -119,7 +119,7 @@ namespace mongo {
return _notAllowed();
}
- virtual IndexAccessMethod* initiateBulk(OperationContext* txn) {
+ virtual IndexAccessMethod* initiateBulk(OperationContext* txn, int64_t numRecords ) {
return NULL;
}
diff --git a/src/mongo/db/index/fts_access_method.cpp b/src/mongo/db/index/fts_access_method.cpp
index c803867b812..5eb20d4f8cf 100644
--- a/src/mongo/db/index/fts_access_method.cpp
+++ b/src/mongo/db/index/fts_access_method.cpp
@@ -31,8 +31,8 @@
namespace mongo {
- FTSAccessMethod::FTSAccessMethod(IndexCatalogEntry* btreeState)
- : BtreeBasedAccessMethod(btreeState), _ftsSpec(btreeState->descriptor()->infoObj()) { }
+ FTSAccessMethod::FTSAccessMethod(IndexCatalogEntry* btreeState, RecordStore* rs )
+ : BtreeBasedAccessMethod(btreeState, rs), _ftsSpec(btreeState->descriptor()->infoObj()) { }
void FTSAccessMethod::getKeys(const BSONObj& obj, BSONObjSet* keys) {
ExpressionKeysPrivate::getFTSKeys(obj, _ftsSpec, keys);
diff --git a/src/mongo/db/index/fts_access_method.h b/src/mongo/db/index/fts_access_method.h
index ba10b4e2b67..2ea4fecc375 100644
--- a/src/mongo/db/index/fts_access_method.h
+++ b/src/mongo/db/index/fts_access_method.h
@@ -38,7 +38,7 @@ namespace mongo {
class FTSAccessMethod : public BtreeBasedAccessMethod {
public:
- FTSAccessMethod(IndexCatalogEntry* btreeState );
+ FTSAccessMethod(IndexCatalogEntry* btreeState, RecordStore* rs );
virtual ~FTSAccessMethod() { }
const fts::FTSSpec& getSpec() const { return _ftsSpec; }
diff --git a/src/mongo/db/index/hash_access_method.cpp b/src/mongo/db/index/hash_access_method.cpp
index 7457c68c085..bb3684c020a 100644
--- a/src/mongo/db/index/hash_access_method.cpp
+++ b/src/mongo/db/index/hash_access_method.cpp
@@ -33,8 +33,8 @@
namespace mongo {
- HashAccessMethod::HashAccessMethod(IndexCatalogEntry* btreeState)
- : BtreeBasedAccessMethod(btreeState) {
+ HashAccessMethod::HashAccessMethod(IndexCatalogEntry* btreeState, RecordStore* rs)
+ : BtreeBasedAccessMethod(btreeState, rs) {
const IndexDescriptor* descriptor = btreeState->descriptor();
diff --git a/src/mongo/db/index/hash_access_method.h b/src/mongo/db/index/hash_access_method.h
index e6e701158ce..0b6777a16da 100644
--- a/src/mongo/db/index/hash_access_method.h
+++ b/src/mongo/db/index/hash_access_method.h
@@ -45,7 +45,7 @@ namespace mongo {
public:
using BtreeBasedAccessMethod::_descriptor;
- HashAccessMethod(IndexCatalogEntry* btreeState);
+ HashAccessMethod(IndexCatalogEntry* btreeState, RecordStore* rs);
virtual ~HashAccessMethod() { }
// This is a NO-OP.
diff --git a/src/mongo/db/index/haystack_access_method.cpp b/src/mongo/db/index/haystack_access_method.cpp
index 59e97a6191c..9bf1ee6593b 100644
--- a/src/mongo/db/index/haystack_access_method.cpp
+++ b/src/mongo/db/index/haystack_access_method.cpp
@@ -39,8 +39,8 @@
namespace mongo {
- HaystackAccessMethod::HaystackAccessMethod(IndexCatalogEntry* btreeState)
- : BtreeBasedAccessMethod(btreeState) {
+ HaystackAccessMethod::HaystackAccessMethod(IndexCatalogEntry* btreeState, RecordStore* rs)
+ : BtreeBasedAccessMethod(btreeState, rs) {
const IndexDescriptor* descriptor = btreeState->descriptor();
@@ -57,7 +57,8 @@ namespace mongo {
ExpressionKeysPrivate::getHaystackKeys(obj, _geoField, _otherFields, _bucketSize, keys);
}
- void HaystackAccessMethod::searchCommand(const BSONObj& nearObj, double maxDistance,
+ void HaystackAccessMethod::searchCommand(Collection* collection,
+ const BSONObj& nearObj, double maxDistance,
const BSONObj& search, BSONObjBuilder* result,
unsigned limit) {
Timer t;
@@ -72,7 +73,7 @@ namespace mongo {
}
int scale = static_cast<int>(ceil(maxDistance / _bucketSize));
- GeoHaystackSearchHopper hopper(nearObj, maxDistance, limit, _geoField, collection());
+ GeoHaystackSearchHopper hopper(nearObj, maxDistance, limit, _geoField, collection);
long long btreeMatches = 0;
@@ -95,7 +96,7 @@ namespace mongo {
unordered_set<DiskLoc, DiskLoc::Hasher> thisPass;
- scoped_ptr<Runner> runner(InternalPlanner::indexScan(_btreeState->collection(),
+ scoped_ptr<Runner> runner(InternalPlanner::indexScan(collection,
_descriptor, key, key, true));
Runner::RunnerState state;
DiskLoc loc;
diff --git a/src/mongo/db/index/haystack_access_method.h b/src/mongo/db/index/haystack_access_method.h
index 82d8eccf6ef..e1a4fe9e7df 100644
--- a/src/mongo/db/index/haystack_access_method.h
+++ b/src/mongo/db/index/haystack_access_method.h
@@ -35,6 +35,8 @@
namespace mongo {
+ class Collection;
+
/**
* Maps (lat, lng) to the bucketSize-sided square bucket that contains it.
* Examines all documents in a given radius of a given point.
@@ -55,12 +57,13 @@ namespace mongo {
public:
using BtreeBasedAccessMethod::_descriptor;
- HaystackAccessMethod(IndexCatalogEntry* btreeState);
+ HaystackAccessMethod(IndexCatalogEntry* btreeState, RecordStore* rs);
virtual ~HaystackAccessMethod() { }
protected:
friend class GeoHaystackSearchCommand;
- void searchCommand(const BSONObj& nearObj, double maxDistance, const BSONObj& search,
+ void searchCommand(Collection* collection,
+ const BSONObj& nearObj, double maxDistance, const BSONObj& search,
BSONObjBuilder* result, unsigned limit);
private:
diff --git a/src/mongo/db/index/index_access_method.h b/src/mongo/db/index/index_access_method.h
index 6268ad0cb90..efdc59384aa 100644
--- a/src/mongo/db/index/index_access_method.h
+++ b/src/mongo/db/index/index_access_method.h
@@ -168,7 +168,7 @@ namespace mongo {
* For now (1/8/14) you can only do bulk when the index is empty
* it will fail if you try other times.
*/
- virtual IndexAccessMethod* initiateBulk(OperationContext* txn) = 0;
+ virtual IndexAccessMethod* initiateBulk(OperationContext* txn, int64_t numRecords ) = 0;
/**
* Call this when you are ready to finish your bulk work.
diff --git a/src/mongo/db/index/s2_access_method.cpp b/src/mongo/db/index/s2_access_method.cpp
index 9cbfd2d418b..c75ec66d44e 100644
--- a/src/mongo/db/index/s2_access_method.cpp
+++ b/src/mongo/db/index/s2_access_method.cpp
@@ -43,8 +43,8 @@ namespace mongo {
static const string kIndexVersionFieldName("2dsphereIndexVersion");
- S2AccessMethod::S2AccessMethod(IndexCatalogEntry* btreeState)
- : BtreeBasedAccessMethod(btreeState) {
+ S2AccessMethod::S2AccessMethod(IndexCatalogEntry* btreeState, RecordStore* rs)
+ : BtreeBasedAccessMethod(btreeState, rs) {
const IndexDescriptor* descriptor = btreeState->descriptor();
diff --git a/src/mongo/db/index/s2_access_method.h b/src/mongo/db/index/s2_access_method.h
index df12026395b..666d2bb1e98 100644
--- a/src/mongo/db/index/s2_access_method.h
+++ b/src/mongo/db/index/s2_access_method.h
@@ -43,7 +43,7 @@ namespace mongo {
public:
using BtreeBasedAccessMethod::_descriptor;
- S2AccessMethod(IndexCatalogEntry* btreeState);
+ S2AccessMethod(IndexCatalogEntry* btreeState, RecordStore* rs);
virtual ~S2AccessMethod() { }
/**
diff --git a/src/mongo/db/index_rebuilder.cpp b/src/mongo/db/index_rebuilder.cpp
index da1dc347cec..015a39b95cb 100644
--- a/src/mongo/db/index_rebuilder.cpp
+++ b/src/mongo/db/index_rebuilder.cpp
@@ -36,6 +36,7 @@
#include "mongo/db/instance.h"
#include "mongo/db/pdfile.h"
#include "mongo/db/repl/rs.h"
+#include "mongo/db/structure/catalog/namespace_index.h"
#include "mongo/db/operation_context_impl.h"
#include "mongo/util/scopeguard.h"
@@ -64,7 +65,7 @@ namespace mongo {
dbName++) {
Client::ReadContext ctx(*dbName);
Database* db = ctx.ctx().db();
- db->namespaceIndex().getNamespaces(collNames, /* onlyCollections */ true);
+ db->namespaceIndex()->getNamespaces(collNames, /* onlyCollections */ true);
}
checkNS(collNames);
}
diff --git a/src/mongo/db/namespace_string.h b/src/mongo/db/namespace_string.h
index 0639c686dc5..53ed2447fb4 100644
--- a/src/mongo/db/namespace_string.h
+++ b/src/mongo/db/namespace_string.h
@@ -95,6 +95,7 @@ namespace mongo {
bool isValid() const { return validDBName( db() ) && !coll().empty(); }
bool operator==( const std::string& nsIn ) const { return nsIn == _ns; }
+ bool operator==( const StringData& nsIn ) const { return nsIn == _ns; }
bool operator==( const NamespaceString& nsIn ) const { return nsIn._ns == _ns; }
bool operator!=( const std::string& nsIn ) const { return nsIn != _ns; }
diff --git a/src/mongo/db/operation_context.h b/src/mongo/db/operation_context.h
index 25da4ee3560..d7bfc4f8f5c 100644
--- a/src/mongo/db/operation_context.h
+++ b/src/mongo/db/operation_context.h
@@ -32,6 +32,7 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
+#include "mongo/base/string_data.h"
#include "mongo/db/storage/recovery_unit.h"
namespace mongo {
@@ -80,6 +81,11 @@ namespace mongo {
int secondsBetween = 3) = 0;
/**
+ * @return true if this instance is primary for this namespace
+ */
+ virtual bool isPrimaryFor( const StringData& ns ) = 0;
+
+ /**
* Returns a OperationContext. Caller takes ownership.
*
* This interface is used for functions that need to create transactions (aka OpCtx), but
diff --git a/src/mongo/db/operation_context_impl.cpp b/src/mongo/db/operation_context_impl.cpp
index 055ab5d6ef0..dde8ded49c1 100644
--- a/src/mongo/db/operation_context_impl.cpp
+++ b/src/mongo/db/operation_context_impl.cpp
@@ -31,6 +31,7 @@
#include "mongo/db/client.h"
#include "mongo/db/curop.h"
#include "mongo/db/kill_current_op.h"
+#include "mongo/db/repl/is_master.h"
#include "mongo/db/storage/mmap_v1/dur_recovery_unit.h"
namespace mongo {
@@ -62,6 +63,11 @@ namespace mongo {
return Status( ErrorCodes::Interrupted, killed );
}
+ bool OperationContextImpl::isPrimaryFor( const StringData& ns ) {
+ string s = ns.toString(); // TODO: fix copy
+ return isMasterNs( s.c_str() );
+ }
+
OperationContext* OperationContextImpl::factory() {
return new OperationContextImpl();
}
diff --git a/src/mongo/db/operation_context_impl.h b/src/mongo/db/operation_context_impl.h
index 6f7b5a7ff2d..01d21f3acff 100644
--- a/src/mongo/db/operation_context_impl.h
+++ b/src/mongo/db/operation_context_impl.h
@@ -52,6 +52,8 @@ namespace mongo {
virtual Status checkForInterruptNoAssert() const;
+ virtual bool isPrimaryFor( const StringData& ns );
+
/**
* Returns an OperationContext. Caller takes ownership.
*/
diff --git a/src/mongo/db/operation_context_noop.h b/src/mongo/db/operation_context_noop.h
index de5832215a7..b442f872ad9 100644
--- a/src/mongo/db/operation_context_noop.h
+++ b/src/mongo/db/operation_context_noop.h
@@ -58,6 +58,10 @@ namespace mongo {
return Status::OK();
}
+ virtual bool isPrimaryFor( const StringData& ns ) {
+ return true;
+ }
+
private:
boost::scoped_ptr<RecoveryUnitNoop> _recoveryUnit;
};
diff --git a/src/mongo/db/repair_database.cpp b/src/mongo/db/repair_database.cpp
index 0e5087c0b4c..72620d77609 100644
--- a/src/mongo/db/repair_database.cpp
+++ b/src/mongo/db/repair_database.cpp
@@ -41,6 +41,7 @@
#include "mongo/db/index/index_descriptor.h"
#include "mongo/util/file.h"
#include "mongo/util/file_allocator.h"
+#include "mongo/util/mmap.h"
namespace mongo {
diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_engine.cpp b/src/mongo/db/storage/mmap_v1/mmap_v1_engine.cpp
new file mode 100644
index 00000000000..a8edffb2642
--- /dev/null
+++ b/src/mongo/db/storage/mmap_v1/mmap_v1_engine.cpp
@@ -0,0 +1,333 @@
+// mmap_v1_engine.cpp
+
+/**
+* Copyright (C) 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 <http://www.gnu.org/licenses/>.
+*
+* 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.
+*/
+
+#include "mongo/db/storage/mmap_v1/mmap_v1_engine.h"
+
+#include "mongo/db/catalog/database.h"
+#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/fts_access_method.h"
+#include "mongo/db/index/hash_access_method.h"
+#include "mongo/db/index/haystack_access_method.h"
+#include "mongo/db/index/s2_access_method.h"
+#include "mongo/db/server_parameters.h"
+#include "mongo/db/structure/catalog/namespace_details.h"
+#include "mongo/db/structure/catalog/namespace_details_collection_entry.h"
+#include "mongo/db/structure/catalog/namespace_details_rsv1_metadata.h"
+#include "mongo/db/structure/record_store_v1_capped.h"
+#include "mongo/db/structure/record_store_v1_simple.h"
+
+namespace mongo {
+
+ MONGO_EXPORT_SERVER_PARAMETER(newCollectionsUsePowerOf2Sizes, bool, true);
+
+ MMAP1DatabaseCatalogEntry::MMAP1DatabaseCatalogEntry( OperationContext* txn,
+ const StringData& name,
+ const StringData& path,
+ bool directoryPerDB )
+ : _name( name.toString() ),
+ _path( path.toString() ),
+ _extentManager( name, path, directoryPerDB ),
+ _namespaceIndex( _path, _name ) {
+
+ try {
+ _checkDuplicateUncasedNames();
+
+ Status s = _extentManager.init(txn);
+ if ( !s.isOK() ) {
+ msgasserted( 16966, str::stream() << "_extentManager.init failed: " << s.toString() );
+ }
+
+ // If already exists, open. Otherwise behave as if empty until
+ // there's a write, then open.
+
+ if ( _namespaceIndex.pathExists() ) {
+ _namespaceIndex.init( txn );
+
+ // upgrade freelist
+ string oldFreeList = _name + ".$freelist";
+ NamespaceDetails* details = _namespaceIndex.details( oldFreeList );
+ if ( details ) {
+ if ( !details->firstExtent.isNull() ) {
+ _extentManager.freeExtents(txn,
+ details->firstExtent,
+ details->lastExtent);
+ }
+ _namespaceIndex.kill_ns( txn, oldFreeList );
+ }
+ }
+ }
+ catch(std::exception& e) {
+ log() << "warning database " << path << " " << name << " could not be opened";
+ DBException* dbe = dynamic_cast<DBException*>(&e);
+ if ( dbe != 0 ) {
+ log() << "DBException " << dbe->getCode() << ": " << e.what() << endl;
+ }
+ else {
+ log() << e.what() << endl;
+ }
+ _extentManager.reset();
+ throw;
+ }
+
+
+ }
+
+ MMAP1DatabaseCatalogEntry::~MMAP1DatabaseCatalogEntry() {
+ }
+
+ void MMAP1DatabaseCatalogEntry::_checkDuplicateUncasedNames() const {
+ string duplicate = Database::duplicateUncasedName(true, _name, _path );
+ if ( !duplicate.empty() ) {
+ stringstream ss;
+ ss << "db already exists with different case already have: [" << duplicate
+ << "] trying to create [" << _name << "]";
+ uasserted( DatabaseDifferCaseCode , ss.str() );
+ }
+ }
+
+ namespace {
+ int _massageExtentSize( const ExtentManager* em, long long size ) {
+ if ( size < em->minSize() )
+ return em->minSize();
+ if ( size > em->maxSize() )
+ return em->maxSize();
+ return static_cast<int>( size );
+ }
+ }
+
+ Status MMAP1DatabaseCatalogEntry::createCollection( OperationContext* txn,
+ const StringData& ns,
+ const CollectionOptions& options,
+ bool allocateDefaultSpace ) {
+ _namespaceIndex.init( txn );
+
+ if ( _namespaceIndex.details( ns ) ) {
+ return Status( ErrorCodes::NamespaceExists,
+ str::stream() << "namespace already exists: " << ns );
+ }
+
+ BSONObj optionsAsBSON = options.toBSON();
+ _addNamespaceToNamespaceCollection( txn, ns, &optionsAsBSON );
+
+ _namespaceIndex.add_ns( txn, ns, DiskLoc(), options.capped );
+
+ // allocation strategy set explicitly in flags or by server-wide default
+ if ( !options.capped ) {
+ NamespaceDetailsRSV1MetaData md( ns,
+ _namespaceIndex.details( ns ),
+ _getNamespaceRecordStore( txn, ns ) );
+
+ if ( options.flagsSet ) {
+ md.setUserFlag( txn, options.flags );
+ }
+ else if ( newCollectionsUsePowerOf2Sizes ) {
+ md.setUserFlag( txn, NamespaceDetails::Flag_UsePowerOf2Sizes );
+ }
+ }
+ else if ( options.cappedMaxDocs > 0 ) {
+ txn->recoveryUnit()->writingInt( _namespaceIndex.details( ns )->maxDocsInCapped ) =
+ options.cappedMaxDocs;
+ }
+
+ if ( allocateDefaultSpace ) {
+ scoped_ptr<RecordStoreV1Base> rs( _getRecordStore( txn, ns ) );
+ if ( options.initialNumExtents > 0 ) {
+ int size = _massageExtentSize( &_extentManager, options.cappedSize );
+ for ( int i = 0; i < options.initialNumExtents; i++ ) {
+ rs->increaseStorageSize( txn, size, -1 );
+ }
+ }
+ else if ( !options.initialExtentSizes.empty() ) {
+ for ( size_t i = 0; i < options.initialExtentSizes.size(); i++ ) {
+ int size = options.initialExtentSizes[i];
+ size = _massageExtentSize( &_extentManager, size );
+ rs->increaseStorageSize( txn, size, -1 );
+ }
+ }
+ else if ( options.capped ) {
+ // normal
+ while ( rs->storageSize() < options.cappedSize ) {
+ int sz = _massageExtentSize( &_extentManager,
+ options.cappedSize - rs->storageSize() );
+ sz &= 0xffffff00;
+ rs->increaseStorageSize( txn, sz, -1 );
+ }
+ }
+ else {
+ rs->increaseStorageSize( txn, _extentManager.initialSize( 128 ), -1 );
+ }
+ }
+
+ return Status::OK();
+ }
+
+ CollectionCatalogEntry* MMAP1DatabaseCatalogEntry::getCollectionCatalogEntry( OperationContext* txn,
+ const StringData& ns ) {
+ NamespaceDetails* details = _namespaceIndex.details( ns );
+ if ( !details ) {
+ return NULL;
+ }
+
+ return new NamespaceDetailsCollectionCatalogEntry( ns,
+ details,
+ _getIndexRecordStore( txn ),
+ this );
+ }
+
+ RecordStore* MMAP1DatabaseCatalogEntry::getRecordStore( OperationContext* txn,
+ const StringData& ns ) {
+ return _getRecordStore( txn, ns );
+ }
+
+ RecordStoreV1Base* MMAP1DatabaseCatalogEntry::_getRecordStore( OperationContext* txn,
+ const StringData& ns ) {
+
+ // XXX TODO - CACHE
+
+ NamespaceString nss( ns );
+ NamespaceDetails* details = _namespaceIndex.details( ns );
+ if ( !details ) {
+ return NULL;
+ }
+
+ auto_ptr<NamespaceDetailsRSV1MetaData> md( new NamespaceDetailsRSV1MetaData( ns,
+ details,
+ _getNamespaceRecordStore( txn, ns ) ) );
+
+ if ( details->isCapped ) {
+ return new CappedRecordStoreV1( txn,
+ NULL, //TOD(ERH) this will blow up :)
+ ns,
+ md.release(),
+ &_extentManager,
+ nss.coll() == "system.indexes" );
+ }
+
+ return new SimpleRecordStoreV1( txn,
+ ns,
+ md.release(),
+ &_extentManager,
+ nss.coll() == "system.indexes" );
+ }
+
+ IndexAccessMethod* MMAP1DatabaseCatalogEntry::getIndex( OperationContext* txn,
+ const CollectionCatalogEntry* collection,
+ IndexCatalogEntry* entry ) {
+ const string& type = entry->descriptor()->getAccessMethodName();
+
+ string ns = collection->ns().ns();
+
+ if ( IndexNames::TEXT == type ||
+ entry->descriptor()->getInfoElement("expireAfterSeconds").isNumber() ) {
+ NamespaceDetailsRSV1MetaData md( ns,
+ _namespaceIndex.details( ns ),
+ _getNamespaceRecordStore( txn, ns ) );
+ md.setUserFlag( txn, NamespaceDetails::Flag_UsePowerOf2Sizes );
+ }
+
+ RecordStore* rs = _getRecordStore( txn, entry->descriptor()->indexNamespace() );
+ invariant( rs );
+
+ if (IndexNames::HASHED == type)
+ return new HashAccessMethod( entry, rs );
+
+ if (IndexNames::GEO_2DSPHERE == type)
+ return new S2AccessMethod( entry, rs );
+
+ if (IndexNames::TEXT == type)
+ return new FTSAccessMethod( entry, rs );
+
+ if (IndexNames::GEO_HAYSTACK == type)
+ return new HaystackAccessMethod( entry, rs );
+
+ if ("" == type)
+ return new BtreeAccessMethod( entry, rs );
+
+ if (IndexNames::GEO_2D == type)
+ return new TwoDAccessMethod( entry, rs );
+
+ log() << "Can't find index for keyPattern " << entry->descriptor()->keyPattern();
+ fassertFailed(17489);
+ }
+
+ RecordStoreV1Base* MMAP1DatabaseCatalogEntry::_getIndexRecordStore( OperationContext* txn ) {
+ NamespaceString nss( _name, "system.indexes" );
+ RecordStoreV1Base* rs = _getRecordStore( txn, nss.ns() );
+ if ( rs != NULL )
+ return rs;
+ CollectionOptions options;
+ Status status = createCollection( txn, nss.ns(), options, true );
+ massertStatusOK( status );
+ rs = _getRecordStore( txn, nss.ns() );
+ invariant( rs );
+ return rs;
+ }
+
+ RecordStoreV1Base* MMAP1DatabaseCatalogEntry::_getNamespaceRecordStore( OperationContext* txn,
+ const StringData& whosAsking) {
+ NamespaceString nss( _name, "system.namespaces" );
+ if ( nss == whosAsking )
+ return NULL;
+ RecordStoreV1Base* rs = _getRecordStore( txn, nss.ns() );
+ if ( rs != NULL )
+ return rs;
+ CollectionOptions options;
+ Status status = createCollection( txn, nss.ns(), options, true );
+ massertStatusOK( status );
+ rs = _getRecordStore( txn, nss.ns() );
+ invariant( rs );
+ return rs;
+
+ }
+
+ void MMAP1DatabaseCatalogEntry::_addNamespaceToNamespaceCollection( OperationContext* txn,
+ const StringData& ns,
+ const BSONObj* options ) {
+ if ( nsToCollectionSubstring( ns ) == "system.namespaces" ) {
+ // system.namespaces holds all the others, so it is not explicitly listed in the catalog.
+ return;
+ }
+
+ BSONObjBuilder b;
+ b.append("name", ns);
+ if ( options && !options->isEmpty() )
+ b.append("options", *options);
+ BSONObj obj = b.done();
+
+ RecordStoreV1Base* rs = _getNamespaceRecordStore( txn, ns );
+ invariant( rs );
+ StatusWith<DiskLoc> loc = rs->insertRecord( txn, obj.objdata(), obj.objsize(), -1 );
+ massertStatusOK( loc.getStatus() );
+ }
+
+}
diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_engine.h b/src/mongo/db/storage/mmap_v1/mmap_v1_engine.h
new file mode 100644
index 00000000000..09d8be4112f
--- /dev/null
+++ b/src/mongo/db/storage/mmap_v1/mmap_v1_engine.h
@@ -0,0 +1,111 @@
+// mmap_v1_engine.h
+
+/**
+* Copyright (C) 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 <http://www.gnu.org/licenses/>.
+*
+* 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.
+*/
+
+#include "mongo/base/status.h"
+#include "mongo/base/string_data.h"
+#include "mongo/db/storage/mmap_v1/mmap_v1_extent_manager.h"
+#include "mongo/db/structure/catalog/namespace_index.h"
+
+namespace mongo {
+
+ class CollectionCatalogEntry;
+ struct CollectionOptions;
+ class IndexAccessMethod;
+ class IndexCatalogEntry;
+ class IndexDescriptor;
+ class RecordStore;
+ class RecordStoreV1Base;
+ class OperationContext;
+
+ class MMAP1DatabaseCatalogEntry {
+ public:
+ MMAP1DatabaseCatalogEntry( OperationContext* txn,
+ const StringData& name,
+ const StringData& path,
+ bool directoryperdb );
+
+ virtual ~MMAP1DatabaseCatalogEntry();
+
+ bool exists() const { return _namespaceIndex.pathExists(); }
+
+ Status createCollection( OperationContext* txn,
+ const StringData& ns,
+ const CollectionOptions& options,
+ bool allocateDefaultSpace );
+
+ /*
+ * ownership passes to caller
+ * will return NULL if ns does not exist
+ */
+ CollectionCatalogEntry* getCollectionCatalogEntry( OperationContext* txn,
+ const StringData& ns );
+
+ // ownership passes to caller
+ RecordStore* getRecordStore( OperationContext* txn,
+ const StringData& ns );
+
+ // ownership passes to caller
+ IndexAccessMethod* getIndex( OperationContext* txn,
+ const CollectionCatalogEntry* collection,
+ IndexCatalogEntry* index );
+
+ const MmapV1ExtentManager* getExtentManager() const { return &_extentManager; } // TODO(ERH): remove
+ MmapV1ExtentManager* getExtentManager() { return &_extentManager; } // TODO(ERH): remove
+
+ const NamespaceIndex& namespaceIndex() const { return _namespaceIndex; } // TODO(ERH): remove
+ NamespaceIndex& namespaceIndex() { return _namespaceIndex; } // TODO(ERH): remove
+
+ private:
+
+ RecordStoreV1Base* _getIndexRecordStore( OperationContext* txn );
+ RecordStoreV1Base* _getNamespaceRecordStore( OperationContext* txn,
+ const StringData& whosAsking );
+
+ RecordStoreV1Base* _getRecordStore( OperationContext* txn,
+ const StringData& ns );
+
+ void _addNamespaceToNamespaceCollection( OperationContext* txn,
+ const StringData& ns,
+ const BSONObj* options );
+ /**
+ * @throws DatabaseDifferCaseCode if the name is a duplicate based on
+ * case insensitive matching.
+ */
+ void _checkDuplicateUncasedNames() const;
+
+ std::string _name;
+ std::string _path;
+
+ MmapV1ExtentManager _extentManager;
+ NamespaceIndex _namespaceIndex;
+
+ friend class NamespaceDetailsCollectionCatalogEntry;
+ };
+}
diff --git a/src/mongo/db/structure/btree/btree_logic.h b/src/mongo/db/structure/btree/btree_logic.h
index e0c9942c12e..3cbc5e35241 100644
--- a/src/mongo/db/structure/btree/btree_logic.h
+++ b/src/mongo/db/structure/btree/btree_logic.h
@@ -42,6 +42,7 @@
namespace mongo {
class BucketDeletionNotification;
+ class RecordStore;
/**
* This is the logic for manipulating the Btree. It is (mostly) independent of the on-disk
diff --git a/src/mongo/db/structure/catalog/namespace_details.cpp b/src/mongo/db/structure/catalog/namespace_details.cpp
index e94f6118737..3b3216188fa 100644
--- a/src/mongo/db/structure/catalog/namespace_details.cpp
+++ b/src/mongo/db/structure/catalog/namespace_details.cpp
@@ -57,30 +57,30 @@ namespace mongo {
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::Extra) <= sizeof(NamespaceDetails) );
/* be sure to initialize new fields here -- doesn't default to zeroes the way we use it */
- _firstExtent = _lastExtent = _capExtent = loc;
- _stats.datasize = _stats.nrecords = 0;
- _lastExtentSize = 0;
- _nIndexes = 0;
- _isCapped = capped;
- _maxDocsInCapped = 0x7fffffff; // no limit (value is for pre-v2.3.2 compatibility)
- _paddingFactor = 1.0;
- _systemFlagsOld = 0;
- _userFlags = 0;
- _capFirstNewRecord = DiskLoc();
+ firstExtent = lastExtent = capExtent = loc;
+ stats.datasize = stats.nrecords = 0;
+ lastExtentSize = 0;
+ nIndexes = 0;
+ isCapped = capped;
+ maxDocsInCapped = 0x7fffffff; // no limit (value is for pre-v2.3.2 compatibility)
+ paddingFactor = 1.0;
+ systemFlagsOldDoNotUse = 0;
+ userFlags = 0;
+ capFirstNewRecord = DiskLoc();
// Signal that we are on first allocation iteration through extents.
- _capFirstNewRecord.setInvalid();
+ capFirstNewRecord.setInvalid();
// For capped case, signal that we are doing initial extent allocation.
if ( capped ) {
// WAS: cappedLastDelRecLastExtent().setInvalid();
- _deletedList[1].setInvalid();
+ deletedList[1].setInvalid();
}
verify( sizeof(_dataFileVersion) == 2 );
_dataFileVersion = 0;
_indexFileVersion = 0;
- _multiKeyIndexBits = 0;
+ multiKeyIndexBits = 0;
_reservedA = 0;
_extraOffset = 0;
- _indexBuildsInProgress = 0;
+ indexBuildsInProgress = 0;
memset(_reserved, 0, sizeof(_reserved));
}
@@ -119,49 +119,6 @@ namespace mongo {
return e;
}
- bool NamespaceDetails::setIndexIsMultikey(OperationContext* txn, int i, bool multikey) {
- massert(16577, "index number greater than NIndexesMax", i < NIndexesMax );
-
- unsigned long long mask = 1ULL << i;
-
- if (multikey) {
- // Shortcut if the bit is already set correctly
- if (_multiKeyIndexBits & mask) {
- return false;
- }
-
- *txn->recoveryUnit()->writing(&_multiKeyIndexBits) |= mask;
- }
- else {
- // Shortcut if the bit is already set correctly
- if (!(_multiKeyIndexBits & mask)) {
- return false;
- }
-
- // Invert mask: all 1's except a 0 at the ith bit
- mask = ~mask;
- *txn->recoveryUnit()->writing(&_multiKeyIndexBits) &= mask;
- }
-
- return true;
- }
-
- IndexDetails& NamespaceDetails::getNextIndexDetails(OperationContext* txn,
- Collection* collection) {
- IndexDetails *id;
- try {
- id = &idx(getTotalIndexCount(), true);
- }
- catch(DBException&) {
- allocExtra(txn,
- collection->ns().ns(),
- collection->_database->namespaceIndex(),
- getTotalIndexCount());
- id = &idx(getTotalIndexCount(), false);
- }
- return *id;
- }
-
IndexDetails& NamespaceDetails::idx(int idxNo, bool missingExpected) {
if( idxNo < NIndexesBase ) {
IndexDetails& id = _indexes[idxNo];
@@ -211,12 +168,13 @@ namespace mongo {
return e->details[i];
}
-
NamespaceDetails::IndexIterator::IndexIterator(const NamespaceDetails *_d,
bool includeBackgroundInProgress) {
d = _d;
i = 0;
- n = includeBackgroundInProgress ? d->getTotalIndexCount() : d->_nIndexes;
+ n = d->nIndexes;
+ if ( includeBackgroundInProgress )
+ n += d->indexBuildsInProgress;
}
// must be called when renaming a NS to fix up extra
@@ -259,7 +217,7 @@ namespace mongo {
massert( 16499,
"max in a capped collection has to be < 2^31 or -1",
validMaxCappedDocs( &max ) );
- _maxDocsInCapped = max;
+ maxDocsInCapped = max;
}
bool NamespaceDetails::validMaxCappedDocs( long long* max ) {
@@ -276,155 +234,8 @@ namespace mongo {
return false;
}
- long long NamespaceDetails::maxCappedDocs() const {
- verify( isCapped() );
- if ( _maxDocsInCapped == 0x7fffffff )
- return numeric_limits<long long>::max();
- return _maxDocsInCapped;
- }
-
/* ------------------------------------------------------------------------- */
- void NamespaceDetails::setLastExtentSize( OperationContext* txn, int newMax ) {
- if ( _lastExtentSize == newMax )
- return;
- txn->recoveryUnit()->writingInt(_lastExtentSize) = newMax;
- }
-
- void NamespaceDetails::incrementStats( OperationContext* txn,
- long long dataSizeIncrement,
- long long numRecordsIncrement ) {
-
- // durability todo : this could be a bit annoying / slow to record constantly
- Stats* s = txn->recoveryUnit()->writing( &_stats );
- s->datasize += dataSizeIncrement;
- s->nrecords += numRecordsIncrement;
- }
-
- void NamespaceDetails::setStats( OperationContext* txn,
- long long dataSize,
- long long numRecords ) {
- Stats* s = txn->recoveryUnit()->writing( &_stats );
- s->datasize = dataSize;
- s->nrecords = numRecords;
- }
-
- void NamespaceDetails::setFirstExtent( OperationContext* txn,
- const DiskLoc& loc ) {
- *txn->recoveryUnit()->writing( &_firstExtent ) = loc;
- }
-
- void NamespaceDetails::setLastExtent( OperationContext* txn,
- const DiskLoc& loc ) {
- *txn->recoveryUnit()->writing( &_lastExtent ) = loc;
- }
-
- void NamespaceDetails::setCapExtent( OperationContext* txn,
- const DiskLoc& loc ) {
- *txn->recoveryUnit()->writing( &_capExtent ) = loc;
- }
-
- void NamespaceDetails::setCapFirstNewRecord( OperationContext* txn,
- const DiskLoc& loc ) {
- *txn->recoveryUnit()->writing( &_capFirstNewRecord ) = loc;
- }
-
- void NamespaceDetails::setFirstExtentInvalid( OperationContext* txn ) {
- *txn->recoveryUnit()->writing( &_firstExtent ) = DiskLoc().setInvalid();
- }
-
- void NamespaceDetails::setLastExtentInvalid( OperationContext* txn ) {
- *txn->recoveryUnit()->writing( &_lastExtent ) = DiskLoc().setInvalid();
- }
-
- void NamespaceDetails::setDeletedListEntry( OperationContext* txn,
- int bucket, const DiskLoc& loc ) {
- *txn->recoveryUnit()->writing( &_deletedList[bucket] ) = loc;
- }
-
- bool NamespaceDetails::setUserFlag( OperationContext* txn, int flags ) {
- if ( ( _userFlags & flags ) == flags )
- return false;
-
- txn->recoveryUnit()->writingInt(_userFlags) |= flags;
- return true;
- }
-
- bool NamespaceDetails::clearUserFlag( OperationContext* txn, int flags ) {
- if ( ( _userFlags & flags ) == 0 )
- return false;
-
- txn->recoveryUnit()->writingInt(_userFlags) &= ~flags;
- return true;
- }
-
- bool NamespaceDetails::replaceUserFlags( OperationContext* txn, int flags ) {
- if ( flags == _userFlags )
- return false;
-
- txn->recoveryUnit()->writingInt(_userFlags) = flags;
- return true;
- }
-
- void NamespaceDetails::setPaddingFactor( OperationContext* txn, double paddingFactor ) {
- if ( paddingFactor == _paddingFactor )
- return;
-
- if ( isCapped() )
- return;
-
- *txn->recoveryUnit()->writing(&_paddingFactor) = paddingFactor;
- }
-
- /* remove bit from a bit array - actually remove its slot, not a clear
- note: this function does not work with x == 63 -- that is ok
- but keep in mind in the future if max indexes were extended to
- exactly 64 it would be a problem
- */
- unsigned long long removeAndSlideBit(unsigned long long b, int x) {
- unsigned long long tmp = b;
- return
- (tmp & ((((unsigned long long) 1) << x)-1)) |
- ((tmp >> (x+1)) << x);
- }
-
- void NamespaceDetails::_removeIndexFromMe( OperationContext* txn, int idxNumber ) {
-
- // TODO: don't do this whole thing, do it piece meal for readability
- NamespaceDetails* d = writingWithExtra( txn );
-
- // fix the _multiKeyIndexBits, by moving all bits above me down one
- d->_multiKeyIndexBits = removeAndSlideBit(d->_multiKeyIndexBits, idxNumber);
-
- if ( idxNumber >= _nIndexes )
- d->_indexBuildsInProgress--;
- else
- d->_nIndexes--;
-
- for ( int i = idxNumber; i < getTotalIndexCount(); i++ )
- d->idx(i) = d->idx(i+1);
-
- d->idx( getTotalIndexCount() ) = IndexDetails();
- }
-
- void NamespaceDetails::swapIndex( OperationContext* txn, int a, int b ) {
-
- // flip main meta data
- IndexDetails temp = idx(a);
- *txn->recoveryUnit()->writing(&idx(a)) = idx(b);
- *txn->recoveryUnit()->writing(&idx(b)) = temp;
-
- // flip multi key bits
- bool tempMultikey = isMultikey(a);
- setIndexIsMultikey( txn, a, isMultikey(b) );
- setIndexIsMultikey( txn, b, tempMultikey );
- }
-
- void NamespaceDetails::orphanDeletedList( OperationContext* txn ) {
- for( int i = 0; i < Buckets; i++ ) {
- *txn->recoveryUnit()->writing(&_deletedList[i]) = DiskLoc();
- }
- }
int NamespaceDetails::_catalogFindIndexByName(const Collection* coll,
const StringData& name,
@@ -443,18 +254,4 @@ namespace mongo {
*txn->recoveryUnit()->writing(&_next) = ofs;
}
- /* ------------------------------------------------------------------------- */
-
- class IndexUpdateTest : public StartupTest {
- public:
- void run() {
- verify( removeAndSlideBit(1, 0) == 0 );
- verify( removeAndSlideBit(2, 0) == 1 );
- verify( removeAndSlideBit(2, 1) == 0 );
- verify( removeAndSlideBit(255, 1) == 127 );
- verify( removeAndSlideBit(21, 2) == 9 );
- verify( removeAndSlideBit(0x4000000000000001ULL, 62) == 1 );
- }
- } iu_unittest;
-
} // namespace mongo
diff --git a/src/mongo/db/structure/catalog/namespace_details.h b/src/mongo/db/structure/catalog/namespace_details.h
index 468e5e967b1..3d8411fa8d9 100644
--- a/src/mongo/db/structure/catalog/namespace_details.h
+++ b/src/mongo/db/structure/catalog/namespace_details.h
@@ -55,12 +55,12 @@ namespace mongo {
public:
enum { NIndexesMax = 64, NIndexesExtra = 30, NIndexesBase = 10 };
- private:
+
/*-------- data fields, as present on disk : */
- DiskLoc _firstExtent;
- DiskLoc _lastExtent;
+ DiskLoc firstExtent;
+ DiskLoc lastExtent;
/* NOTE: capped collections v1 override the meaning of deletedList.
deletedList[0] points to a list of free records (DeletedRecord's) for all extents in
@@ -69,43 +69,50 @@ namespace mongo {
changes, this value is updated. !deletedList[1].isValid() when this value is not
yet computed.
*/
- DiskLoc _deletedList[Buckets];
+ DiskLoc deletedList[Buckets];
// ofs 168 (8 byte aligned)
struct Stats {
// datasize and nrecords MUST Be adjacent code assumes!
long long datasize; // this includes padding, but not record headers
long long nrecords;
- } _stats;
+ } stats;
+
- int _lastExtentSize;
- int _nIndexes;
+ int lastExtentSize;
+
+ int nIndexes;
// ofs 192
IndexDetails _indexes[NIndexesBase];
+ public:
// ofs 352 (16 byte aligned)
- int _isCapped; // there is wasted space here if I'm right (ERH)
- int _maxDocsInCapped; // max # of objects for a capped table, -1 for inf.
+ int isCapped; // there is wasted space here if I'm right (ERH)
+
+ int maxDocsInCapped; // max # of objects for a capped table, -1 for inf.
- double _paddingFactor; // 1.0 = no padding.
+ double paddingFactor; // 1.0 = no padding.
// ofs 368 (16)
- int _systemFlagsOld; // things that the system sets/cares about
+ int systemFlagsOldDoNotUse; // things that the system sets/cares about
- DiskLoc _capExtent; // the "current" extent we're writing too for a capped collection
- DiskLoc _capFirstNewRecord;
+ DiskLoc capExtent; // the "current" extent we're writing too for a capped collection
+ DiskLoc capFirstNewRecord;
unsigned short _dataFileVersion; // NamespaceDetails version. So we can do backward compatibility in the future. See filever.h
unsigned short _indexFileVersion;
- unsigned long long _multiKeyIndexBits;
+
+ unsigned long long multiKeyIndexBits;
// ofs 400 (16)
unsigned long long _reservedA;
long long _extraOffset; // where the $extra info is located (bytes relative to this)
- int _indexBuildsInProgress; // Number of indexes currently being built
+ public:
+ int indexBuildsInProgress; // Number of indexes currently being built
+
+ int userFlags;
- int _userFlags;
char _reserved[72];
/*-------- end data 496 bytes */
public:
@@ -152,63 +159,14 @@ namespace mongo {
NamespaceDetails *src); // must be called when renaming a NS to fix up extra
public:
- const DiskLoc& capExtent() const { return _capExtent; }
- void setCapExtent( OperationContext* txn, const DiskLoc& loc );
-
- const DiskLoc& capFirstNewRecord() const { return _capFirstNewRecord; }
- void setCapFirstNewRecord( OperationContext* txn, const DiskLoc& loc );
-
- public:
-
- const DiskLoc& firstExtent() const { return _firstExtent; }
- void setFirstExtent( OperationContext* txn, const DiskLoc& loc );
-
- const DiskLoc& lastExtent() const { return _lastExtent; }
- void setLastExtent( OperationContext* txn, const DiskLoc& loc );
-
- void setFirstExtentInvalid( OperationContext* txn );
- void setLastExtentInvalid( OperationContext* txn );
-
-
- long long dataSize() const { return _stats.datasize; }
- long long numRecords() const { return _stats.nrecords; }
-
- void incrementStats( OperationContext* txn,
- long long dataSizeIncrement,
- long long numRecordsIncrement );
-
- void setStats( OperationContext* txn,
- long long dataSizeIncrement,
- long long numRecordsIncrement );
-
-
- bool isCapped() const { return _isCapped; }
- long long maxCappedDocs() const;
void setMaxCappedDocs( OperationContext* txn, long long max );
- int lastExtentSize() const { return _lastExtentSize; }
- void setLastExtentSize( OperationContext* txn, int newMax );
-
- const DiskLoc& deletedListEntry( int bucket ) const { return _deletedList[bucket]; }
- void setDeletedListEntry( OperationContext* txn, int bucket, const DiskLoc& loc );
-
- void orphanDeletedList( OperationContext* txn );
-
/**
* @param max in and out, will be adjusted
* @return if the value is valid at all
*/
static bool validMaxCappedDocs( long long* max );
- /* when a background index build is in progress, we don't count the index in nIndexes until
- complete, yet need to still use it in _indexRecord() - thus we use this function for that.
- */
- int getTotalIndexCount() const { return _nIndexes + _indexBuildsInProgress; }
-
- int getCompletedIndexCount() const { return _nIndexes; }
-
- int getIndexBuildsInProgress() const { return _indexBuildsInProgress; }
-
enum UserFlags {
Flag_UsePowerOf2Sizes = 1 << 0
};
@@ -232,73 +190,12 @@ namespace mongo {
return IndexIterator(this, includeBackgroundInProgress);
}
- /* multikey indexes are indexes where there are more than one key in the index
- for a single document. see multikey in docs.
- for these, we have to do some dedup work on queries.
- */
- bool isMultikey(int i) const { return (_multiKeyIndexBits & (((unsigned long long) 1) << i)) != 0; }
-
- /**
- * @return - if any state was changed
- */
- bool setIndexIsMultikey(OperationContext* txn, int i, bool multikey = true);
-
/**
* This fetches the IndexDetails for the next empty index slot. The caller must populate
* returned object. This handles allocating extra index space, if necessary.
*/
IndexDetails& getNextIndexDetails(OperationContext* txn, Collection* collection);
- double paddingFactor() const { return _paddingFactor; }
-
- void setPaddingFactor( OperationContext* txn, double paddingFactor );
-
- /* called to indicate that an update fit in place.
- fits also called on an insert -- idea there is that if you had some mix and then went to
- pure inserts it would adapt and PF would trend to 1.0. note update calls insert on a move
- so there is a double count there that must be adjusted for below.
-
- todo: greater sophistication could be helpful and added later. for example the absolute
- size of documents might be considered -- in some cases smaller ones are more likely
- to grow than larger ones in the same collection? (not always)
- */
- void paddingFits( OperationContext* txn ) {
- MONGO_SOMETIMES(sometimes, 4) { // do this on a sampled basis to journal less
- double x = std::max(1.0, _paddingFactor - 0.001 );
- setPaddingFactor( txn, x );
- }
- }
- void paddingTooSmall( OperationContext* txn ) {
- MONGO_SOMETIMES(sometimes, 4) { // do this on a sampled basis to journal less
- /* the more indexes we have, the higher the cost of a move. so we take that into
- account herein. note on a move that insert() calls paddingFits(), thus
- here for example with no inserts and nIndexes = 1 we have
- .001*4-.001 or a 3:1 ratio to non moves -> 75% nonmoves. insert heavy
- can pushes this down considerably. further tweaking will be a good idea but
- this should be an adequate starting point.
- */
- double N = std::min(_nIndexes,7) + 3;
- double x = std::min(2.0,_paddingFactor + (0.001 * N));
- setPaddingFactor( txn, x );
- }
- }
-
- int userFlags() const { return _userFlags; }
- bool isUserFlagSet( int flag ) const { return _userFlags & flag; }
-
- /**
- * these methods only modify NamespaceDetails and do not
- * sync changes back to system.namespaces
- * a typical call might
- if ( nsd->setUserFlag( 4 ) ) {
- nsd->syncUserFlags();
- }
- * these methods all return true iff only something was modified
- */
- bool setUserFlag( OperationContext* txn, int flag );
- bool clearUserFlag( OperationContext* txn, int flag );
- bool replaceUserFlags( OperationContext* txn, int flags );
-
NamespaceDetails *writingWithoutExtra( OperationContext* txn );
/** Make all linked Extra objects writeable as well */
@@ -316,8 +213,6 @@ namespace mongo {
private:
- void _removeIndexFromMe( OperationContext* txn, int idx );
-
/**
* swaps all meta data for 2 indexes
* a and b are 2 index ids, whose contents will be swapped
@@ -334,7 +229,7 @@ namespace mongo {
BOOST_STATIC_ASSERT( NIndexesMax <= 64 ); // multiKey bits
BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::Extra) == 496 );
}; // NamespaceDetails
- BOOST_STATIC_ASSERT( sizeof(NamespaceDetails) == 496 );
+ BOOST_STATIC_ASSERT( sizeof(NamespaceDetails) == 496 ); // XXX
#pragma pack()
} // namespace mongo
diff --git a/src/mongo/db/structure/catalog/namespace_details_collection_entry.cpp b/src/mongo/db/structure/catalog/namespace_details_collection_entry.cpp
new file mode 100644
index 00000000000..32c78a19100
--- /dev/null
+++ b/src/mongo/db/structure/catalog/namespace_details_collection_entry.cpp
@@ -0,0 +1,325 @@
+// namespace_details_collection_entry.h
+
+/**
+* Copyright (C) 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 <http://www.gnu.org/licenses/>.
+*
+* 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.
+*/
+
+#include "mongo/db/structure/catalog/namespace_details_collection_entry.h"
+
+#include "mongo/db/index/index_descriptor.h"
+#include "mongo/db/storage/mmap_v1/mmap_v1_engine.h"
+#include "mongo/db/structure/catalog/namespace_details.h"
+#include "mongo/db/structure/record_store.h"
+#include "mongo/util/startup_test.h"
+
+namespace mongo {
+ NamespaceDetailsCollectionCatalogEntry::NamespaceDetailsCollectionCatalogEntry( const StringData& ns,
+ NamespaceDetails* details,
+ RecordStore* indexRecordStore,
+ MMAP1DatabaseCatalogEntry* db )
+ : CollectionCatalogEntry( ns ),
+ _details( details ),
+ _indexRecordStore( indexRecordStore ),
+ _db( db ) {
+ }
+
+ int NamespaceDetailsCollectionCatalogEntry::getTotalIndexCount() const {
+ return _details->nIndexes + _details->indexBuildsInProgress;
+ }
+
+ int NamespaceDetailsCollectionCatalogEntry::getCompletedIndexCount() const {
+ return _details->nIndexes;
+ }
+
+ int NamespaceDetailsCollectionCatalogEntry::getMaxAllowedIndexes() const {
+ return NamespaceDetails::NIndexesMax;
+ }
+
+ void NamespaceDetailsCollectionCatalogEntry::getAllIndexes( std::vector<std::string>* names ) const {
+ NamespaceDetails::IndexIterator i = _details->ii( true );
+ while ( i.more() ) {
+ const IndexDetails& id = i.next();
+ const BSONObj obj( _indexRecordStore->recordFor( id.info )->data() );
+ names->push_back( obj.getStringField("name") );
+ }
+ }
+
+ bool NamespaceDetailsCollectionCatalogEntry::isIndexMultikey(const StringData& idxName) const {
+ int idxNo = _findIndexNumber( idxName );
+ invariant( idxNo >= 0 );
+ return isIndexMultikey( idxNo );
+ }
+
+ bool NamespaceDetailsCollectionCatalogEntry::isIndexMultikey(int idxNo) const {
+ return (_details->multiKeyIndexBits & (((unsigned long long) 1) << idxNo)) != 0;
+ }
+
+ bool NamespaceDetailsCollectionCatalogEntry::setIndexIsMultikey(OperationContext* txn,
+ const StringData& indexName,
+ bool multikey ) {
+
+ int idxNo = _findIndexNumber( indexName );
+ invariant( idxNo >= 0 );
+ return setIndexIsMultikey( txn, idxNo, multikey );
+ }
+
+ bool NamespaceDetailsCollectionCatalogEntry::setIndexIsMultikey(OperationContext* txn,
+ int idxNo,
+ bool multikey ) {
+ unsigned long long mask = 1ULL << idxNo;
+
+ if (multikey) {
+ // Shortcut if the bit is already set correctly
+ if (_details->multiKeyIndexBits & mask) {
+ return false;
+ }
+
+ *txn->recoveryUnit()->writing(&_details->multiKeyIndexBits) |= mask;
+ }
+ else {
+ // Shortcut if the bit is already set correctly
+ if (!(_details->multiKeyIndexBits & mask)) {
+ return false;
+ }
+
+ // Invert mask: all 1's except a 0 at the ith bit
+ mask = ~mask;
+ *txn->recoveryUnit()->writing(&_details->multiKeyIndexBits) &= mask;
+ }
+
+ return true;
+ }
+
+ DiskLoc NamespaceDetailsCollectionCatalogEntry::getIndexHead( const StringData& idxName ) const {
+ int idxNo = _findIndexNumber( idxName );
+ invariant( idxNo >= 0 );
+ return _details->idx( idxNo ).head;
+ }
+
+ BSONObj NamespaceDetailsCollectionCatalogEntry::getIndexSpec( const StringData& idxName ) const {
+ int idxNo = _findIndexNumber( idxName );
+ invariant( idxNo >= 0 );
+ const IndexDetails& id = _details->idx( idxNo );
+ return BSONObj( _indexRecordStore->recordFor( id.info )->data() );
+ }
+
+ void NamespaceDetailsCollectionCatalogEntry::setIndexHead( OperationContext* txn,
+ const StringData& idxName,
+ const DiskLoc& newHead ) {
+ int idxNo = _findIndexNumber( idxName );
+ invariant( idxNo >= 0 );
+ *txn->recoveryUnit()->writing( &_details->idx( idxNo ).head) = newHead;
+ }
+
+ bool NamespaceDetailsCollectionCatalogEntry::isIndexReady( const StringData& idxName ) const {
+ int idxNo = _findIndexNumber( idxName );
+ invariant( idxNo >= 0 );
+ return idxNo < getCompletedIndexCount();
+ }
+
+ int NamespaceDetailsCollectionCatalogEntry::_findIndexNumber( const StringData& idxName ) const {
+ NamespaceDetails::IndexIterator i = _details->ii( true );
+ while ( i.more() ) {
+ const IndexDetails& id = i.next();
+ int idxNo = i.pos() - 1;
+ const BSONObj obj( _indexRecordStore->recordFor( id.info )->data() );
+ if ( idxName == obj.getStringField("name") )
+ return idxNo;
+ }
+ return -1;
+ }
+
+ /* remove bit from a bit array - actually remove its slot, not a clear
+ note: this function does not work with x == 63 -- that is ok
+ but keep in mind in the future if max indexes were extended to
+ exactly 64 it would be a problem
+ */
+ unsigned long long removeAndSlideBit(unsigned long long b, int x) {
+ unsigned long long tmp = b;
+ return
+ (tmp & ((((unsigned long long) 1) << x)-1)) |
+ ((tmp >> (x+1)) << x);
+ }
+
+ class IndexUpdateTest : public StartupTest {
+ public:
+ void run() {
+ verify( removeAndSlideBit(1, 0) == 0 );
+ verify( removeAndSlideBit(2, 0) == 1 );
+ verify( removeAndSlideBit(2, 1) == 0 );
+ verify( removeAndSlideBit(255, 1) == 127 );
+ verify( removeAndSlideBit(21, 2) == 9 );
+ verify( removeAndSlideBit(0x4000000000000001ULL, 62) == 1 );
+ }
+ } iu_unittest;
+
+ Status NamespaceDetailsCollectionCatalogEntry::removeIndex( OperationContext* txn,
+ const StringData& indexName ) {
+ int idxNo = _findIndexNumber( indexName );
+ invariant( idxNo >= 0 );
+
+ DiskLoc infoLocation = _details->idx( idxNo ).info;
+
+ // all info in the .ns file
+ {
+ NamespaceDetails* d = _details->writingWithExtra( txn );
+
+ // fix the _multiKeyIndexBits, by moving all bits above me down one
+ d->multiKeyIndexBits = removeAndSlideBit(d->multiKeyIndexBits, idxNo);
+
+ if ( idxNo >= d->nIndexes )
+ d->indexBuildsInProgress--;
+ else
+ d->nIndexes--;
+
+ for ( int i = idxNo; i < getTotalIndexCount(); i++ )
+ d->idx(i) = d->idx(i+1);
+
+ d->idx( getTotalIndexCount() ) = IndexDetails();
+ }
+
+ // remove from system.indexes
+
+ { // sanity check
+ Record* record = _indexRecordStore->recordFor( infoLocation );
+ invariant( record );
+ BSONObj info( record->data() );
+ invariant( info["name"].String() == indexName );
+ }
+
+ _indexRecordStore->deleteRecord( txn, infoLocation );
+
+ return Status::OK();
+ }
+
+ Status NamespaceDetailsCollectionCatalogEntry::prepareForIndexBuild( OperationContext* txn,
+ const IndexDescriptor* desc ) {
+ BSONObj spec = desc->infoObj();
+ // 1) entry in system.indexs
+ StatusWith<DiskLoc> systemIndexesEntry = _indexRecordStore->insertRecord( txn,
+ spec.objdata(),
+ spec.objsize(),
+ -1 );
+ if ( !systemIndexesEntry.isOK() )
+ return systemIndexesEntry.getStatus();
+
+ // 2) NamespaceDetails mods
+ IndexDetails *id;
+ try {
+ id = &_details->idx(getTotalIndexCount(), true);
+ }
+ catch( DBException& ) {
+ _details->allocExtra(txn,
+ ns().ns(),
+ _db->namespaceIndex(),
+ getTotalIndexCount());
+ id = &_details->idx(getTotalIndexCount(), false);
+ }
+
+ *txn->recoveryUnit()->writing( &id->info ) = systemIndexesEntry.getValue();
+ *txn->recoveryUnit()->writing( &id->head ) = DiskLoc();
+
+ txn->recoveryUnit()->writingInt( _details->indexBuildsInProgress ) += 1;
+
+ // 3) indexes entry in .ns file
+ NamespaceIndex& nsi = _db->namespaceIndex();
+ invariant( nsi.details( desc->indexNamespace() ) == NULL );
+ nsi.add_ns( txn, desc->indexNamespace(), DiskLoc(), false );
+
+ // 4) system.namespaces entry index ns
+ _db->_addNamespaceToNamespaceCollection( txn, desc->indexNamespace(), NULL);
+
+ return Status::OK();
+ }
+
+ void NamespaceDetailsCollectionCatalogEntry::indexBuildSuccess( OperationContext* txn,
+ const StringData& indexName ) {
+ int idxNo = _findIndexNumber( indexName );
+ fassert( 17202, idxNo >= 0 );
+
+ // Make sure the newly created index is relocated to nIndexes, if it isn't already there
+ if ( idxNo != getCompletedIndexCount() ) {
+ int toIdxNo = getCompletedIndexCount();
+
+ //_details->swapIndex( txn, idxNo, toIdxNo );
+
+ // flip main meta data
+ IndexDetails temp = _details->idx(idxNo);
+ *txn->recoveryUnit()->writing(&_details->idx(idxNo)) = _details->idx(toIdxNo);
+ *txn->recoveryUnit()->writing(&_details->idx(toIdxNo)) = temp;
+
+ // flip multi key bits
+ bool tempMultikey = isIndexMultikey(idxNo);
+ setIndexIsMultikey( txn, idxNo, isIndexMultikey(toIdxNo) );
+ setIndexIsMultikey( txn, toIdxNo, tempMultikey );
+
+ idxNo = toIdxNo;
+ invariant( idxNo = _findIndexNumber( indexName ) );
+ }
+
+ txn->recoveryUnit()->writingInt( _details->indexBuildsInProgress ) -= 1;
+ txn->recoveryUnit()->writingInt( _details->nIndexes ) += 1;
+
+ invariant( isIndexReady( indexName ) );
+ }
+
+ void NamespaceDetailsCollectionCatalogEntry::updateTTLSetting( OperationContext* txn,
+ const StringData& idxName,
+ long long newExpireSeconds ) {
+ int idx = _findIndexNumber( idxName );
+ invariant( idx >= 0 );
+
+ IndexDetails& indexDetails = _details->idx( idx );
+
+ Record* record = _indexRecordStore->recordFor( indexDetails.info );
+ BSONObj obj( record->data() );
+ const BSONElement oldExpireSecs = obj.getField("expireAfterSeconds");
+
+ // Important that we set the new value in-place. We are writing directly to the
+ // object here so must be careful not to overwrite with a longer numeric type.
+
+ char* nonConstPtr = const_cast<char*>(oldExpireSecs.value());
+ switch( oldExpireSecs.type() ) {
+ case EOO:
+ massert( 16631, "index does not have an 'expireAfterSeconds' field", false );
+ break;
+ case NumberInt:
+ *txn->recoveryUnit()->writing(reinterpret_cast<int*>(nonConstPtr)) = newExpireSeconds;
+ break;
+ case NumberDouble:
+ *txn->recoveryUnit()->writing(reinterpret_cast<double*>(nonConstPtr)) = newExpireSeconds;
+ break;
+ case NumberLong:
+ *txn->recoveryUnit()->writing(reinterpret_cast<long long*>(nonConstPtr)) = newExpireSeconds;
+ break;
+ default:
+ massert( 16632, "current 'expireAfterSeconds' is not a number", false );
+ }
+ }
+
+
+}
diff --git a/src/mongo/db/structure/catalog/namespace_details_collection_entry.h b/src/mongo/db/structure/catalog/namespace_details_collection_entry.h
new file mode 100644
index 00000000000..d87d4ef2a9a
--- /dev/null
+++ b/src/mongo/db/structure/catalog/namespace_details_collection_entry.h
@@ -0,0 +1,104 @@
+// namespace_details_collection_entry.h
+
+#pragma once
+
+/**
+* Copyright (C) 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 <http://www.gnu.org/licenses/>.
+*
+* 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.
+*/
+
+#include "mongo/base/string_data.h"
+#include "mongo/bson/bsonobj.h"
+#include "mongo/db/catalog/collection_catalog_entry.h"
+#include "mongo/db/diskloc.h"
+
+namespace mongo {
+
+ class NamespaceDetails;
+
+ class MMAP1DatabaseCatalogEntry;;
+ class RecordStore;
+ class OperationContext;
+
+ class NamespaceDetailsCollectionCatalogEntry : public CollectionCatalogEntry {
+ public:
+ NamespaceDetailsCollectionCatalogEntry( const StringData& ns,
+ NamespaceDetails* details,
+ RecordStore* indexRecordStore,
+ MMAP1DatabaseCatalogEntry* db );
+
+ virtual ~NamespaceDetailsCollectionCatalogEntry(){}
+
+ virtual int getTotalIndexCount() const;
+
+ virtual int getCompletedIndexCount() const;
+
+ virtual int getMaxAllowedIndexes() const;
+
+ virtual void getAllIndexes( std::vector<std::string>* names ) const;
+
+ virtual BSONObj getIndexSpec( const StringData& idxName ) const;
+
+ virtual bool isIndexMultikey(const StringData& indexName) const;
+ virtual bool isIndexMultikey(int idxNo) const;
+
+ virtual bool setIndexIsMultikey(OperationContext* txn,
+ int idxNo,
+ bool multikey = true);
+ virtual bool setIndexIsMultikey(OperationContext* txn,
+ const StringData& indexName,
+ bool multikey = true);
+
+ virtual DiskLoc getIndexHead( const StringData& indexName ) const;
+
+ virtual void setIndexHead( OperationContext* txn,
+ const StringData& indexName,
+ const DiskLoc& newHead );
+
+ virtual bool isIndexReady( const StringData& indexName ) const;
+
+ virtual Status removeIndex( OperationContext* txn,
+ const StringData& indexName );
+
+ virtual Status prepareForIndexBuild( OperationContext* txn,
+ const IndexDescriptor* spec );
+
+ virtual void indexBuildSuccess( OperationContext* txn,
+ const StringData& indexName );
+
+ virtual void updateTTLSetting( OperationContext* txn,
+ const StringData& idxName,
+ long long newExpireSeconds );
+ private:
+ int _findIndexNumber( const StringData& indexName) const;
+
+ NamespaceDetails* _details;
+ RecordStore* _indexRecordStore;
+ MMAP1DatabaseCatalogEntry* _db;
+
+ friend class MMAP1DatabaseCatalogEntry;
+ };
+}
diff --git a/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.cpp b/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.cpp
new file mode 100644
index 00000000000..7d3062dcca9
--- /dev/null
+++ b/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.cpp
@@ -0,0 +1,225 @@
+// namespace_details_rsv1_metadata.cpp
+
+/**
+ * Copyright (C) 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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.
+ */
+
+#include "mongo/db/ops/update.h"
+#include "mongo/db/structure/catalog/namespace_details_rsv1_metadata.h"
+
+namespace mongo {
+ NamespaceDetailsRSV1MetaData::NamespaceDetailsRSV1MetaData( const StringData& ns,
+ NamespaceDetails* details,
+ RecordStore* namespaceRecordStore )
+ : _ns( ns.toString() ),
+ _details( details ),
+ _namespaceRecordStore( namespaceRecordStore ) {
+ }
+
+ const DiskLoc& NamespaceDetailsRSV1MetaData::capExtent() const {
+ return _details->capExtent;
+ }
+
+ void NamespaceDetailsRSV1MetaData::setCapExtent( OperationContext* txn, const DiskLoc& loc ) {
+ *txn->recoveryUnit()->writing( &_details->capExtent ) = loc;
+ }
+
+ const DiskLoc& NamespaceDetailsRSV1MetaData::capFirstNewRecord() const {
+ return _details->capFirstNewRecord;
+ }
+
+ void NamespaceDetailsRSV1MetaData::setCapFirstNewRecord( OperationContext* txn,
+ const DiskLoc& loc ) {
+ *txn->recoveryUnit()->writing( &_details->capFirstNewRecord ) = loc;
+ }
+
+ bool NamespaceDetailsRSV1MetaData::capLooped() const {
+ return _details->capFirstNewRecord.isValid();
+ }
+
+ long long NamespaceDetailsRSV1MetaData::dataSize() const {
+ return _details->stats.datasize;
+ }
+ long long NamespaceDetailsRSV1MetaData::numRecords() const {
+ return _details->stats.nrecords;
+ }
+
+ void NamespaceDetailsRSV1MetaData::incrementStats( OperationContext* txn,
+ long long dataSizeIncrement,
+ long long numRecordsIncrement ) {
+ // durability todo : this could be a bit annoying / slow to record constantly
+ NamespaceDetails::Stats* s = txn->recoveryUnit()->writing( &_details->stats );
+ s->datasize += dataSizeIncrement;
+ s->nrecords += numRecordsIncrement;
+ }
+
+ void NamespaceDetailsRSV1MetaData::setStats( OperationContext* txn,
+ long long dataSize,
+ long long numRecords ) {
+ NamespaceDetails::Stats* s = txn->recoveryUnit()->writing( &_details->stats );
+ s->datasize = dataSize;
+ s->nrecords = numRecords;
+ }
+
+ const DiskLoc& NamespaceDetailsRSV1MetaData::deletedListEntry( int bucket ) const {
+ return _details->deletedList[ bucket ];
+ }
+
+ void NamespaceDetailsRSV1MetaData::setDeletedListEntry( OperationContext* txn,
+ int bucket,
+ const DiskLoc& loc ) {
+ *txn->recoveryUnit()->writing( &_details->deletedList[bucket] ) = loc;
+ }
+
+ void NamespaceDetailsRSV1MetaData::orphanDeletedList( OperationContext* txn ) {
+ for( int i = 0; i < Buckets; i++ ) {
+ setDeletedListEntry( txn, i, DiskLoc() );
+ }
+ }
+
+ const DiskLoc& NamespaceDetailsRSV1MetaData::firstExtent() const {
+ return _details->firstExtent;
+ }
+
+ void NamespaceDetailsRSV1MetaData::setFirstExtent( OperationContext* txn, const DiskLoc& loc ) {
+ *txn->recoveryUnit()->writing( &_details->firstExtent ) = loc;
+ }
+
+ const DiskLoc& NamespaceDetailsRSV1MetaData::lastExtent() const {
+ return _details->lastExtent;
+ }
+
+ void NamespaceDetailsRSV1MetaData::setLastExtent( OperationContext* txn, const DiskLoc& loc ) {
+ *txn->recoveryUnit()->writing( &_details->lastExtent ) = loc;
+ }
+
+ bool NamespaceDetailsRSV1MetaData::isCapped() const {
+ return _details->isCapped;
+ }
+
+ bool NamespaceDetailsRSV1MetaData::isUserFlagSet( int flag ) const {
+ return _details->userFlags & flag;
+ }
+
+ int NamespaceDetailsRSV1MetaData::userFlags() const {
+ return _details->userFlags;
+ }
+
+ bool NamespaceDetailsRSV1MetaData::setUserFlag( OperationContext* txn, int flag ) {
+ if ( ( _details->userFlags & flag ) == flag )
+ return false;
+
+ txn->recoveryUnit()->writingInt( _details->userFlags) |= flag;
+ _syncUserFlags( txn );
+ return true;
+ }
+
+ bool NamespaceDetailsRSV1MetaData::clearUserFlag( OperationContext* txn, int flag ) {
+ if ( ( _details->userFlags & flag ) == 0 )
+ return false;
+
+ txn->recoveryUnit()->writingInt(_details->userFlags) &= ~flag;
+ _syncUserFlags( txn );
+ return true;
+ }
+
+ bool NamespaceDetailsRSV1MetaData::replaceUserFlags( OperationContext* txn, int flags ) {
+ if ( _details->userFlags == flags )
+ return false;
+
+ txn->recoveryUnit()->writingInt(_details->userFlags) = flags;
+ _syncUserFlags( txn );
+ return true;
+ }
+
+ int NamespaceDetailsRSV1MetaData::lastExtentSize() const {
+ return _details->lastExtentSize;
+ }
+
+ void NamespaceDetailsRSV1MetaData::setLastExtentSize( OperationContext* txn, int newMax ) {
+ if ( _details->lastExtentSize == newMax )
+ return;
+ txn->recoveryUnit()->writingInt(_details->lastExtentSize) = newMax;
+ }
+
+ long long NamespaceDetailsRSV1MetaData::maxCappedDocs() const {
+ invariant( _details->isCapped );
+ if ( _details->maxDocsInCapped == 0x7fffffff )
+ return numeric_limits<long long>::max();
+ return _details->maxDocsInCapped;
+ }
+
+ double NamespaceDetailsRSV1MetaData::paddingFactor() const {
+ return _details->paddingFactor;
+ }
+
+ void NamespaceDetailsRSV1MetaData::setPaddingFactor( OperationContext* txn, double paddingFactor ) {
+ if ( paddingFactor == _details->paddingFactor )
+ return;
+
+ if ( _details->isCapped )
+ return;
+
+ *txn->recoveryUnit()->writing(&_details->paddingFactor) = paddingFactor;
+ }
+
+ void NamespaceDetailsRSV1MetaData::_syncUserFlags( OperationContext* txn ) {
+ if ( !_namespaceRecordStore )
+ return;
+
+ scoped_ptr<RecordIterator> iterator( _namespaceRecordStore->getIterator( DiskLoc(),
+ false,
+ CollectionScanParams::FORWARD ) );
+ while ( !iterator->isEOF() ) {
+ DiskLoc loc = iterator->getNext();
+ const Record* rec = iterator->recordFor( loc );
+
+ BSONObj oldEntry( rec->data() );
+ BSONElement e = oldEntry["name"];
+ if ( e.type() != String )
+ continue;
+
+ if ( e.String() != _ns )
+ continue;
+
+ BSONObj newEntry = applyUpdateOperators( oldEntry,
+ BSON( "$set" << BSON( "options.flags" << userFlags() ) ) );
+
+ StatusWith<DiskLoc> result = _namespaceRecordStore->updateRecord( txn,
+ loc,
+ newEntry.objdata(),
+ newEntry.objsize(),
+ -1,
+ NULL );
+ fassert( 17486, result.isOK() );
+ return;
+ }
+
+ fassertFailed( 17488 );
+ }
+
+}
diff --git a/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.h b/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.h
index 90015c86cb3..d4460de8bf2 100644
--- a/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.h
+++ b/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.h
@@ -30,120 +30,82 @@
#pragma once
+#include <string>
+
+#include "mongo/base/string_data.h"
#include "mongo/db/structure/catalog/namespace_details.h"
#include "mongo/db/structure/record_store_v1_base.h"
namespace mongo {
+ class RecordStore;
+
/*
* NOTE: NamespaceDetails will become a struct
* all dur, etc... will move here
*/
class NamespaceDetailsRSV1MetaData : public RecordStoreV1MetaData {
public:
- explicit NamespaceDetailsRSV1MetaData( NamespaceDetails* details ) {
- _details = details;
- }
+ explicit NamespaceDetailsRSV1MetaData( const StringData& ns,
+ NamespaceDetails* details,
+ RecordStore* namespaceRecordStore );
virtual ~NamespaceDetailsRSV1MetaData(){}
- virtual const DiskLoc& capExtent() const {
- return _details->capExtent();
- }
-
- virtual void setCapExtent( OperationContext* txn, const DiskLoc& loc ) {
- _details->setCapExtent( txn, loc );
- }
+ virtual const DiskLoc& capExtent() const;
+ virtual void setCapExtent( OperationContext* txn, const DiskLoc& loc );
- virtual const DiskLoc& capFirstNewRecord() const {
- return _details->capFirstNewRecord();
- }
+ virtual const DiskLoc& capFirstNewRecord() const;
+ virtual void setCapFirstNewRecord( OperationContext* txn, const DiskLoc& loc );
- virtual void setCapFirstNewRecord( OperationContext* txn, const DiskLoc& loc ) {
- _details->setCapFirstNewRecord( txn, loc );
- }
+ virtual bool capLooped() const;
- virtual long long dataSize() const {
- return _details->dataSize();
- }
- virtual long long numRecords() const {
- return _details->numRecords();
- }
+ virtual long long dataSize() const;
+ virtual long long numRecords() const;
virtual void incrementStats( OperationContext* txn,
long long dataSizeIncrement,
- long long numRecordsIncrement ) {
- _details->incrementStats( txn, dataSizeIncrement, numRecordsIncrement );
- }
+ long long numRecordsIncrement );
virtual void setStats( OperationContext* txn,
- long long dataSizeIncrement,
- long long numRecordsIncrement ) {
- _details->setStats( txn,
- dataSizeIncrement,
- numRecordsIncrement );
- }
-
- virtual const DiskLoc& deletedListEntry( int bucket ) const {
- return _details->deletedListEntry( bucket );
- }
+ long long dataSize,
+ long long numRecords );
+ virtual const DiskLoc& deletedListEntry( int bucket ) const;
virtual void setDeletedListEntry( OperationContext* txn,
int bucket,
- const DiskLoc& loc ) {
- _details->setDeletedListEntry( txn, bucket, loc );
- }
-
- virtual void orphanDeletedList(OperationContext* txn) {
- _details->orphanDeletedList( txn );
- }
+ const DiskLoc& loc );
+ virtual void orphanDeletedList(OperationContext* txn);
- virtual const DiskLoc& firstExtent() const {
- return _details->firstExtent();
- }
+ virtual const DiskLoc& firstExtent() const;
+ virtual void setFirstExtent( OperationContext* txn, const DiskLoc& loc );
- virtual void setFirstExtent( OperationContext* txn, const DiskLoc& loc ) {
- _details->setFirstExtent( txn, loc );
- }
+ virtual const DiskLoc& lastExtent() const;
+ virtual void setLastExtent( OperationContext* txn, const DiskLoc& loc );
- virtual const DiskLoc& lastExtent() const {
- return _details->lastExtent();
- }
+ virtual bool isCapped() const;
- virtual void setLastExtent( OperationContext* txn, const DiskLoc& loc ) {
- _details->setLastExtent( txn, loc );
- }
+ virtual bool isUserFlagSet( int flag ) const;
+ virtual int userFlags() const;
+ virtual bool setUserFlag( OperationContext* txn, int flag );
+ virtual bool clearUserFlag( OperationContext* txn, int flag );
+ virtual bool replaceUserFlags( OperationContext* txn, int flags );
- virtual bool isCapped() const {
- return _details->isCapped();
- }
+ virtual int lastExtentSize() const;
+ virtual void setLastExtentSize( OperationContext* txn, int newMax );
- virtual bool isUserFlagSet( int flag ) const {
- return _details->isUserFlagSet( flag );
- }
+ virtual long long maxCappedDocs() const;
- virtual int lastExtentSize() const {
- return _details->lastExtentSize();
- }
+ virtual double paddingFactor() const;
+ virtual void setPaddingFactor( OperationContext* txn, double paddingFactor );
- virtual void setLastExtentSize( OperationContext* txn, int newMax ) {
- _details->setLastExtentSize( txn, newMax );
- }
-
- virtual long long maxCappedDocs() const {
- return _details->maxCappedDocs();
- }
-
- virtual double paddingFactor() const {
- return _details->paddingFactor();
- }
+ private:
- virtual void setPaddingFactor( OperationContext* txn, double paddingFactor ) {
- _details->setPaddingFactor( txn, paddingFactor );
- }
+ void _syncUserFlags( OperationContext* txn );
- private:
+ std::string _ns;
NamespaceDetails* _details;
+ RecordStore* _namespaceRecordStore;
};
}
diff --git a/src/mongo/db/structure/catalog/namespace_index.cpp b/src/mongo/db/structure/catalog/namespace_index.cpp
index 3bb52d27d6a..04eb462c06b 100644
--- a/src/mongo/db/structure/catalog/namespace_index.cpp
+++ b/src/mongo/db/structure/catalog/namespace_index.cpp
@@ -94,8 +94,8 @@ namespace mongo {
}
}
- bool NamespaceIndex::exists() const {
- return !boost::filesystem::exists(path());
+ bool NamespaceIndex::pathExists() const {
+ return boost::filesystem::exists(path());
}
boost::filesystem::path NamespaceIndex::path() const {
diff --git a/src/mongo/db/structure/catalog/namespace_index.h b/src/mongo/db/structure/catalog/namespace_index.h
index f5871ba8e0c..8564887ff29 100644
--- a/src/mongo/db/structure/catalog/namespace_index.h
+++ b/src/mongo/db/structure/catalog/namespace_index.h
@@ -33,6 +33,7 @@
#include <list>
#include <string>
+#include "mongo/base/disallow_copying.h"
#include "mongo/db/diskloc.h"
#include "mongo/db/structure/catalog/hashtab.h"
#include "mongo/db/structure/catalog/namespace.h"
@@ -46,12 +47,13 @@ namespace mongo {
if you will: at least the core parts. (Additional info in system.* collections.)
*/
class NamespaceIndex {
+ MONGO_DISALLOW_COPYING(NamespaceIndex);
public:
NamespaceIndex(const std::string &dir, const std::string &database) :
_ht( 0 ), _dir( dir ), _database( database ) {}
- /* returns true if new db will be created if we init lazily */
- bool exists() const;
+ /* returns true if the file represented by this file exists on disk */
+ bool pathExists() const;
void init( OperationContext* txn ) {
if ( !_ht.get() )
@@ -84,7 +86,7 @@ namespace mongo {
void maybeMkdir() const;
DurableMappedFile _f;
- std::auto_ptr<HashTable<Namespace,NamespaceDetails> > _ht;
+ scoped_ptr<HashTable<Namespace,NamespaceDetails> > _ht;
std::string _dir;
std::string _database;
};
diff --git a/src/mongo/db/structure/record_store.h b/src/mongo/db/structure/record_store.h
index 1b006c464cd..020c76b6af7 100644
--- a/src/mongo/db/structure/record_store.h
+++ b/src/mongo/db/structure/record_store.h
@@ -31,11 +31,13 @@
#pragma once
#include "mongo/base/owned_pointer_vector.h"
+#include "mongo/bson/mutable/damage_vector.h"
#include "mongo/db/diskloc.h"
#include "mongo/db/exec/collection_scan_common.h"
namespace mongo {
+ class CappedDocumentDeleteCallback;
class Collection;
struct CompactOptions;
struct CompactStats;
@@ -65,6 +67,18 @@ namespace mongo {
};
/**
+ * @see RecordStore::updateRecord
+ */
+ class UpdateMoveNotifier {
+ public:
+ virtual ~UpdateMoveNotifier(){}
+ virtual Status recordStoreGoingToMove( OperationContext* txn,
+ const DiskLoc& oldLocation,
+ const char* oldBuffer,
+ size_t oldSize ) = 0;
+ };
+
+ /**
* A RecordIterator provides an interface for walking over a RecordStore.
* The details of navigating the collection's structure are below this interface.
*/
@@ -113,6 +127,10 @@ namespace mongo {
virtual long long numRecords() const = 0;
+ virtual bool isCapped() const = 0;
+
+ virtual void setCappedDeleteCallback(CappedDocumentDeleteCallback*) {invariant( false );}
+
/**
* @param extraInfo - optional more debug info
* @param level - optional, level of debug info to put in (higher is more)
@@ -135,6 +153,23 @@ namespace mongo {
int quotaMax ) = 0;
/**
+ * @param notifier - this is called if the document is moved
+ * it is to be called after the document has been written to new
+ * location, before deleted from old.
+ * @return Status or DiskLoc, DiskLoc might be different
+ */
+ virtual StatusWith<DiskLoc> updateRecord( OperationContext* txn,
+ const DiskLoc& oldLocation,
+ const char* data,
+ int len,
+ int quotaMax,
+ UpdateMoveNotifier* notifier ) = 0;
+
+ virtual Status updateWithDamages( OperationContext* txn,
+ const DiskLoc& loc,
+ const char* damangeSource,
+ const mutablebson::DamageVector& damages ) = 0;
+ /**
* returned iterator owned by caller
* canonical to get all would be
* getIterator( DiskLoc(), false, CollectionScanParams::FORWARD )
@@ -183,16 +218,26 @@ namespace mongo {
ValidateResults* results, BSONObjBuilder* output ) const = 0;
/**
+ * @param scaleSize - amount by which to scale size metrics
+ * appends any custom stats from the RecordStore or other unique stats
+ */
+ virtual void appendCustomStats( BSONObjBuilder* result, double scale ) const = 0;
+
+ /**
* Load all data into cache.
* What cache depends on implementation.
* @param output (optional) - where to put detailed stats
*/
virtual Status touch( OperationContext* txn, BSONObjBuilder* output ) const = 0;
- // TODO: this makes me sad, it shouldn't be in the interface
- // do not use this anymore
- virtual void increaseStorageSize( OperationContext* txn, int size, int quotaMax ) = 0;
-
+ /**
+ * @return Status::OK() if option hanlded
+ * InvalidOptions is option not supported
+ * other errors indicate option supported, but error setting
+ */
+ virtual Status setCustomOption( OperationContext* txn,
+ const BSONElement& option,
+ BSONObjBuilder* info = NULL ) = 0;
protected:
std::string _ns;
};
diff --git a/src/mongo/db/structure/record_store_v1_base.cpp b/src/mongo/db/structure/record_store_v1_base.cpp
index ff391111e9b..6fb81234071 100644
--- a/src/mongo/db/structure/record_store_v1_base.cpp
+++ b/src/mongo/db/structure/record_store_v1_base.cpp
@@ -231,6 +231,8 @@ namespace mongo {
_details->incrementStats( txn, r->netLength(), 1 );
+ _paddingFits( txn );
+
return loc;
}
@@ -244,6 +246,18 @@ namespace mongo {
"record has to be >= 4 bytes" );
}
+ StatusWith<DiskLoc> status = _insertRecord( txn, data, len, quotaMax );
+ if ( status.isOK() )
+ _paddingFits( txn );
+
+ return status;
+ }
+
+ StatusWith<DiskLoc> RecordStoreV1Base::_insertRecord( OperationContext* txn,
+ const char* data,
+ int len,
+ int quotaMax ) {
+
int lenWHdr = getRecordAllocationSize( len + Record::HeaderSize );
fassert( 17208, lenWHdr >= ( len + Record::HeaderSize ) );
@@ -265,6 +279,70 @@ namespace mongo {
return loc;
}
+ StatusWith<DiskLoc> RecordStoreV1Base::updateRecord( OperationContext* txn,
+ const DiskLoc& oldLocation,
+ const char* data,
+ int dataSize,
+ int quotaMax,
+ UpdateMoveNotifier* notifier ) {
+ Record* oldRecord = recordFor( oldLocation );
+ if ( oldRecord->netLength() >= dataSize ) {
+ // we fit
+ _paddingFits( txn );
+ memcpy( txn->recoveryUnit()->writingPtr( oldRecord->data(), dataSize ), data, dataSize );
+ return StatusWith<DiskLoc>( oldLocation );
+ }
+
+ if ( isCapped() )
+ return StatusWith<DiskLoc>( ErrorCodes::InternalError,
+ "failing update: objects in a capped ns cannot grow",
+ 10003 );
+
+ // we have to move
+
+ _paddingTooSmall( txn );
+
+ StatusWith<DiskLoc> newLocation = _insertRecord( txn, data, dataSize, quotaMax );
+ if ( !newLocation.isOK() )
+ return newLocation;
+
+ // insert worked, so we delete old record
+ if ( notifier ) {
+ Status moveStatus = notifier->recordStoreGoingToMove( txn,
+ oldLocation,
+ oldRecord->data(),
+ oldRecord->netLength() );
+ if ( !moveStatus.isOK() )
+ return StatusWith<DiskLoc>( moveStatus );
+ }
+
+ deleteRecord( txn, oldLocation );
+
+ return newLocation;
+ }
+
+
+ Status RecordStoreV1Base::updateWithDamages( OperationContext* txn,
+ const DiskLoc& loc,
+ const char* damangeSource,
+ const mutablebson::DamageVector& damages ) {
+ _paddingFits( txn );
+
+ Record* rec = recordFor( loc );
+ char* root = rec->data();
+
+ // All updates were in place. Apply them via durability and writing pointer.
+ mutablebson::DamageVector::const_iterator where = damages.begin();
+ const mutablebson::DamageVector::const_iterator end = damages.end();
+ for( ; where != end; ++where ) {
+ const char* sourcePtr = damangeSource + where->sourceOffset;
+ void* targetPtr = txn->recoveryUnit()->writingPtr(root + where->targetOffset, where->size);
+ std::memcpy(targetPtr, sourcePtr, where->size);
+ }
+
+ return Status::OK();
+ }
+
void RecordStoreV1Base::deleteRecord( OperationContext* txn, const DiskLoc& dl ) {
Record* todelete = recordFor( dl );
@@ -688,6 +766,18 @@ namespace mongo {
return Status::OK();
}
+ void RecordStoreV1Base::appendCustomStats( BSONObjBuilder* result, double scale ) const {
+ result->append( "lastExtentSize", _details->lastExtentSize() / scale );
+ result->append( "paddingFactor", _details->paddingFactor() );
+ result->append( "userFlags", _details->userFlags() );
+
+ if ( isCapped() ) {
+ result->appendBool( "capped", true );
+ result->appendNumber( "max", _details->maxCappedDocs() );
+ }
+ }
+
+
namespace {
struct touch_location {
const char* root;
@@ -815,4 +905,51 @@ namespace mongo {
return MaxBucket;
}
+ void RecordStoreV1Base::_paddingFits( OperationContext* txn ) {
+ MONGO_SOMETIMES(sometimes, 4) { // do this on a sampled basis to journal less
+ double x = max(1.0, _details->paddingFactor() - 0.001 );
+ _details->setPaddingFactor( txn, x );
+ }
+ }
+
+ void RecordStoreV1Base::_paddingTooSmall( OperationContext* txn ) {
+ MONGO_SOMETIMES(sometimes, 4) { // do this on a sampled basis to journal less
+ /* the more indexes we have, the higher the cost of a move. so we take that into
+ account herein. note on a move that insert() calls paddingFits(), thus
+ here for example with no inserts and nIndexes = 1 we have
+ .001*4-.001 or a 3:1 ratio to non moves -> 75% nonmoves. insert heavy
+ can pushes this down considerably. further tweaking will be a good idea but
+ this should be an adequate starting point.
+ */
+ double N = 4; // magic
+ double x = min(2.0,_details->paddingFactor() + (0.001 * N));
+ _details->setPaddingFactor( txn, x );
+ }
+ }
+
+ Status RecordStoreV1Base::setCustomOption( OperationContext* txn,
+ const BSONElement& option,
+ BSONObjBuilder* info ) {
+ if ( str::equals( "usePowerOf2Sizes", option.fieldName() ) ) {
+ bool oldPowerOf2 = _details->isUserFlagSet( Flag_UsePowerOf2Sizes );
+ bool newPowerOf2 = option.trueValue();
+
+ if ( oldPowerOf2 != newPowerOf2 ) {
+ // change userFlags
+ info->appendBool( "usePowerOf2Sizes_old", oldPowerOf2 );
+
+ if ( newPowerOf2 )
+ _details->setUserFlag( txn, Flag_UsePowerOf2Sizes );
+ else
+ _details->clearUserFlag( txn, Flag_UsePowerOf2Sizes );
+
+ info->appendBool( "usePowerOf2Sizes_new", newPowerOf2 );
+ }
+
+ return Status::OK();
+ }
+
+ return Status( ErrorCodes::InvalidOptions,
+ str::stream() << "no such option: " << option.fieldName() );
+ }
}
diff --git a/src/mongo/db/structure/record_store_v1_base.h b/src/mongo/db/structure/record_store_v1_base.h
index c83c94a4603..a3da188ba75 100644
--- a/src/mongo/db/structure/record_store_v1_base.h
+++ b/src/mongo/db/structure/record_store_v1_base.h
@@ -80,6 +80,10 @@ namespace mongo {
virtual bool isCapped() const = 0;
virtual bool isUserFlagSet( int flag ) const = 0;
+ virtual int userFlags() const = 0;
+ virtual bool setUserFlag( OperationContext* txn, int flag ) = 0;
+ virtual bool clearUserFlag( OperationContext* txn, int flag ) = 0;
+ virtual bool replaceUserFlags( OperationContext* txn, int flags ) = 0;
virtual int lastExtentSize() const = 0;
virtual void setLastExtentSize( OperationContext* txn, int newMax ) = 0;
@@ -138,6 +142,18 @@ namespace mongo {
const DocWriter* doc,
int quotaMax );
+ virtual StatusWith<DiskLoc> updateRecord( OperationContext* txn,
+ const DiskLoc& oldLocation,
+ const char* data,
+ int len,
+ int quotaMax,
+ UpdateMoveNotifier* notifier );
+
+ virtual Status updateWithDamages( OperationContext* txn,
+ const DiskLoc& loc,
+ const char* damangeSource,
+ const mutablebson::DamageVector& damages );
+
virtual RecordIterator* getIteratorForRepair() const;
void increaseStorageSize( OperationContext* txn, int size, int quotaMax );
@@ -147,6 +163,8 @@ namespace mongo {
ValidateAdaptor* adaptor,
ValidateResults* results, BSONObjBuilder* output ) const;
+ virtual void appendCustomStats( BSONObjBuilder* result, double scale ) const;
+
virtual Status touch( OperationContext* txn, BSONObjBuilder* output ) const;
const DeletedRecord* deletedRecordFor( const DiskLoc& loc ) const;
@@ -182,6 +200,9 @@ namespace mongo {
/* return which "deleted bucket" for this size object */
static int bucket(int size);
+ virtual Status setCustomOption( OperationContext* txn,
+ const BSONElement& option,
+ BSONObjBuilder* info = NULL );
protected:
virtual bool isCapped() const = 0;
@@ -218,6 +239,18 @@ namespace mongo {
*/
void _addRecordToRecListInExtent(OperationContext* txn, Record* r, DiskLoc loc);
+ void _paddingTooSmall( OperationContext* txn );
+ void _paddingFits( OperationContext* txn );
+
+ /**
+ * internal
+ * doesn't check inputs or change padding
+ */
+ StatusWith<DiskLoc> _insertRecord( OperationContext* txn,
+ const char* data,
+ int len,
+ int quotaMax );
+
scoped_ptr<RecordStoreV1MetaData> _details;
ExtentManager* _extentManager;
bool _isSystemIndexes;
diff --git a/src/mongo/db/structure/record_store_v1_capped.h b/src/mongo/db/structure/record_store_v1_capped.h
index 198a0d0275c..d3c7a1c1ee8 100644
--- a/src/mongo/db/structure/record_store_v1_capped.h
+++ b/src/mongo/db/structure/record_store_v1_capped.h
@@ -83,6 +83,10 @@ namespace mongo {
virtual bool isCapped() const { return true; }
+ virtual void setCappedDeleteCallback( CappedDocumentDeleteCallback* cb ) {
+ _deleteCallback = cb;
+ }
+
virtual StatusWith<DiskLoc> allocRecord( OperationContext* txn,
int lengthWithHeaders,
int quotaMax );
diff --git a/src/mongo/db/structure/record_store_v1_test_help.cpp b/src/mongo/db/structure/record_store_v1_test_help.cpp
index cc2662ef498..cebb035b87c 100644
--- a/src/mongo/db/structure/record_store_v1_test_help.cpp
+++ b/src/mongo/db/structure/record_store_v1_test_help.cpp
@@ -147,6 +147,30 @@ namespace mongo {
return _userFlags & flag;
}
+ bool DummyRecordStoreV1MetaData::setUserFlag( OperationContext* txn, int flag ) {
+ if ( ( _userFlags & flag ) == flag )
+ return false;
+
+ _userFlags |= flag;
+ return true;
+
+ }
+ bool DummyRecordStoreV1MetaData::clearUserFlag( OperationContext* txn, int flag ) {
+ if ( ( _userFlags & flag ) == 0 )
+ return false;
+
+ _userFlags &= ~flag;
+ return true;
+
+ }
+ bool DummyRecordStoreV1MetaData::replaceUserFlags( OperationContext* txn, int flags ) {
+ if ( _userFlags == flags )
+ return false;
+ _userFlags = flags;
+ return true;
+ }
+
+
int DummyRecordStoreV1MetaData::lastExtentSize() const {
return _lastExtentSize;
}
diff --git a/src/mongo/db/structure/record_store_v1_test_help.h b/src/mongo/db/structure/record_store_v1_test_help.h
index 2f33dbb5676..b4694f6acb9 100644
--- a/src/mongo/db/structure/record_store_v1_test_help.h
+++ b/src/mongo/db/structure/record_store_v1_test_help.h
@@ -74,6 +74,11 @@ namespace mongo {
virtual bool isCapped() const;
virtual bool isUserFlagSet( int flag ) const;
+ virtual int userFlags() const { return _userFlags; }
+ virtual bool setUserFlag( OperationContext* txn, int flag );
+ virtual bool clearUserFlag( OperationContext* txn, int flag );
+ virtual bool replaceUserFlags( OperationContext* txn, int flags );
+
virtual int lastExtentSize() const;
virtual void setLastExtentSize( OperationContext* txn, int newMax );