diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2015-01-02 18:09:29 -0500 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2015-01-05 13:59:47 -0500 |
commit | 12d82c741061da23a442086465322352f157d094 (patch) | |
tree | e71fd0a9e98c94be93b075a7611f51fe1a1f304b /src/mongo | |
parent | a55a7b936ec2f4e935db4de4f4edb4696935a08d (diff) | |
download | mongo-12d82c741061da23a442086465322352f157d094.tar.gz |
SERVER-16591 Get rid of _collectionsLock in the database catalog
This lock is not needed anymore since any modifications to the set of
collections are done with the database X lock held.
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/concurrency/locker_noop.h | 175 | ||||
-rw-r--r-- | src/mongo/db/operation_context.h | 13 | ||||
-rw-r--r-- | src/mongo/db/operation_context_noop.h | 17 | ||||
-rw-r--r-- | src/mongo/db/storage/kv/kv_database_catalog_entry.cpp | 109 | ||||
-rw-r--r-- | src/mongo/db/storage/kv/kv_database_catalog_entry.h | 9 | ||||
-rw-r--r-- | src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp | 226 | ||||
-rw-r--r-- | src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h | 114 |
7 files changed, 406 insertions, 257 deletions
diff --git a/src/mongo/db/concurrency/locker_noop.h b/src/mongo/db/concurrency/locker_noop.h new file mode 100644 index 00000000000..44510c49f9d --- /dev/null +++ b/src/mongo/db/concurrency/locker_noop.h @@ -0,0 +1,175 @@ +/** + * 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/db/concurrency/locker.h" + +namespace mongo { + + /** + * Locker, which cannot be used to lock/unlock resources and just returns true for checks for + * whether a particular resource is locked. Do not use it for cases where actual locking + * behaviour is expected or locking is performed. + */ + class LockerNoop : public Locker { + public: + LockerNoop() { } + + virtual LockerId getId() const { invariant(false); } + + virtual LockResult lockGlobal(LockMode mode, unsigned timeoutMs) { + invariant(false); + } + + virtual LockResult lockGlobalBegin(LockMode mode) { + invariant(false); + } + + virtual LockResult lockGlobalComplete(unsigned timeoutMs) { + invariant(false); + } + + virtual void lockMMAPV1Flush() { + invariant(false); + } + + virtual bool unlockAll() { + invariant(false); + } + + virtual void downgradeGlobalXtoSForMMAPV1() { + invariant(false); + } + + virtual void beginWriteUnitOfWork() { + + } + + virtual void endWriteUnitOfWork() { + + } + + virtual bool inAWriteUnitOfWork() const { + invariant(false); + } + + virtual LockResult lock(ResourceId resId, + LockMode mode, + unsigned timeoutMs, + bool checkDeadlock) { + invariant(false); + } + + virtual void downgrade(ResourceId resId, LockMode newMode) { + invariant(false); + } + + virtual bool unlock(ResourceId resId) { + invariant(false); + } + + virtual LockMode getLockMode(ResourceId resId) const { + invariant(false); + } + + virtual bool isLockHeldForMode(ResourceId resId, LockMode mode) const { + return true; + } + + virtual bool isDbLockedForMode(const StringData& dbName, LockMode mode) const { + return true; + } + + virtual bool isCollectionLockedForMode(const StringData& ns, LockMode mode) const { + return true; + } + + virtual ResourceId getWaitingResource() const { + invariant(false); + } + + virtual void getLockerInfo(LockerInfo* lockerInfo) const { + invariant(false); + } + + virtual bool saveLockStateAndUnlock(LockSnapshot* stateOut) { + invariant(false); + } + + virtual void restoreLockState(const LockSnapshot& stateToRestore) { + invariant(false); + } + + virtual void dump() const { + invariant(false); + } + + virtual bool isW() const { + invariant(false); + } + + virtual bool isR() const { + invariant(false); + } + + virtual bool isLocked() const { + invariant(false); + } + + virtual bool isWriteLocked() const { + invariant(false); + } + + virtual bool isReadLocked() const { + invariant(false); + } + + virtual void assertEmpty() const { + invariant(false); + } + + virtual bool hasLockPending() const { + invariant(false); + } + + virtual void setIsBatchWriter(bool newValue) { + invariant(false); + } + + virtual bool isBatchWriter() const { + invariant(false); + } + + virtual void setLockPendingParallelWriter(bool newValue) { + invariant(false); + } + + }; + +} // namespace mongo diff --git a/src/mongo/db/operation_context.h b/src/mongo/db/operation_context.h index 59c190733f8..99bf8361ae6 100644 --- a/src/mongo/db/operation_context.h +++ b/src/mongo/db/operation_context.h @@ -148,17 +148,14 @@ namespace mongo { : _txn(txn), _ended(false) { - if ( _txn->lockState() ) { - _txn->lockState()->beginWriteUnitOfWork(); - } - + _txn->lockState()->beginWriteUnitOfWork(); _txn->recoveryUnit()->beginUnitOfWork(); } ~WriteUnitOfWork() { _txn->recoveryUnit()->endUnitOfWork(); - if (_txn->lockState() && !_ended) { + if (!_ended) { _txn->lockState()->endWriteUnitOfWork(); } } @@ -167,11 +164,9 @@ namespace mongo { invariant(!_ended); _txn->recoveryUnit()->commitUnitOfWork(); + _txn->lockState()->endWriteUnitOfWork(); - if (_txn->lockState()) { - _txn->lockState()->endWriteUnitOfWork(); - _ended = true; - } + _ended = true; } private: diff --git a/src/mongo/db/operation_context_noop.h b/src/mongo/db/operation_context_noop.h index 8d946850186..0ebdbceb386 100644 --- a/src/mongo/db/operation_context_noop.h +++ b/src/mongo/db/operation_context_noop.h @@ -29,6 +29,7 @@ #include "mongo/db/operation_context.h" #include "mongo/db/client.h" +#include "mongo/db/concurrency/locker_noop.h" #include "mongo/db/curop.h" #include "mongo/db/storage/recovery_unit_noop.h" @@ -36,12 +37,16 @@ namespace mongo { class OperationContextNoop : public OperationContext { public: - OperationContextNoop(RecoveryUnit* ru) { - _recoveryUnit.reset(ru); + OperationContextNoop(RecoveryUnit* ru) + : _recoveryUnit(ru), + _locker(new LockerNoop()) { + } - OperationContextNoop() { - _recoveryUnit.reset(new RecoveryUnitNoop()); + OperationContextNoop() + : _recoveryUnit(new RecoveryUnitNoop()), + _locker(new LockerNoop()) { + } virtual ~OperationContextNoop() { } @@ -69,8 +74,7 @@ namespace mongo { } virtual Locker* lockState() const { - // TODO: This should return an actual object if necessary for testing. - return NULL; + return _locker.get(); } virtual ProgressMeter* setMessage(const char * msg, @@ -103,6 +107,7 @@ namespace mongo { private: std::auto_ptr<RecoveryUnit> _recoveryUnit; + scoped_ptr<Locker> _locker; ProgressMeter _pm; }; diff --git a/src/mongo/db/storage/kv/kv_database_catalog_entry.cpp b/src/mongo/db/storage/kv/kv_database_catalog_entry.cpp index 51fde7efb9c..abde589c5a3 100644 --- a/src/mongo/db/storage/kv/kv_database_catalog_entry.cpp +++ b/src/mongo/db/storage/kv/kv_database_catalog_entry.cpp @@ -56,7 +56,6 @@ namespace mongo { _dce->_engine->getEngine()->dropIdent(_opCtx, _ident); } - boost::mutex::scoped_lock lk(_dce->_collectionsLock); const CollectionMap::iterator it = _dce->_collections.find(_collection); if (it != _dce->_collections.end()) { delete it->second; @@ -94,7 +93,6 @@ namespace mongo { } virtual void rollback() { - boost::mutex::scoped_lock lk(_dce->_collectionsLock); _dce->_collections[_collection] = _entry; } @@ -123,7 +121,6 @@ namespace mongo { } bool KVDatabaseCatalogEntry::isEmpty() const { - boost::mutex::scoped_lock lk( _collectionsLock ); return _collections.empty(); } @@ -134,7 +131,6 @@ namespace mongo { int64_t KVDatabaseCatalogEntry::sizeOnDisk( OperationContext* opCtx ) const { int64_t size = 0; - boost::mutex::scoped_lock lk( _collectionsLock ); for ( CollectionMap::const_iterator it = _collections.begin(); it != _collections.end(); ++it ) { const KVCollectionCatalogEntry* coll = it->second; if ( !coll ) @@ -166,26 +162,31 @@ namespace mongo { } void KVDatabaseCatalogEntry::getCollectionNamespaces( std::list<std::string>* out ) const { - boost::mutex::scoped_lock lk( _collectionsLock ); - for ( CollectionMap::const_iterator it = _collections.begin(); it != _collections.end(); ++it ) { + for (CollectionMap::const_iterator it = _collections.begin(); + it != _collections.end(); + ++it) { + out->push_back( it->first ); } } CollectionCatalogEntry* KVDatabaseCatalogEntry::getCollectionCatalogEntry( const StringData& ns ) const { - boost::mutex::scoped_lock lk( _collectionsLock ); + CollectionMap::const_iterator it = _collections.find( ns.toString() ); - if ( it == _collections.end() ) + if (it == _collections.end()) { return NULL; + } + return it->second; } RecordStore* KVDatabaseCatalogEntry::getRecordStore( const StringData& ns ) const { - boost::mutex::scoped_lock lk( _collectionsLock ); CollectionMap::const_iterator it = _collections.find( ns.toString() ); - if ( it == _collections.end() ) + if (it == _collections.end()) { return NULL; + } + return it->second->getRecordStore(); } @@ -193,19 +194,16 @@ namespace mongo { const StringData& ns, const CollectionOptions& options, bool allocateDefaultSpace ) { + + invariant(txn->lockState()->isDbLockedForMode(name(), MODE_X)); + if (ns.empty()) { return Status(ErrorCodes::BadValue, "Collection namespace cannot be empty"); } - // we assume there is a logical lock on the collection name above - - { - boost::mutex::scoped_lock lk( _collectionsLock ); - if (_collections.count(ns.toString())) { - invariant(_collections[ns.toString()]); - return Status( ErrorCodes::NamespaceExists, - "collection already exists" ); - } + if (_collections.count(ns.toString())) { + invariant(_collections[ns.toString()]); + return Status(ErrorCodes::NamespaceExists, "collection already exists"); } // need to create it @@ -221,7 +219,7 @@ namespace mongo { RecordStore* rs = _engine->getEngine()->getRecordStore( txn, ns, ident, options ); invariant( rs ); - boost::mutex::scoped_lock lk( _collectionsLock ); + txn->recoveryUnit()->registerChange(new AddCollectionChange(txn, this, ns, ident, true)); _collections[ns.toString()] = new KVCollectionCatalogEntry( _engine->getEngine(), _engine->getCatalog(), @@ -238,8 +236,8 @@ namespace mongo { RecordStore* rs = _engine->getEngine()->getRecordStore( opCtx, ns, ident, md.options ); invariant( rs ); - boost::mutex::scoped_lock lk( _collectionsLock ); invariant(!_collections.count(ns)); + // No change registration since this is only for committed collections _collections[ns] = new KVCollectionCatalogEntry( _engine->getEngine(), _engine->getCatalog(), @@ -252,19 +250,21 @@ namespace mongo { const StringData& fromNS, const StringData& toNS, bool stayTemp ) { + + invariant(txn->lockState()->isDbLockedForMode(name(), MODE_X)); + RecordStore* originalRS = NULL; - // Note: assuming that both fromNS and toNS (or whole db) are X-locked from above. - { - boost::mutex::scoped_lock lk( _collectionsLock ); - CollectionMap::const_iterator it = _collections.find( fromNS.toString() ); - if ( it == _collections.end() ) - return Status( ErrorCodes::NamespaceNotFound, "rename cannot find collection" ); - originalRS = it->second->getRecordStore(); - it = _collections.find( toNS.toString() ); - if ( it != _collections.end() ) - return Status( ErrorCodes::NamespaceExists, "for rename to already exists" ); + CollectionMap::const_iterator it = _collections.find( fromNS.toString() ); + if (it == _collections.end()) { + return Status(ErrorCodes::NamespaceNotFound, "rename cannot find collection"); + } + + originalRS = it->second->getRecordStore(); + it = _collections.find( toNS.toString() ); + if (it != _collections.end()) { + return Status(ErrorCodes::NamespaceExists, "for rename to already exists"); } const std::string identFrom = _engine->getCatalog()->getCollectionIdent( fromNS ); @@ -284,7 +284,6 @@ namespace mongo { BSONCollectionCatalogEntry::MetaData md = _engine->getCatalog()->getMetaData( txn, toNS ); RecordStore* rs = _engine->getEngine()->getRecordStore( txn, toNS, identTo, md.options ); - boost::mutex::scoped_lock lk( _collectionsLock ); const CollectionMap::iterator itFrom = _collections.find(fromNS.toString()); invariant(itFrom != _collections.end()); txn->recoveryUnit()->registerChange(new RemoveCollectionChange(txn, this, fromNS, identFrom, @@ -300,18 +299,18 @@ namespace mongo { return Status::OK(); } - Status KVDatabaseCatalogEntry::dropCollection( OperationContext* opCtx, - const StringData& ns ) { - KVCollectionCatalogEntry* entry; - { - boost::mutex::scoped_lock lk( _collectionsLock ); - CollectionMap::const_iterator it = _collections.find( ns.toString() ); - if ( it == _collections.end() ) - return Status( ErrorCodes::NamespaceNotFound, "cannnot find collection to drop" ); - entry = it->second; + Status KVDatabaseCatalogEntry::dropCollection(OperationContext* opCtx, const StringData& ns) { + invariant(opCtx->lockState()->isDbLockedForMode(name(), MODE_X)); + + CollectionMap::const_iterator it = _collections.find( ns.toString() ); + if (it == _collections.end()) { + return Status(ErrorCodes::NamespaceNotFound, "cannnot find collection to drop"); } - invariant( entry->getTotalIndexCount( opCtx ) == entry->getCompletedIndexCount( opCtx ) ); + KVCollectionCatalogEntry* const entry = it->second; + + invariant(entry->getTotalIndexCount(opCtx) == entry->getCompletedIndexCount(opCtx)); + { std::vector<std::string> indexNames; entry->getAllIndexes( opCtx, &indexNames ); @@ -319,24 +318,24 @@ namespace mongo { entry->removeIndex( opCtx, indexNames[i] ); } } - invariant( entry->getTotalIndexCount( opCtx ) == 0 ); - string ident = _engine->getCatalog()->getCollectionIdent( ns ); + invariant( entry->getTotalIndexCount( opCtx ) == 0 ); - boost::mutex::scoped_lock lk( _collectionsLock ); + const std::string ident = _engine->getCatalog()->getCollectionIdent(ns); - Status status = _engine->getCatalog()->dropCollection( opCtx, ns ); - if ( !status.isOK() ) + Status status = _engine->getCatalog()->dropCollection(opCtx, ns); + if (!status.isOK()) { return status; + } - - const CollectionMap::iterator it = _collections.find(ns.toString()); - invariant(it != _collections.end()); - - // This will lazily delete the KVCollectionCatalogEntry and notify the storageEngine to drop - // the collection only on WUOW::commit(). - opCtx->recoveryUnit()->registerChange(new RemoveCollectionChange(opCtx, this, ns, ident, - it->second, true)); + // This will lazily delete the KVCollectionCatalogEntry and notify the storageEngine to + // drop the collection only on WUOW::commit(). + opCtx->recoveryUnit()->registerChange(new RemoveCollectionChange(opCtx, + this, + ns, + ident, + it->second, + true)); _collections.erase( ns.toString() ); diff --git a/src/mongo/db/storage/kv/kv_database_catalog_entry.h b/src/mongo/db/storage/kv/kv_database_catalog_entry.h index fb522120491..fc5fb39adbd 100644 --- a/src/mongo/db/storage/kv/kv_database_catalog_entry.h +++ b/src/mongo/db/storage/kv/kv_database_catalog_entry.h @@ -33,9 +33,6 @@ #include <map> #include <string> -#include <boost/scoped_ptr.hpp> -#include <boost/thread/mutex.hpp> - #include "mongo/db/catalog/database_catalog_entry.h" namespace mongo { @@ -95,10 +92,10 @@ namespace mongo { class AddCollectionChange; class RemoveCollectionChange; - KVStorageEngine* _engine; // not owned here + typedef std::map<std::string, KVCollectionCatalogEntry*> CollectionMap; + - typedef std::map<std::string,KVCollectionCatalogEntry*> CollectionMap; + KVStorageEngine* const _engine; // not owned here CollectionMap _collections; - mutable boost::mutex _collectionsLock; }; } diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp index 1df0cccb9fa..d9a9e5da8db 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp @@ -35,7 +35,6 @@ #include <utility> #include "mongo/db/catalog/index_catalog_entry.h" -#include "mongo/db/client.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" @@ -49,7 +48,6 @@ #include "mongo/db/storage/mmap_v1/catalog/namespace_details.h" #include "mongo/db/storage/mmap_v1/catalog/namespace_details_collection_entry.h" #include "mongo/db/storage/mmap_v1/catalog/namespace_details_rsv1_metadata.h" -#include "mongo/db/storage/mmap_v1/dur.h" #include "mongo/db/storage/mmap_v1/data_file.h" #include "mongo/db/storage/mmap_v1/record_store_v1_capped.h" #include "mongo/db/storage/mmap_v1/record_store_v1_simple.h" @@ -57,39 +55,55 @@ #include "mongo/util/log.h" namespace mongo { +namespace { - namespace { - bool newCollectionsUsePowerOf2SizesFlag = true; // Unused, needed for server parameter. - - /** - * Declaration for the "newCollectionsUsePowerOf2Sizes" server parameter, - * which is now deprecated in 2.8. - * Note that: - * - setting to true performs a no-op. - * - setting to false will fail. - */ - class NewCollectionsUsePowerOf2SizesParameter : public ExportedServerParameter<bool> { - public: - NewCollectionsUsePowerOf2SizesParameter() : - ExportedServerParameter<bool>(ServerParameterSet::getGlobal(), - "newCollectionsUsePowerOf2Sizes", - &newCollectionsUsePowerOf2SizesFlag, - true, - true) {} - - virtual Status validate(const bool& potentialNewValue) { - if (!potentialNewValue) { - return Status(ErrorCodes::BadValue, - "newCollectionsUsePowerOf2Sizes cannot be set to false. " - "Use noPadding instead during createCollection."); - } + /** + * Declaration for the "newCollectionsUsePowerOf2Sizes" server parameter, which is now + * deprecated in 2.8. + * Note that: + * - setting to true performs a no-op. + * - setting to false will fail. + */ + class NewCollectionsUsePowerOf2SizesParameter : public ExportedServerParameter<bool> { + public: + NewCollectionsUsePowerOf2SizesParameter() : + ExportedServerParameter<bool>(ServerParameterSet::getGlobal(), + "newCollectionsUsePowerOf2Sizes", + &newCollectionsUsePowerOf2SizesFlag, + true, + true) { + + } - return Status::OK(); + virtual Status validate(const bool& potentialNewValue) { + if (!potentialNewValue) { + return Status(ErrorCodes::BadValue, + "newCollectionsUsePowerOf2Sizes cannot be set to false. " + "Use noPadding instead during createCollection."); } - } exportedNewCollectionsUsePowerOf2SizesParameter; + return Status::OK(); + } + + private: + // Unused, needed for server parameter. + bool newCollectionsUsePowerOf2SizesFlag; + + } exportedNewCollectionsUsePowerOf2SizesParameter; + + + 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); } +} // namespace + + /** * Registers the insertion of a new entry in the _collections cache with the RecoveryUnit, * allowing for rollback. @@ -124,7 +138,6 @@ namespace mongo { : _ns(ns.toString()), _catalogEntry(catalogEntry), _cachedEntry(cachedEntry) { } void rollback() { - boost::mutex::scoped_lock lk(_catalogEntry->_collectionsLock); _catalogEntry->_collections[_ns] = _cachedEntry; } @@ -166,7 +179,7 @@ namespace mongo { // _init. That is ok, since they can't have indexes on them anyway. if (!entry) { entry = new Entry(); - _insertInCache_inlock(txn, ns, entry); + _insertInCache(txn, ns, entry); // Add the indexes on this namespace to the list of namespaces to load. std::vector<std::string> indexNames; @@ -190,7 +203,7 @@ namespace mongo { catch(std::exception& e) { log() << "warning database " << path << " " << name << " could not be opened"; DBException* dbe = dynamic_cast<DBException*>(&e); - if ( dbe != 0 ) { + if (dbe) { log() << "DBException " << dbe->getCode() << ": " << e.what() << endl; } else { @@ -217,10 +230,10 @@ namespace mongo { void MMAPV1DatabaseCatalogEntry::_removeFromCache(RecoveryUnit* ru, const StringData& ns) { - boost::mutex::scoped_lock lk(_collectionsLock); CollectionMap::iterator i = _collections.find(ns.toString()); - if ( i == _collections.end() ) + if (i == _collections.end()) { return; + } // If there is an operation context, register a rollback to restore the cache entry if (ru) { @@ -416,12 +429,11 @@ namespace mongo { _getNamespaceRecordStore()->deleteRecord( txn, oldSpecLocation ); - boost::mutex::scoped_lock lk( _collectionsLock ); Entry*& entry = _collections[toNS.toString()]; invariant( entry == NULL ); txn->recoveryUnit()->registerChange(new EntryInsertion(toNS, this)); entry = new Entry(); - _insertInCache_inlock(txn, toNS, entry); + _insertInCache(txn, toNS, entry); return Status::OK(); } @@ -497,20 +509,11 @@ namespace mongo { _namespaceIndex.getCollectionNamespaces( tofill ); } - 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 ); - } - } + void MMAPV1DatabaseCatalogEntry::_ensureSystemCollection(OperationContext* txn, + const StringData& ns) { - void MMAPV1DatabaseCatalogEntry::_ensureSystemCollection_inlock( OperationContext* txn, - const StringData& ns ) { - NamespaceDetails* details = _namespaceIndex.details( ns ); - if ( details ) { + NamespaceDetails* details = _namespaceIndex.details(ns); + if (details) { return; } _namespaceIndex.add_ns( txn, ns, DiskLoc(), false ); @@ -543,8 +546,8 @@ namespace mongo { bool isSystemNamespacesGoingToBeNew = _namespaceIndex.details( nsn.toString() ) == NULL; bool isSystemIndexesGoingToBeNew = _namespaceIndex.details( nsi.toString() ) == NULL; - _ensureSystemCollection_inlock( txn, nsn.toString() ); - _ensureSystemCollection_inlock( txn, nsi.toString() ); + _ensureSystemCollection(txn, nsn.toString()); + _ensureSystemCollection(txn, nsi.toString()); if ( isSystemNamespacesGoingToBeNew ) { txn->recoveryUnit()->registerChange(new EntryInsertion(nsn.toString(), this)); @@ -597,7 +600,7 @@ namespace mongo { } if ( isSystemIndexesGoingToBeNew ) { - _addNamespaceToNamespaceCollection_inlock( txn, nsi.toString(), NULL ); + _addNamespaceToNamespaceCollection(txn, nsi.toString(), NULL); } if ( !nsEntry->catalogEntry ) @@ -647,14 +650,11 @@ namespace mongo { options.cappedMaxDocs; } - { - boost::mutex::scoped_lock lk( _collectionsLock ); - Entry*& entry = _collections[ns.toString()]; - invariant( !entry ); - txn->recoveryUnit()->registerChange(new EntryInsertion(ns, this)); - entry = new Entry(); - _insertInCache_inlock(txn, ns, entry); - } + Entry*& entry = _collections[ns.toString()]; + invariant( !entry ); + txn->recoveryUnit()->registerChange(new EntryInsertion(ns, this)); + entry = new Entry(); + _insertInCache(txn, ns, entry); if ( allocateDefaultSpace ) { RecordStoreV1Base* rs = _getRecordStore( ns ); @@ -698,56 +698,59 @@ namespace mongo { _addNamespaceToNamespaceCollection(txn, name, NULL); _namespaceIndex.add_ns(txn, name, DiskLoc(), false); - boost::mutex::scoped_lock lk( _collectionsLock ); Entry*& entry = _collections[name.toString()]; invariant( !entry ); txn->recoveryUnit()->registerChange(new EntryInsertion(name, this)); entry = new Entry(); - _insertInCache_inlock(txn, name, entry); + _insertInCache(txn, name, entry); } CollectionCatalogEntry* MMAPV1DatabaseCatalogEntry::getCollectionCatalogEntry( const StringData& ns ) const { - boost::mutex::scoped_lock lk( _collectionsLock ); + CollectionMap::const_iterator i = _collections.find( ns.toString() ); - if ( i == _collections.end() ) + if (i == _collections.end()) { return NULL; + } invariant( i->second->catalogEntry.get() ); return i->second->catalogEntry.get(); } - void MMAPV1DatabaseCatalogEntry::_insertInCache_inlock(OperationContext* txn, - const StringData& ns, - Entry* entry) { + void MMAPV1DatabaseCatalogEntry::_insertInCache(OperationContext* txn, + const StringData& ns, + Entry* entry) { + NamespaceDetails* details = _namespaceIndex.details(ns); invariant(details); - entry->catalogEntry.reset( new NamespaceDetailsCollectionCatalogEntry( ns, - details, - _getIndexRecordStore_inlock(), - this ) ); + entry->catalogEntry.reset( + new NamespaceDetailsCollectionCatalogEntry(ns, + details, + _getIndexRecordStore(), + this)); - NamespaceString nss( ns ); + auto_ptr<NamespaceDetailsRSV1MetaData> md( + new NamespaceDetailsRSV1MetaData(ns, + details, + _getNamespaceRecordStore())); - auto_ptr<NamespaceDetailsRSV1MetaData> md( new NamespaceDetailsRSV1MetaData( ns, - details, - _getNamespaceRecordStore_inlock() ) ); + const NamespaceString nss(ns); - if ( details->isCapped ) { - entry->recordStore.reset( new CappedRecordStoreV1( txn, - NULL, //TOD(ERH) this will blow up :) - ns, - md.release(), - &_extentManager, - nss.coll() == "system.indexes" ) ); + if (details->isCapped) { + entry->recordStore.reset(new CappedRecordStoreV1(txn, + NULL, + ns, + md.release(), + &_extentManager, + nss.coll() == "system.indexes")); } else { - entry->recordStore.reset( new SimpleRecordStoreV1( txn, - ns, - md.release(), - &_extentManager, - nss.coll() == "system.indexes" ) ); + entry->recordStore.reset(new SimpleRecordStoreV1(txn, + ns, + md.release(), + &_extentManager, + nss.coll() == "system.indexes")); } } @@ -756,10 +759,10 @@ namespace mongo { } RecordStoreV1Base* MMAPV1DatabaseCatalogEntry::_getRecordStore( const StringData& ns ) const { - boost::mutex::scoped_lock lk( _collectionsLock ); CollectionMap::const_iterator i = _collections.find( ns.toString() ); - if ( i == _collections.end() ) + if (i == _collections.end()) { return NULL; + } invariant( i->second->recordStore.get() ); return i->second->recordStore.get(); @@ -814,58 +817,49 @@ namespace mongo { } RecordStoreV1Base* MMAPV1DatabaseCatalogEntry::_getIndexRecordStore() { - boost::mutex::scoped_lock lk( _collectionsLock ); - return _getIndexRecordStore_inlock(); - } - - RecordStoreV1Base* MMAPV1DatabaseCatalogEntry::_getIndexRecordStore_inlock() { - NamespaceString nss( name(), "system.indexes" ); + const NamespaceString nss(name(), "system.indexes"); Entry* entry = _collections[nss.toString()]; invariant( entry ); + return entry->recordStore.get(); } RecordStoreV1Base* MMAPV1DatabaseCatalogEntry::_getNamespaceRecordStore() const { - boost::mutex::scoped_lock lk( _collectionsLock ); - return _getNamespaceRecordStore_inlock(); - } - - RecordStoreV1Base* MMAPV1DatabaseCatalogEntry::_getNamespaceRecordStore_inlock() const { - NamespaceString nss( name(), "system.namespaces" ); + const NamespaceString nss( name(), "system.namespaces" ); CollectionMap::const_iterator i = _collections.find( nss.toString() ); invariant( i != _collections.end() ); + return i->second->recordStore.get(); } - void MMAPV1DatabaseCatalogEntry::_addNamespaceToNamespaceCollection( OperationContext* txn, - const StringData& ns, - const BSONObj* options ) { - boost::mutex::scoped_lock lk( _collectionsLock ); - _addNamespaceToNamespaceCollection_inlock( txn, ns, options ); - } + void MMAPV1DatabaseCatalogEntry::_addNamespaceToNamespaceCollection(OperationContext* txn, + const StringData& ns, + const BSONObj* options) { - void MMAPV1DatabaseCatalogEntry::_addNamespaceToNamespaceCollection_inlock( OperationContext* txn, - const StringData& ns, - const BSONObj* options ) { - if ( nsToCollectionSubstring( ns ) == "system.namespaces" ) { + 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() ) + if (options && !options->isEmpty()) { b.append("options", *options); - BSONObj obj = b.done(); + } + + const BSONObj obj = b.done(); - RecordStoreV1Base* rs = _getNamespaceRecordStore_inlock(); + RecordStoreV1Base* rs = _getNamespaceRecordStore(); invariant( rs ); + StatusWith<RecordId> loc = rs->insertRecord( txn, obj.objdata(), obj.objsize(), false ); massertStatusOK( loc.getStatus() ); } - void MMAPV1DatabaseCatalogEntry::_removeNamespaceFromNamespaceCollection( OperationContext* txn, - const StringData& ns ) { + void MMAPV1DatabaseCatalogEntry::_removeNamespaceFromNamespaceCollection( + OperationContext* txn, + const StringData& ns ) { + if ( nsToCollectionSubstring( ns ) == "system.namespaces" ) { // system.namespaces holds all the others, so it is not explicitly listed in the catalog. return; diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h index 9eb1ef53b47..6a597e85dc3 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h @@ -1,32 +1,30 @@ -// mmap_v1_database_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. -*/ + * 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 @@ -63,16 +61,15 @@ namespace mongo { // these two seem the same and yet different // TODO(ERH): consolidate into one ideally - bool exists() const { return _namespaceIndex.pathExists(); } - bool isEmpty() const { return !_namespaceIndex.allocated(); } - bool hasUserData() const { + virtual bool exists() const { return _namespaceIndex.pathExists(); } + virtual bool isEmpty() const { return !_namespaceIndex.allocated(); } + virtual bool hasUserData() const { // The two collections which exist and can't be removed are: // system.indexes // system.namespaces return _collections.size() > 2; } - virtual int64_t sizeOnDisk( OperationContext* opCtx ) const; virtual bool isOlderThan24( OperationContext* opCtx ) const; @@ -98,7 +95,7 @@ namespace mongo { void getCollectionNamespaces( std::list<std::string>* tofill ) const; - /* + /** * will return NULL if ns does not exist */ CollectionCatalogEntry* getCollectionCatalogEntry( const StringData& ns ) const; @@ -115,11 +112,6 @@ namespace mongo { CollectionOptions getCollectionOptions( OperationContext* txn, const StringData& ns ) const; - - // - // Remaining methods are MMAPv1 specific - // - /** * Creates a CollectionCatalogEntry in the for an index rather than a collection. MMAPv1 * puts both indexes and collections into CCEs. A namespace named 'name' must not exist. @@ -127,17 +119,21 @@ namespace mongo { void createNamespaceForIndex(OperationContext* txn, const StringData& name); private: - class EntryInsertion; class EntryRemoval; friend class NamespaceDetailsCollectionCatalogEntry; - // The _collections map is a cache for efficiently looking up namespace information. - // Access to the cache is protected by the _collectionsLock mutex. - // Once initialized, the cache must remain consistent with the data in the memory-mapped - // database files through _removeFromCache and _insertInCache_inlock. These methods - // use the RecoveryUnit to ensure correct handling of rollback. + // The _collections map is a cache for efficiently looking up namespace information. Access + // to the cache is protected by holding the appropriate DB lock. Regular operations + // (insert/update/delete/query) hold intent locks on the database and they access the cache + // directly. Metadata operations, such as create db/collection, etc acquire exclusive lock + // on the database, which protects against concurrent readers of the cache. + // + // Once initialized, the cache must remain consistent with the data in the memory-mapped + // database files through _removeFromCache and _insertInCache. These methods use the + // RecoveryUnit to ensure correct handling of rollback. + struct Entry { scoped_ptr<CollectionCatalogEntry> catalogEntry; scoped_ptr<RecordStoreV1Base> recordStore; @@ -146,39 +142,29 @@ namespace mongo { typedef std::map<std::string, Entry*> CollectionMap; - RecordStoreV1Base* _getIndexRecordStore_inlock(); RecordStoreV1Base* _getIndexRecordStore(); - RecordStoreV1Base* _getNamespaceRecordStore_inlock() const; RecordStoreV1Base* _getNamespaceRecordStore() const; - RecordStoreV1Base* _getRecordStore( const StringData& ns ) const; - - void _addNamespaceToNamespaceCollection( OperationContext* txn, - const StringData& ns, - const BSONObj* options ); - - void _addNamespaceToNamespaceCollection_inlock( OperationContext* txn, - const StringData& ns, - const BSONObj* options ); + RecordStoreV1Base* _getRecordStore(const StringData& ns) const; + void _addNamespaceToNamespaceCollection(OperationContext* txn, + const StringData& ns, + const BSONObj* options); - void _removeNamespaceFromNamespaceCollection( OperationContext* txn, - const StringData& ns ); + void _removeNamespaceFromNamespaceCollection(OperationContext* txn, const StringData& ns); Status _renameSingleNamespace( OperationContext* txn, const StringData& fromNS, const StringData& toNS, bool stayTemp ); - void _ensureSystemCollection_inlock( OperationContext* txn, - const StringData& ns ); - void _init( OperationContext* txn ); + void _ensureSystemCollection(OperationContext* txn, const StringData& ns); - void _lazyInit( OperationContext* txn ); + void _init( OperationContext* txn ); /** * Populate the _collections cache. */ - void _insertInCache_inlock(OperationContext* opCtx, const StringData& ns, Entry* entry); + void _insertInCache(OperationContext* opCtx, const StringData& ns, Entry* entry); /** * Drop cached information for specified namespace. If a RecoveryUnit is specified, @@ -187,12 +173,10 @@ namespace mongo { void _removeFromCache(RecoveryUnit* ru, const StringData& ns); - std::string _path; + const std::string _path; MmapV1ExtentManager _extentManager; NamespaceIndex _namespaceIndex; - - mutable boost::mutex _collectionsLock; CollectionMap _collections; }; } |