summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zhang <jason.zhang@mongodb.com>2022-10-13 22:33:47 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-10-13 23:25:53 +0000
commitbe1848a26189a8c773cf00a4ce6ff053b8dc0cac (patch)
treee34ef920ee3d62589360d50c2a17c835158d1d30
parent69f11e092a68749b684bad807bbd6ef2aa097baa (diff)
downloadmongo-be1848a26189a8c773cf00a4ce6ff053b8dc0cac.tar.gz
SERVER-69708 Detect a write without a shard key or _id
-rw-r--r--src/mongo/s/SConscript2
-rw-r--r--src/mongo/s/write_ops/SConscript10
-rw-r--r--src/mongo/s/write_ops/write_without_shard_key_util.cpp55
-rw-r--r--src/mongo/s/write_ops/write_without_shard_key_util.h48
-rw-r--r--src/mongo/s/write_ops/write_without_shard_key_util_test.cpp95
5 files changed, 210 insertions, 0 deletions
diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript
index 0a53d677ade..f3cb743a434 100644
--- a/src/mongo/s/SConscript
+++ b/src/mongo/s/SConscript
@@ -642,6 +642,7 @@ env.CppUnitTest(
'write_ops/batched_command_request_test.cpp',
'write_ops/batched_command_response_test.cpp',
'write_ops/write_op_test.cpp',
+ 'write_ops/write_without_shard_key_util_test.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/auth/authmocks',
@@ -656,6 +657,7 @@ env.CppUnitTest(
'$BUILD_DIR/mongo/s/commands/cluster_commands_common',
'$BUILD_DIR/mongo/s/write_ops/batch_write_types',
'$BUILD_DIR/mongo/s/write_ops/cluster_write_ops',
+ '$BUILD_DIR/mongo/s/write_ops/write_without_shard_key_util',
'$BUILD_DIR/mongo/util/net/network',
'$BUILD_DIR/mongo/util/periodic_runner_factory',
'coreshard',
diff --git a/src/mongo/s/write_ops/SConscript b/src/mongo/s/write_ops/SConscript
index b591f592405..68aab96d8d2 100644
--- a/src/mongo/s/write_ops/SConscript
+++ b/src/mongo/s/write_ops/SConscript
@@ -25,6 +25,16 @@ env.Library(
)
env.Library(
+ target='write_without_shard_key_util',
+ source=[
+ 'write_without_shard_key_util.cpp',
+ ],
+ LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/s/grid',
+ ],
+)
+
+env.Library(
target='cluster_write_ops',
source=[
'batch_write_exec.cpp',
diff --git a/src/mongo/s/write_ops/write_without_shard_key_util.cpp b/src/mongo/s/write_ops/write_without_shard_key_util.cpp
new file mode 100644
index 00000000000..820a813c399
--- /dev/null
+++ b/src/mongo/s/write_ops/write_without_shard_key_util.cpp
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2022-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.
+ */
+
+#include "mongo/bson/bsonobj.h"
+#include "mongo/logv2/log.h"
+#include "mongo/s/catalog_cache.h"
+#include "mongo/s/grid.h"
+
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kSharding
+
+namespace mongo {
+namespace write_without_shard_key {
+
+bool canTargetQueryByShardKeyOrId(OperationContext* opCtx,
+ NamespaceString ns,
+ const BSONObj& query) {
+ auto cm =
+ uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, ns));
+ auto shardKey =
+ uassertStatusOK(cm.getShardKeyPattern().extractShardKeyFromQuery(opCtx, ns, query));
+
+ if (shardKey.isEmpty() && !query.hasField("_id")) {
+ LOGV2(6970800, "A write without shard key or _id detected");
+ return false;
+ }
+ return true;
+}
+} // namespace write_without_shard_key
+} // namespace mongo
diff --git a/src/mongo/s/write_ops/write_without_shard_key_util.h b/src/mongo/s/write_ops/write_without_shard_key_util.h
new file mode 100644
index 00000000000..9de749d3f5c
--- /dev/null
+++ b/src/mongo/s/write_ops/write_without_shard_key_util.h
@@ -0,0 +1,48 @@
+/**
+ * Copyright (C) 2022-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.
+ */
+
+#pragma once
+
+#include "mongo/bson/bsonobj.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/operation_context.h"
+
+namespace mongo {
+namespace write_without_shard_key {
+
+/**
+ * Returns true if the write with the given query has enough information to target a single
+ * document, meaning the query contains a shard key, an _id, or both.
+ */
+bool canTargetQueryByShardKeyOrId(OperationContext* opCtx,
+ NamespaceString ns,
+ const BSONObj& query);
+
+} // namespace write_without_shard_key
+} // namespace mongo
diff --git a/src/mongo/s/write_ops/write_without_shard_key_util_test.cpp b/src/mongo/s/write_ops/write_without_shard_key_util_test.cpp
new file mode 100644
index 00000000000..3c29c0d6d98
--- /dev/null
+++ b/src/mongo/s/write_ops/write_without_shard_key_util_test.cpp
@@ -0,0 +1,95 @@
+/**
+ * Copyright (C) 2022-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.
+ */
+
+#include "mongo/logv2/log.h"
+#include "mongo/s/catalog_cache_test_fixture.h"
+#include "mongo/s/write_ops/write_without_shard_key_util.h"
+#include "mongo/unittest/unittest.h"
+
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kTest
+
+namespace mongo {
+namespace write_without_shard_key {
+namespace {
+
+const NamespaceString kNss("TestDB", "TestColl");
+const int splitPoint = 50;
+
+class WriteWithoutShardKeyUtilTest : public CatalogCacheTestFixture {
+public:
+ void setUp() override {
+ CatalogCacheTestFixture::setUp();
+
+ // Shard key is a compound shard key: {a:1, b:1}.
+ const ShardKeyPattern shardKeyPattern(BSON("a" << 1 << "b" << 1));
+ _cm = makeChunkManager(
+ kNss, shardKeyPattern, nullptr, false, {BSON("a" << splitPoint << "b" << splitPoint)});
+ }
+
+ ChunkManager getChunkManager() const {
+ return *_cm;
+ }
+
+ OperationContext* getOpCtx() {
+ return operationContext();
+ }
+
+private:
+ boost::optional<ChunkManager> _cm;
+};
+
+TEST_F(WriteWithoutShardKeyUtilTest, WriteQueryContainingFullShardKeyCanTargetSingleDocument) {
+ auto hasTargetingInfo = write_without_shard_key::canTargetQueryByShardKeyOrId(
+ getOpCtx(), kNss, BSON("a" << 1 << "b" << 1));
+ ASSERT_EQ(hasTargetingInfo, true);
+}
+
+TEST_F(WriteWithoutShardKeyUtilTest,
+ WriteQueryContainingPartialShardKeyCannotTargetSingleDocument) {
+ auto hasTargetingInfo =
+ write_without_shard_key::canTargetQueryByShardKeyOrId(getOpCtx(), kNss, BSON("a" << 1));
+ ASSERT_EQ(hasTargetingInfo, false);
+}
+
+TEST_F(WriteWithoutShardKeyUtilTest, WriteQueryContainingUnderscoreIdCanTargetSingleDocument) {
+ auto hasTargetingInfo =
+ write_without_shard_key::canTargetQueryByShardKeyOrId(getOpCtx(), kNss, BSON("_id" << 1));
+ ASSERT_EQ(hasTargetingInfo, true);
+}
+
+TEST_F(WriteWithoutShardKeyUtilTest,
+ WriteQueryWithoutShardKeyOrUnderscoreIdCannotTargetSingleDocument) {
+ auto hasTargetingInfo =
+ write_without_shard_key::canTargetQueryByShardKeyOrId(getOpCtx(), kNss, BSON("x" << 1));
+ ASSERT_EQ(hasTargetingInfo, false);
+}
+
+} // namespace
+} // namespace write_without_shard_key
+} // namespace mongo