summaryrefslogtreecommitdiff
path: root/src/mongo/db/s/implicit_create_collection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/s/implicit_create_collection.cpp')
-rw-r--r--src/mongo/db/s/implicit_create_collection.cpp150
1 files changed, 150 insertions, 0 deletions
diff --git a/src/mongo/db/s/implicit_create_collection.cpp b/src/mongo/db/s/implicit_create_collection.cpp
new file mode 100644
index 00000000000..17f68349c30
--- /dev/null
+++ b/src/mongo/db/s/implicit_create_collection.cpp
@@ -0,0 +1,150 @@
+/**
+ * Copyright (C) 2018 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.
+ */
+
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kSharding
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/s/implicit_create_collection.h"
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "mongo/db/catalog/catalog_raii.h"
+#include "mongo/db/commands.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/operation_context.h"
+#include "mongo/db/service_context.h"
+#include "mongo/s/grid.h"
+#include "mongo/s/request_types/create_collection_gen.h"
+
+#include "mongo/stdx/condition_variable.h"
+#include "mongo/stdx/mutex.h"
+#include "mongo/util/scopeguard.h"
+
+namespace mongo {
+
+namespace {
+
+/**
+ * Responsible for explicitly creating collections in the sharding catalog. Also takes care of
+ * making sure that concurrent attempts to create a collection for the same ns will be
+ * synchronized and avoid duplicate work as much as possible.
+ */
+
+class CreateCollectionSerializer {
+public:
+ explicit CreateCollectionSerializer(NamespaceString ns) : _ns(std::move(ns)) {}
+
+ /**
+ * Initialize this collection so it will be officially tracked in a sharded environment
+ * by sending the command to the config server to create an entry for this collection in
+ * the sharding catalog.
+ */
+ void onCannotImplicitlyCreateCollection(OperationContext* opCtx) {
+ invariant(!opCtx->lockState()->isLocked());
+
+ {
+ stdx::unique_lock<stdx::mutex> lg(_mutex);
+ while (_isInProgress) {
+ opCtx->waitForConditionOrInterrupt(_cvIsInProgress, lg);
+ }
+
+ _isInProgress = true;
+ }
+
+ ON_BLOCK_EXIT([&] {
+ stdx::lock_guard<stdx::mutex> lg(_mutex);
+ _isInProgress = false;
+ _cvIsInProgress.notify_one();
+ });
+
+ {
+ AutoGetCollection autoColl(opCtx, _ns, MODE_IS);
+ if (autoColl.getCollection() != nullptr) {
+ // Collection already created, no more work needs to be done.
+ return;
+ }
+ }
+
+ ConfigsvrCreateCollection configCreateCmd;
+ configCreateCmd.setNs(_ns);
+
+ uassertStatusOK(
+ Grid::get(opCtx)->shardRegistry()->getConfigShard()->runCommandWithFixedRetryAttempts(
+ opCtx,
+ ReadPreferenceSetting{ReadPreference::PrimaryOnly},
+ "admin",
+ CommandHelpers::appendMajorityWriteConcern(configCreateCmd.toBSON()),
+ Shard::RetryPolicy::kIdempotent));
+ }
+
+private:
+ const NamespaceString _ns;
+
+ stdx::mutex _mutex;
+ stdx::condition_variable _cvIsInProgress;
+ bool _isInProgress = false;
+};
+
+class CreateCollectionSerializerMap {
+public:
+ std::shared_ptr<CreateCollectionSerializer> getForNs(const NamespaceString& ns) {
+ stdx::lock_guard<stdx::mutex> lg(_mutex);
+ auto iter = _inProgressMap.find(ns.ns());
+ if (iter == _inProgressMap.end()) {
+ std::tie(iter, std::ignore) =
+ _inProgressMap.emplace(ns.ns(), std::make_shared<CreateCollectionSerializer>(ns));
+ }
+
+ return iter->second;
+ }
+
+ void cleanupNs(const NamespaceString& ns) {
+ stdx::lock_guard<stdx::mutex> lg(_mutex);
+ _inProgressMap.erase(ns.ns());
+ }
+
+private:
+ stdx::mutex _mutex;
+ std::map<std::string, std::shared_ptr<CreateCollectionSerializer>> _inProgressMap;
+};
+
+const auto createCollectionSerializerMap =
+ ServiceContext::declareDecoration<CreateCollectionSerializerMap>();
+
+} // unnamed namespace
+
+void onCannotImplicitlyCreateCollection(OperationContext* opCtx, const NamespaceString& ns) {
+ auto& handlerMap = createCollectionSerializerMap(opCtx->getServiceContext());
+ handlerMap.getForNs(ns)->onCannotImplicitlyCreateCollection(opCtx);
+ handlerMap.cleanupNs(ns);
+}
+
+} // namespace mongo