diff options
Diffstat (limited to 'src/mongo/db/catalog')
-rw-r--r-- | src/mongo/db/catalog/SConscript | 17 | ||||
-rw-r--r-- | src/mongo/db/catalog/capped_utils.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/catalog/catalog_raii.cpp | 121 | ||||
-rw-r--r-- | src/mongo/db/catalog/catalog_raii.h | 217 | ||||
-rw-r--r-- | src/mongo/db/catalog/coll_mod.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/catalog/drop_collection.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/catalog/drop_database.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/catalog/drop_indexes.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/catalog/rename_collection.cpp | 2 |
9 files changed, 358 insertions, 17 deletions
diff --git a/src/mongo/db/catalog/SConscript b/src/mongo/db/catalog/SConscript index 8a92c492aa6..8ea1877cf19 100644 --- a/src/mongo/db/catalog/SConscript +++ b/src/mongo/db/catalog/SConscript @@ -119,6 +119,21 @@ env.Library( ], ) +env.Library( + target='catalog_raii', + source=[ + 'catalog_raii.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/db/catalog/database_holder', + '$BUILD_DIR/mongo/db/concurrency/lock_manager', + '$BUILD_DIR/mongo/db/views/views', + 'collection', + 'database', + 'uuid_catalog', + ], +) + env.CppUnitTest( target='database_test', source=[ @@ -205,7 +220,7 @@ env.CppUnitTest( ) env.Library( - target='catalog', + target='catalog_impl', source=[ "collection_compact.cpp", "collection_impl.cpp", diff --git a/src/mongo/db/catalog/capped_utils.cpp b/src/mongo/db/catalog/capped_utils.cpp index cc5c82ac2fc..d84b7bbc7ac 100644 --- a/src/mongo/db/catalog/capped_utils.cpp +++ b/src/mongo/db/catalog/capped_utils.cpp @@ -34,10 +34,9 @@ #include "mongo/base/error_codes.h" #include "mongo/db/background.h" -#include "mongo/db/catalog/collection.h" +#include "mongo/db/catalog/catalog_raii.h" #include "mongo/db/catalog/collection_catalog_entry.h" #include "mongo/db/catalog/create_collection.h" -#include "mongo/db/catalog/database.h" #include "mongo/db/catalog/document_validation.h" #include "mongo/db/catalog/drop_collection.h" #include "mongo/db/catalog/index_catalog.h" @@ -45,13 +44,11 @@ #include "mongo/db/client.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/curop.h" -#include "mongo/db/db_raii.h" #include "mongo/db/index_builder.h" #include "mongo/db/query/internal_plans.h" #include "mongo/db/query/plan_yield_policy.h" #include "mongo/db/repl/replication_coordinator_global.h" #include "mongo/db/service_context.h" -#include "mongo/db/views/view.h" #include "mongo/util/scopeguard.h" mongo::Status mongo::emptyCapped(OperationContext* opCtx, const NamespaceString& collectionName) { diff --git a/src/mongo/db/catalog/catalog_raii.cpp b/src/mongo/db/catalog/catalog_raii.cpp new file mode 100644 index 00000000000..ef61f3db568 --- /dev/null +++ b/src/mongo/db/catalog/catalog_raii.cpp @@ -0,0 +1,121 @@ +/** + * Copyright (C) 2017 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/platform/basic.h" + +#include "mongo/db/catalog/catalog_raii.h" + +#include "mongo/db/catalog/database_holder.h" +#include "mongo/db/catalog/uuid_catalog.h" +#include "mongo/util/fail_point_service.h" + +namespace mongo { +namespace { + +MONGO_FP_DECLARE(setAutoGetCollectionWait); + +} // namespace + +AutoGetDb::AutoGetDb(OperationContext* opCtx, StringData ns, LockMode mode) + : _dbLock(opCtx, ns, mode), _db(dbHolder().get(opCtx, ns)) {} + +AutoGetDb::AutoGetDb(OperationContext* opCtx, StringData ns, Lock::DBLock lock) + : _dbLock(std::move(lock)), _db(dbHolder().get(opCtx, ns)) {} + +AutoGetCollection::AutoGetCollection(OperationContext* opCtx, + const NamespaceString& nss, + const UUID& uuid, + LockMode modeAll) + : _viewMode(ViewMode::kViewsForbidden), + _autoDb(opCtx, nss.db(), Lock::DBLock(opCtx, nss.db(), modeAll)), + _collLock(opCtx->lockState(), nss.ns(), modeAll), + _coll(UUIDCatalog::get(opCtx).lookupCollectionByUUID(uuid)) { + // Wait for a configured amount of time after acquiring locks if the failpoint is enabled + MONGO_FAIL_POINT_BLOCK(setAutoGetCollectionWait, customWait) { + const BSONObj& data = customWait.getData(); + sleepFor(Milliseconds(data["waitForMillis"].numberInt())); + } +} + +AutoGetCollection::AutoGetCollection(OperationContext* opCtx, + const NamespaceString& nss, + LockMode modeColl, + ViewMode viewMode, + Lock::DBLock lock) + : _viewMode(viewMode), + _autoDb(opCtx, nss.db(), std::move(lock)), + _collLock(opCtx->lockState(), nss.ns(), modeColl), + _coll(_autoDb.getDb() ? _autoDb.getDb()->getCollection(opCtx, nss) : nullptr) { + Database* const db = _autoDb.getDb(); + + // If the database exists, but not the collection, check for views + if (_viewMode == ViewMode::kViewsForbidden && db && !_coll && + db->getViewCatalog()->lookup(opCtx, nss.ns())) { + uasserted(ErrorCodes::CommandNotSupportedOnView, + str::stream() << "Namespace " << nss.ns() << " is a view, not a collection"); + } + + // Wait for a configured amount of time after acquiring locks if the failpoint is enabled + MONGO_FAIL_POINT_BLOCK(setAutoGetCollectionWait, customWait) { + const BSONObj& data = customWait.getData(); + sleepFor(Milliseconds(data["waitForMillis"].numberInt())); + } +} + +AutoGetCollection::AutoGetCollection(OperationContext* opCtx, + const NamespaceString& nss, + LockMode modeDB, + LockMode modeColl, + ViewMode viewMode) + : AutoGetCollection(opCtx, nss, modeColl, viewMode, Lock::DBLock(opCtx, nss.db(), modeDB)) {} + +AutoGetCollectionOrView::AutoGetCollectionOrView(OperationContext* opCtx, + const NamespaceString& nss, + LockMode modeAll) + : _autoColl(opCtx, nss, modeAll, modeAll, AutoGetCollection::ViewMode::kViewsPermitted), + _view(_autoColl.getDb() && !_autoColl.getCollection() + ? _autoColl.getDb()->getViewCatalog()->lookup(opCtx, nss.ns()) + : nullptr) {} + +AutoGetOrCreateDb::AutoGetOrCreateDb(OperationContext* opCtx, StringData ns, LockMode mode) + : _dbLock(opCtx, ns, mode), _db(dbHolder().get(opCtx, ns)) { + invariant(mode == MODE_IX || mode == MODE_X); + _justCreated = false; + + // If the database didn't exist, relock in MODE_X + if (_db == NULL) { + if (mode != MODE_X) { + _dbLock.relockWithMode(MODE_X); + } + + _db = dbHolder().openDb(opCtx, ns); + _justCreated = true; + } +} + +} // namespace mongo diff --git a/src/mongo/db/catalog/catalog_raii.h b/src/mongo/db/catalog/catalog_raii.h new file mode 100644 index 00000000000..8ff5401dc18 --- /dev/null +++ b/src/mongo/db/catalog/catalog_raii.h @@ -0,0 +1,217 @@ +/** + * Copyright (C) 2017 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/catalog/collection.h" +#include "mongo/db/catalog/database.h" +#include "mongo/db/concurrency/d_concurrency.h" +#include "mongo/db/namespace_string.h" +#include "mongo/db/operation_context.h" +#include "mongo/db/views/view.h" + +namespace mongo { + +/** + * RAII-style class, which acquires a lock on the specified database in the requested mode and + * obtains a reference to the database. Used as a shortcut for calls to dbHolder().get(). + * + * Use this when you want to do a database-level operation, like read a list of all collections, or + * drop a collection. + * + * It is guaranteed that the lock will be released when this object goes out of scope, therefore + * the database reference returned by this class should not be retained. + */ +class AutoGetDb { + MONGO_DISALLOW_COPYING(AutoGetDb); + +public: + AutoGetDb(OperationContext* opCtx, StringData ns, LockMode mode); + AutoGetDb(OperationContext* opCtx, StringData ns, Lock::DBLock lock); + + Database* getDb() const { + return _db; + } + +private: + const Lock::DBLock _dbLock; + Database* const _db; +}; + +/** + * RAII-style class, which acquires a locks on the specified database and collection in the + * requested mode and obtains references to both. + * + * Use this when you want to access something at the collection level, but do not want to do any of + * the tasks associated with the 'ForRead' variants below. For example, you can use this to access a + * Collection's CursorManager, or to remove a document. + * + * It is guaranteed that locks will be released when this object goes out of scope, therefore + * the database and the collection references returned by this class should not be retained. + */ +class AutoGetCollection { + MONGO_DISALLOW_COPYING(AutoGetCollection); + +public: + enum class ViewMode { kViewsPermitted, kViewsForbidden }; + + AutoGetCollection(OperationContext* opCtx, const NamespaceString& nss, LockMode modeAll) + : AutoGetCollection(opCtx, nss, modeAll, modeAll, ViewMode::kViewsForbidden) {} + + AutoGetCollection(OperationContext* opCtx, + const NamespaceString& nss, + LockMode modeDB, + LockMode modeColl) + : AutoGetCollection(opCtx, nss, modeDB, modeColl, ViewMode::kViewsForbidden) {} + + AutoGetCollection(OperationContext* opCtx, + const NamespaceString& nss, + const UUID& uuid, + LockMode modeAll); + + AutoGetCollection(OperationContext* opCtx, + const NamespaceString& nss, + LockMode modeColl, + ViewMode viewMode, + Lock::DBLock lock); + + /** + * This constructor is intended for internal use and should not be used outside this file. + * AutoGetCollectionForReadCommand and AutoGetCollectionOrViewForReadCommand use 'viewMode' to + * determine whether or not it is permissible to obtain a handle on a view namespace. Use + * another constructor or another 'AutoGet' class instead. + */ + AutoGetCollection(OperationContext* opCtx, + const NamespaceString& nss, + LockMode modeDB, + LockMode modeColl, + ViewMode viewMode); + + /** + * Returns nullptr if the database didn't exist. + */ + Database* getDb() const { + return _autoDb.getDb(); + } + + /** + * Returns nullptr if the collection didn't exist. + */ + Collection* getCollection() const { + return _coll; + } + +private: + const ViewMode _viewMode; + const AutoGetDb _autoDb; + const Lock::CollectionLock _collLock; + + Collection* const _coll; +}; + +/** + * RAII-style class which acquires the appropriate hierarchy of locks for a collection or + * view. The pointer to a view definition is nullptr if it does not exist. + * + * Use this when you have not yet determined if the namespace is a view or a collection. + * For example, you can use this to access a namespace's CursorManager. + * + * It is guaranteed that locks will be released when this object goes out of scope, therefore + * the view returned by this class should not be retained. + */ +class AutoGetCollectionOrView { + MONGO_DISALLOW_COPYING(AutoGetCollectionOrView); + +public: + AutoGetCollectionOrView(OperationContext* opCtx, const NamespaceString& nss, LockMode modeAll); + + /** + * Returns nullptr if the database didn't exist. + */ + Database* getDb() const { + return _autoColl.getDb(); + } + + /** + * Returns nullptr if the collection didn't exist. + */ + Collection* getCollection() const { + return _autoColl.getCollection(); + } + + /** + * Returns nullptr if the view didn't exist. + */ + ViewDefinition* getView() const { + return _view.get(); + } + +private: + const AutoGetCollection _autoColl; + std::shared_ptr<ViewDefinition> _view; +}; + +/** + * RAII-style class, which acquires a lock on the specified database in the requested mode and + * obtains a reference to the database, creating it was non-existing. Used as a shortcut for + * calls to dbHolder().openDb(), taking care of locking details. The requested mode must be + * MODE_IX or MODE_X. If the database needs to be created, the lock will automatically be + * reacquired as MODE_X. + * + * Use this when you are about to perform a write, and want to create the database if it doesn't + * already exist. + * + * It is guaranteed that locks will be released when this object goes out of scope, therefore + * the database reference returned by this class should not be retained. + */ +class AutoGetOrCreateDb { + MONGO_DISALLOW_COPYING(AutoGetOrCreateDb); + +public: + AutoGetOrCreateDb(OperationContext* opCtx, StringData ns, LockMode mode); + + Database* getDb() const { + return _db; + } + + bool justCreated() const { + return _justCreated; + } + + Lock::DBLock& lock() { + return _dbLock; + } + +private: + Lock::DBLock _dbLock; // not const, as we may need to relock for implicit create + Database* _db; + bool _justCreated; +}; + +} // namespace mongo diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp index baf7e98ed49..cd1022f9f93 100644 --- a/src/mongo/db/catalog/coll_mod.cpp +++ b/src/mongo/db/catalog/coll_mod.cpp @@ -37,10 +37,8 @@ #include "mongo/bson/simple_bsonelement_comparator.h" #include "mongo/db/background.h" -#include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/collection_catalog_entry.h" #include "mongo/db/catalog/collection_options.h" -#include "mongo/db/catalog/database.h" #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/client.h" #include "mongo/db/commands/feature_compatibility_version_command_parser.h" diff --git a/src/mongo/db/catalog/drop_collection.cpp b/src/mongo/db/catalog/drop_collection.cpp index 46cd73e0766..cd9e6ad4106 100644 --- a/src/mongo/db/catalog/drop_collection.cpp +++ b/src/mongo/db/catalog/drop_collection.cpp @@ -33,8 +33,6 @@ #include "mongo/db/catalog/drop_collection.h" #include "mongo/db/background.h" -#include "mongo/db/catalog/collection.h" -#include "mongo/db/catalog/database.h" #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/client.h" #include "mongo/db/concurrency/write_conflict_exception.h" diff --git a/src/mongo/db/catalog/drop_database.cpp b/src/mongo/db/catalog/drop_database.cpp index 9fe58b7230f..59a919ad7ef 100644 --- a/src/mongo/db/catalog/drop_database.cpp +++ b/src/mongo/db/catalog/drop_database.cpp @@ -35,12 +35,10 @@ #include <algorithm> #include "mongo/db/background.h" -#include "mongo/db/catalog/database.h" +#include "mongo/db/catalog/catalog_raii.h" #include "mongo/db/client.h" -#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/curop.h" -#include "mongo/db/db_raii.h" #include "mongo/db/op_observer.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/service_context.h" @@ -49,7 +47,6 @@ #include "mongo/util/scopeguard.h" namespace mongo { - namespace { // This is used to wait for the collection drops to replicate to a majority of the replica set. diff --git a/src/mongo/db/catalog/drop_indexes.cpp b/src/mongo/db/catalog/drop_indexes.cpp index 12aae53b281..29b9ec80cd5 100644 --- a/src/mongo/db/catalog/drop_indexes.cpp +++ b/src/mongo/db/catalog/drop_indexes.cpp @@ -33,8 +33,6 @@ #include "mongo/db/catalog/drop_indexes.h" #include "mongo/db/background.h" -#include "mongo/db/catalog/collection.h" -#include "mongo/db/catalog/database.h" #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/client.h" #include "mongo/db/concurrency/write_conflict_exception.h" @@ -48,6 +46,7 @@ namespace mongo { namespace { + Status wrappedRun(OperationContext* opCtx, Collection* collection, const BSONObj& jsobj, @@ -142,6 +141,7 @@ Status wrappedRun(OperationContext* opCtx, return Status(ErrorCodes::IndexNotFound, "invalid index name spec"); } + } // namespace Status dropIndexes(OperationContext* opCtx, diff --git a/src/mongo/db/catalog/rename_collection.cpp b/src/mongo/db/catalog/rename_collection.cpp index 8b32346d169..21553d58e55 100644 --- a/src/mongo/db/catalog/rename_collection.cpp +++ b/src/mongo/db/catalog/rename_collection.cpp @@ -33,9 +33,7 @@ #include "mongo/db/catalog/rename_collection.h" #include "mongo/db/background.h" -#include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/collection_catalog_entry.h" -#include "mongo/db/catalog/database.h" #include "mongo/db/catalog/database_holder.h" #include "mongo/db/catalog/document_validation.h" #include "mongo/db/catalog/drop_collection.h" |