summaryrefslogtreecommitdiff
path: root/src/mongo/db/index/index_build_interceptor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/index/index_build_interceptor.cpp')
-rw-r--r--src/mongo/db/index/index_build_interceptor.cpp146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/mongo/db/index/index_build_interceptor.cpp b/src/mongo/db/index/index_build_interceptor.cpp
new file mode 100644
index 00000000000..6af48b542c1
--- /dev/null
+++ b/src/mongo/db/index/index_build_interceptor.cpp
@@ -0,0 +1,146 @@
+/**
+ * Copyright (C) 2018-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * 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
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * 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 Server Side 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::kIndex
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/index/index_build_interceptor.h"
+
+#include "mongo/bson/bsonobj.h"
+#include "mongo/db/catalog_raii.h"
+#include "mongo/db/db_raii.h"
+#include "mongo/db/index/index_access_method.h"
+#include "mongo/db/multi_key_path_tracker.h"
+#include "mongo/db/operation_context.h"
+#include "mongo/db/s/operation_sharding_state.h"
+#include "mongo/util/log.h"
+#include "mongo/util/uuid.h"
+
+namespace mongo {
+
+namespace {
+const bool makeCollections = false;
+}
+
+NamespaceString IndexBuildInterceptor::makeTempSideWritesNs() {
+ return NamespaceString("local.system.sideWrites-" + UUID::gen().toString());
+}
+
+void IndexBuildInterceptor::ensureSideWritesCollectionExists(OperationContext* opCtx) {
+ if (!makeCollections) {
+ return;
+ }
+
+ // TODO SERVER-38027 Consider pushing this higher into the createIndexes command logic.
+ OperationShardingState::get(opCtx).setAllowImplicitCollectionCreation(BSONElement());
+
+ AutoGetOrCreateDb local(opCtx, "local", LockMode::MODE_X);
+ CollectionOptions options;
+ options.setNoIdIndex();
+ options.temp = true;
+
+ local.getDb()->createCollection(opCtx, _sideWritesNs.ns(), options);
+}
+
+void IndexBuildInterceptor::removeSideWritesCollection(OperationContext* opCtx) {
+ if (!makeCollections) {
+ return;
+ }
+
+ AutoGetDb local(opCtx, "local", LockMode::MODE_X);
+ fassert(50994, local.getDb()->dropCollectionEvenIfSystem(opCtx, _sideWritesNs, repl::OpTime()));
+}
+
+Status IndexBuildInterceptor::sideWrite(OperationContext* opCtx,
+ IndexAccessMethod* indexAccessMethod,
+ const BSONObj* obj,
+ RecordId loc,
+ Op op,
+ int64_t* numKeysOut) {
+ *numKeysOut = 0;
+ BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ BSONObjSet multikeyMetadataKeys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
+ MultikeyPaths multikeyPaths;
+
+ indexAccessMethod->getKeys(*obj,
+ IndexAccessMethod::GetKeysMode::kEnforceConstraints,
+ &keys,
+ &multikeyMetadataKeys,
+ &multikeyPaths);
+ // Maintain parity with IndexAccessMethods handling of key counting. Only include
+ // `multikeyMetadataKeys` when inserting.
+ *numKeysOut = keys.size() + (op == Op::kInsert ? multikeyMetadataKeys.size() : 0);
+
+ if (_multikeyPaths) {
+ MultikeyPathTracker::mergeMultikeyPaths(&_multikeyPaths.get(), multikeyPaths);
+ } else {
+ // `mergeMultikeyPaths` is sensitive to the two inputs having the same multikey
+ // "shape". Initialize `_multikeyPaths` with the right shape from the first result.
+ _multikeyPaths = multikeyPaths;
+ }
+
+ AutoGetCollection coll(opCtx, _sideWritesNs, LockMode::MODE_IX);
+ invariant(coll.getCollection());
+
+ std::vector<InsertStatement> toInsert;
+ for (const auto& key : keys) {
+ // Documents inserted into this table must be consumed in insert-order. Today, we can rely
+ // on storage engines to return documents in insert-order, but with clustered indexes,
+ // that may no longer be true.
+ //
+ // Additionally, these writes should be timestamped with the same timestamps that the
+ // other writes making up this operation are given. When index builds can cope with
+ // replication rollbacks, side table writes associated with a CUD operation should
+ // remain/rollback along with the corresponding oplog entry.
+ toInsert.emplace_back(BSON(
+ "op" << (op == Op::kInsert ? "i" : "d") << "key" << key << "recordId" << loc.repr()));
+ }
+
+ if (op == Op::kInsert) {
+ // Wildcard indexes write multikey path information, typically part of the catalog
+ // document, to the index itself. Multikey information is never deleted, so we only need
+ // to add this data on the insert path.
+ for (const auto& key : multikeyMetadataKeys) {
+ toInsert.emplace_back(BSON("op"
+ << "i"
+ << "key"
+ << key
+ << "recordId"
+ << static_cast<int64_t>(
+ RecordId::ReservedId::kWildcardMultikeyMetadataId)));
+ }
+ }
+
+ OpDebug* const opDebug = nullptr;
+ const bool fromMigrate = false;
+ return coll.getCollection()->insertDocuments(
+ opCtx, toInsert.begin(), toInsert.end(), opDebug, fromMigrate);
+}
+} // namespace mongo