summaryrefslogtreecommitdiff
path: root/src/mongo/db/catalog
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/catalog')
-rw-r--r--src/mongo/db/catalog/SConscript17
-rw-r--r--src/mongo/db/catalog/capped_utils.cpp5
-rw-r--r--src/mongo/db/catalog/catalog_raii.cpp121
-rw-r--r--src/mongo/db/catalog/catalog_raii.h217
-rw-r--r--src/mongo/db/catalog/coll_mod.cpp2
-rw-r--r--src/mongo/db/catalog/drop_collection.cpp2
-rw-r--r--src/mongo/db/catalog/drop_database.cpp5
-rw-r--r--src/mongo/db/catalog/drop_indexes.cpp4
-rw-r--r--src/mongo/db/catalog/rename_collection.cpp2
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"