summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenety Goh <benety@mongodb.com>2022-08-28 08:31:07 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-08-31 12:12:05 +0000
commitcf72acd7f83576a12abf2928ca53699fdb341e25 (patch)
tree4106cb332d94fee9f8bcad4190dfa6efae08e4e8
parentdaaff3b1445848a645e2ab883d6836b37ffc8a83 (diff)
downloadmongo-cf72acd7f83576a12abf2928ca53699fdb341e25.tar.gz
SERVER-68477 listIndexes repairs TTL indexes with NaN expireAfterSeconds
(cherry picked from commit d6528bf96f08b79ca850902b2d1d81264fa7baa1)
-rw-r--r--jstests/noPassthrough/ttl_expire_nan.js24
-rw-r--r--src/mongo/db/catalog/index_key_validate.cpp16
-rw-r--r--src/mongo/db/catalog/index_key_validate.h6
-rw-r--r--src/mongo/db/catalog/index_key_validate_test.cpp14
4 files changed, 57 insertions, 3 deletions
diff --git a/jstests/noPassthrough/ttl_expire_nan.js b/jstests/noPassthrough/ttl_expire_nan.js
index 5d26b214487..6b8ff73d015 100644
--- a/jstests/noPassthrough/ttl_expire_nan.js
+++ b/jstests/noPassthrough/ttl_expire_nan.js
@@ -11,9 +11,13 @@
(function() {
'use strict';
+load('jstests/noPassthrough/libs/index_build.js');
+
const rst = new ReplSetTest({
nodes: [{}, {rsConfig: {votes: 0, priority: 0}}],
nodeOptions: {setParameter: {ttlMonitorSleepSecs: 5}},
+ // Sync from primary only so that we have a well-defined node to check listIndexes behavior.
+ settings: {chainingAllowed: false},
});
rst.startSet();
rst.initiate();
@@ -41,5 +45,25 @@ checkLog.containsJson(secondary, 20384, {
assert.eq(
coll.countDocuments({}), 1, 'ttl index with NaN duration should not remove any documents.');
+// Confirm that TTL index is replicated with a non-zero 'expireAfterSeconds' during initial sync.
+const newNode = rst.add({rsConfig: {votes: 0, priority: 0}});
+rst.reInitiate();
+rst.waitForState(newNode, ReplSetTest.State.SECONDARY);
+rst.awaitReplication();
+let newNodeTestDB = newNode.getDB(db.getName());
+let newNodeColl = newNodeTestDB.getCollection(coll.getName());
+const newNodeIndexes = IndexBuildTest.assertIndexes(newNodeColl, 2, ['_id_', 't_1']);
+const newNodeSpec = newNodeIndexes.t_1;
+jsTestLog('TTL index on initial sync node: ' + tojson(newNodeSpec));
+assert(newNodeSpec.hasOwnProperty('expireAfterSeconds'),
+ 'Index was not replicated as a TTL index during initial sync.');
+assert.gt(newNodeSpec.expireAfterSeconds,
+ 0,
+ 'NaN expireAferSeconds was replicated as zero during initial sync.');
+
+// Check that listIndexes on the primary logged a "Fixing expire field from TTL index spec" message
+// during the NaN 'expireAfterSeconds' conversion.
+checkLog.containsJson(primary, 6835900, {namespace: coll.getFullName()});
+
rst.stopSet();
})();
diff --git a/src/mongo/db/catalog/index_key_validate.cpp b/src/mongo/db/catalog/index_key_validate.cpp
index 3fc2aa28304..6e7c5faeb09 100644
--- a/src/mongo/db/catalog/index_key_validate.cpp
+++ b/src/mongo/db/catalog/index_key_validate.cpp
@@ -269,8 +269,8 @@ BSONObj removeUnknownFields(const NamespaceString& ns, const BSONObj& indexSpec)
BSONObj repairIndexSpec(const NamespaceString& ns,
const BSONObj& indexSpec,
const std::set<StringData>& allowedFieldNames) {
- auto fixBoolIndexSpecFn = [&indexSpec, &ns](const BSONElement& indexSpecElem,
- BSONObjBuilder* builder) {
+ auto fixIndexSpecFn = [&indexSpec, &ns](const BSONElement& indexSpecElem,
+ BSONObjBuilder* builder) {
StringData fieldName = indexSpecElem.fieldNameStringData();
if ((IndexDescriptor::kBackgroundFieldName == fieldName ||
IndexDescriptor::kUniqueFieldName == fieldName ||
@@ -285,11 +285,21 @@ BSONObj repairIndexSpec(const NamespaceString& ns,
"fieldName"_attr = redact(fieldName),
"indexSpec"_attr = redact(indexSpec));
builder->appendBool(fieldName, true);
+ } else if (IndexDescriptor::kExpireAfterSecondsFieldName == fieldName &&
+ !(indexSpecElem.isNumber() && !indexSpecElem.isNaN())) {
+ LOGV2_WARNING(6835900,
+ "Fixing expire field from TTL index spec",
+ "namespace"_attr = redact(ns.toString()),
+ "fieldName"_attr = redact(fieldName),
+ "indexSpec"_attr = redact(indexSpec));
+ builder->appendNumber(fieldName,
+ durationCount<Seconds>(kExpireAfterSecondsForInactiveTTLIndex));
} else {
builder->append(indexSpecElem);
}
};
- return buildRepairedIndexSpec(ns, indexSpec, allowedFieldNames, fixBoolIndexSpecFn);
+
+ return buildRepairedIndexSpec(ns, indexSpec, allowedFieldNames, fixIndexSpecFn);
}
StatusWith<BSONObj> validateIndexSpec(OperationContext* opCtx, const BSONObj& indexSpec) {
diff --git a/src/mongo/db/catalog/index_key_validate.h b/src/mongo/db/catalog/index_key_validate.h
index f9680ac035b..2ba7174c1b0 100644
--- a/src/mongo/db/catalog/index_key_validate.h
+++ b/src/mongo/db/catalog/index_key_validate.h
@@ -43,6 +43,12 @@ class StatusWith;
namespace index_key_validate {
+// TTL indexes with 'expireAfterSeconds' are repaired with this duration, which is chosen to be
+// the largest possible value for the 'safeInt' type that can be returned in the listIndexes
+// response.
+constexpr auto kExpireAfterSecondsForInactiveTTLIndex =
+ Seconds(std::numeric_limits<int32_t>::max());
+
static std::set<StringData> allowedFieldNames = {
IndexDescriptor::k2dIndexBitsFieldName,
IndexDescriptor::k2dIndexMaxFieldName,
diff --git a/src/mongo/db/catalog/index_key_validate_test.cpp b/src/mongo/db/catalog/index_key_validate_test.cpp
index 9c4813a2d2e..c60df1b34aa 100644
--- a/src/mongo/db/catalog/index_key_validate_test.cpp
+++ b/src/mongo/db/catalog/index_key_validate_test.cpp
@@ -426,6 +426,20 @@ TEST(IndexKeyValidateTest, RepairIndexSpecs) {
NamespaceString("coll"),
fromjson("{key: {a: 1}, name: 'index', sparse: 'true', background: '1', safe: "
"true, force: true}"))));
+
+ ASSERT(BSON("key" << BSON("a" << 1) << "name"
+ << "index"
+ << "expireAfterSeconds" << std::numeric_limits<int32_t>::max())
+ .binaryEqual(index_key_validate::repairIndexSpec(
+ NamespaceString("coll"),
+ fromjson("{key: {a: 1}, name: 'index', expireAfterSeconds: NaN}"))));
+
+ ASSERT(BSON("key" << BSON("a" << 1) << "name"
+ << "index"
+ << "expireAfterSeconds" << std::numeric_limits<int32_t>::max())
+ .binaryEqual(index_key_validate::repairIndexSpec(
+ NamespaceString("coll"),
+ fromjson("{key: {a: 1}, name: 'index', expireAfterSeconds: '123'}"))));
}
TEST(IndexKeyValidateTest, GeoIndexSpecs) {