summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorKris Satya <kris.satya@mongodb.com>2021-07-20 19:05:12 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-07-23 19:46:24 +0000
commit394ba6d936777fb26b10ef8f530fb61c11c68921 (patch)
tree8834f3a95908b8d0568ed90a23f9e30c7834dd21 /jstests
parent6bd454e5ddbd3644db1bfcfc75c92fb7010ffffb (diff)
downloadmongo-394ba6d936777fb26b10ef8f530fb61c11c68921.tar.gz
SERVER-58493 Add support for time-series metaField-only deletes with hint
Diffstat (limited to 'jstests')
-rw-r--r--jstests/core/timeseries/timeseries_delete_hint.js206
-rw-r--r--jstests/libs/parallelTester.js3
2 files changed, 209 insertions, 0 deletions
diff --git a/jstests/core/timeseries/timeseries_delete_hint.js b/jstests/core/timeseries/timeseries_delete_hint.js
new file mode 100644
index 00000000000..043a96c4e01
--- /dev/null
+++ b/jstests/core/timeseries/timeseries_delete_hint.js
@@ -0,0 +1,206 @@
+/**
+ * Tests running the delete command with a hint on a time-series collection.
+ * @tags: [
+ * assumes_no_implicit_collection_creation_after_drop,
+ * does_not_support_stepdowns,
+ * does_not_support_transactions,
+ * requires_fcv_50,
+ * requires_getmore,
+ * # $currentOp can't run with a readConcern other than 'local'.
+ * assumes_read_concern_unchanged,
+ * # This test only synchronizes deletes on the primary.
+ * assumes_read_preference_unchanged,
+ * # Fail points in this test do not exist on mongos.
+ * assumes_against_mongod_not_mongos,
+ * uses_parallel_shell,
+ * ]
+ */
+(function() {
+"use strict";
+
+load("jstests/core/timeseries/libs/timeseries.js");
+load("jstests/libs/curop_helpers.js");
+load('jstests/libs/parallel_shell_helpers.js');
+
+if (!TimeseriesTest.timeseriesUpdatesAndDeletesEnabled(db.getMongo())) {
+ jsTestLog("Skipping test because the time-series updates and deletes feature flag is disabled");
+ return;
+}
+
+const timeFieldName = "time";
+const metaFieldName = "tag";
+const collName = 't';
+const bucketsCollNamespace = jsTestName() + '.system.buckets.' + collName;
+
+const validateDeleteIndex = (docsToInsert,
+ expectedRemainingDocs,
+ expectedNRemoved,
+ deleteQuery,
+ indexes,
+ expectedPlan,
+ {expectedErrorCode = null} = {}) => {
+ const testDB = db.getSiblingDB(jsTestName());
+ const awaitTestDelete = startParallelShell(funWithArgs(
+ function(docsToInsert,
+ expectedRemainingDocs,
+ expectedNRemoved,
+ deleteQuery,
+ indexes,
+ timeFieldName,
+ metaFieldName,
+ collName,
+ expectedErrorCode) {
+ const testDB = db.getSiblingDB(jsTestName());
+ const coll = testDB.getCollection(collName);
+
+ assert.commandWorked(testDB.createCollection(
+ coll.getName(),
+ {timeseries: {timeField: timeFieldName, metaField: metaFieldName}}));
+ assert.commandWorked(coll.createIndexes(indexes));
+
+ assert.commandWorked(coll.insert(docsToInsert));
+
+ assert.commandWorked(testDB.adminCommand(
+ {configureFailPoint: "hangBeforeChildRemoveOpFinishes", mode: "alwaysOn"}));
+ const res = expectedErrorCode
+ ? assert.commandFailedWithCode(
+ testDB.runCommand({delete: coll.getName(), deletes: deleteQuery}),
+ expectedErrorCode)
+ : assert.commandWorked(
+ testDB.runCommand({delete: coll.getName(), deletes: deleteQuery}));
+ assert.eq(res["n"], expectedNRemoved);
+ assert.docEq(coll.find({}, {_id: 0}).toArray(), expectedRemainingDocs);
+ assert(coll.drop());
+ },
+ docsToInsert,
+ expectedRemainingDocs,
+ expectedNRemoved,
+ deleteQuery,
+ indexes,
+ timeFieldName,
+ metaFieldName,
+ collName,
+ expectedErrorCode));
+
+ for (let childCount = 0; childCount < deleteQuery.length; ++childCount) {
+ const childCurOp = waitForCurOpByFailPoint(
+ testDB, bucketsCollNamespace, "hangBeforeChildRemoveOpFinishes")[0];
+
+ // Assert the plan uses the expected index.
+ if (!expectedErrorCode) {
+ assert.eq(childCurOp['planSummary'], expectedPlan);
+ }
+
+ assert.commandWorked(testDB.adminCommand(
+ {configureFailPoint: "hangBeforeChildRemoveOpIsPopped", mode: "alwaysOn"}));
+ assert.commandWorked(testDB.adminCommand(
+ {configureFailPoint: "hangBeforeChildRemoveOpFinishes", mode: "off"}));
+
+ waitForCurOpByFailPoint(testDB, bucketsCollNamespace, "hangBeforeChildRemoveOpIsPopped");
+
+ // Enable the hangBeforeChildRemoveOpFinishes fail point if this is not the last child.
+ if (childCount + 1 < deleteQuery.length) {
+ assert.commandWorked(testDB.adminCommand(
+ {configureFailPoint: "hangBeforeChildRemoveOpFinishes", mode: "alwaysOn"}));
+ }
+
+ assert.commandWorked(testDB.adminCommand(
+ {configureFailPoint: "hangBeforeChildRemoveOpIsPopped", mode: "off"}));
+ }
+
+ // Wait for testDelete to finish.
+ awaitTestDelete();
+};
+
+const objA = {
+ [timeFieldName]: ISODate(),
+ "measurement": {"A": "cpu"},
+ [metaFieldName]: {a: "A"}
+};
+const objB = {
+ [timeFieldName]: ISODate(),
+ "measurement": {"A": "cpu"},
+ [metaFieldName]: {b: "B"}
+};
+const objC = {
+ [timeFieldName]: ISODate(),
+ "measurement": {"A": "cpu"},
+ [metaFieldName]: {c: "C"}
+};
+
+// Query using the metaField index as a hint.
+validateDeleteIndex([objA, objB, objC],
+ [objB, objC],
+ 1,
+ [{q: {[metaFieldName]: {a: "A"}}, limit: 0, hint: {[metaFieldName]: 1}}],
+ [{[metaFieldName]: 1}],
+ "IXSCAN { meta: 1 }");
+
+// Query on a collection with a compound index using the timeField and metaField indexes as
+// hints.
+validateDeleteIndex(
+ [objA, objB, objC],
+ [objB, objC],
+ 1,
+ [{q: {[metaFieldName]: {a: "A"}}, limit: 0, hint: {[timeFieldName]: 1, [metaFieldName]: 1}}],
+ [{[timeFieldName]: 1, [metaFieldName]: 1}],
+ "IXSCAN { control.min.time: 1, control.max.time: 1, meta: 1 }");
+
+// Query on a collection with a compound index using the timeField and metaField indexes as
+// hints
+validateDeleteIndex(
+ [objA, objB, objC],
+ [objA, objC],
+ 1,
+ [{q: {[metaFieldName]: {b: "B"}}, limit: 0, hint: {[timeFieldName]: -1, [metaFieldName]: 1}}],
+ [{[timeFieldName]: -1, [metaFieldName]: 1}],
+ "IXSCAN { control.max.time: -1, control.min.time: -1, meta: 1 }");
+
+// Query on a collection with a compound index using the timeField and metaField index names
+// as hints.
+validateDeleteIndex([objA, objB, objC],
+ [objA, objC],
+ 1,
+ [{
+ q: {[metaFieldName]: {b: "B"}},
+ limit: 0,
+ hint: timeFieldName + "_1_" + metaFieldName + "_1"
+ }],
+ [{[timeFieldName]: 1, [metaFieldName]: 1}],
+ "IXSCAN { control.min.time: 1, control.max.time: 1, meta: 1 }");
+
+// Query on a collection with multiple indexes using the timeField index as a hint.
+validateDeleteIndex([objA, objB, objC],
+ [objA, objB],
+ 1,
+ [{q: {[metaFieldName]: {c: "C"}}, limit: 0, hint: {[timeFieldName]: 1}}],
+ [{[metaFieldName]: -1}, {[timeFieldName]: 1}],
+ "IXSCAN { control.min.time: 1, control.max.time: 1 }");
+
+// Query on a collection with multiple indexes using the timeField index as a hint.
+validateDeleteIndex([objA, objB, objC],
+ [objA, objB],
+ 1,
+ [{q: {[metaFieldName]: {c: "C"}}, limit: 0, hint: {[timeFieldName]: 1}}],
+ [{[metaFieldName]: -1}, {[timeFieldName]: 1}],
+ "IXSCAN { control.min.time: 1, control.max.time: 1 }");
+
+// Query on a collection with multiple indexes using an invalid index name.
+validateDeleteIndex([objA, objB, objC],
+ [objA, objB, objC],
+ 0,
+ [{q: {[metaFieldName]: {c: "C"}}, limit: 0, hint: "test_hint"}],
+ [{[metaFieldName]: -1}, {[timeFieldName]: 1}],
+ "IXSCAN { control.min.time: 1, control.max.time: 1 }",
+ {expectedErrorCode: ErrorCodes.BadValue});
+
+// TODO: SERVER-58519 Uncomment this test.
+// // Query on a collection with multiple indexes using an invalid index spec.
+// validateDeleteIndex([objA, objB, objC],
+// [objA, objB, objC],
+// 0,
+// [{q: {[metaFieldName]: {c: "C"}}, limit: 0, hint: {"test_hint": 1}}],
+// [{[metaFieldName]: -1}, {[timeFieldName]: 1}],
+// "IXSCAN { control.min.time: 1, control.max.time: 1 }",
+// {expectedErrorCode: ErrorCodes.BadValue});
+})();
diff --git a/jstests/libs/parallelTester.js b/jstests/libs/parallelTester.js
index fb4edc625eb..d1146548c74 100644
--- a/jstests/libs/parallelTester.js
+++ b/jstests/libs/parallelTester.js
@@ -228,6 +228,9 @@ if (typeof _threadInject != "undefined") {
"bench_test1.js",
"bench_test2.js",
"bench_test3.js",
+ // This test causes delete commands to hang, which may affect other tests running
+ // concurrently.
+ "timeseries/timeseries_delete_hint.js"
]);
// Get files, including files in subdirectories.