summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuhong Zhang <yuhong.zhang@mongodb.com>2022-03-03 21:41:10 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-03-11 01:56:16 +0000
commita94046f398f652564813c90cae8c9e419b1f0f6b (patch)
treeb75bb213e2ea517b5803de1ef1408291586f7382
parentba2d2a0ed53c59d732fb7a6452d27ef190c0dbc9 (diff)
downloadmongo-a94046f398f652564813c90cae8c9e419b1f0f6b.tar.gz
SERVER-61158 add unique to collMod index request
-rw-r--r--jstests/core/collmod_convert_to_unique.js78
-rw-r--r--src/mongo/db/auth/auth_op_observer.cpp4
-rw-r--r--src/mongo/db/auth/auth_op_observer.h2
-rw-r--r--src/mongo/db/catalog/coll_mod.cpp96
-rw-r--r--src/mongo/db/free_mon/free_mon_op_observer.h2
-rw-r--r--src/mongo/db/op_observer.h11
-rw-r--r--src/mongo/db/op_observer_impl.cpp13
-rw-r--r--src/mongo/db/op_observer_impl.h2
-rw-r--r--src/mongo/db/op_observer_impl_test.cpp29
-rw-r--r--src/mongo/db/op_observer_noop.h2
-rw-r--r--src/mongo/db/op_observer_registry.h4
-rw-r--r--src/mongo/db/op_observer_util.cpp19
-rw-r--r--src/mongo/db/op_observer_util.h2
-rw-r--r--src/mongo/db/s/config_server_op_observer.h2
-rw-r--r--src/mongo/db/s/shard_server_op_observer.h2
15 files changed, 195 insertions, 73 deletions
diff --git a/jstests/core/collmod_convert_to_unique.js b/jstests/core/collmod_convert_to_unique.js
new file mode 100644
index 00000000000..a7b85450164
--- /dev/null
+++ b/jstests/core/collmod_convert_to_unique.js
@@ -0,0 +1,78 @@
+/**
+ * Basic js tests for the collMod command converting regular indexes to unique indexes.
+ *
+ * @tags: [
+ * # Cannot implicitly shard accessed collections because of collection existing when none
+ * # expected.
+ * assumes_no_implicit_collection_creation_after_drop, # common tag in collMod tests.
+ * requires_fcv_42,
+ * requires_non_retryable_commands, # common tag in collMod tests.
+ * ]
+ */
+
+(function() {
+'use strict';
+
+const collModIndexUniqueEnabled =
+ assert.commandWorked(db.getMongo().adminCommand({getParameter: 1, collModIndexUnique: 1}))
+ .collModIndexUnique.value;
+
+if (!collModIndexUniqueEnabled) {
+ jsTestLog('Skipping test because the collMod unique index feature flag is disabled.');
+ return;
+}
+
+const collName = 'collmod_convert_to_unique';
+const coll = db.getCollection(collName);
+coll.drop();
+assert.commandWorked(db.createCollection(collName));
+
+function countUnique(key) {
+ const all = coll.getIndexes().filter(function(z) {
+ return z.unique && friendlyEqual(z.key, key);
+ });
+ return all.length;
+}
+
+// Creates a regular index and use collMod to convert it to a unique index.
+assert.commandWorked(coll.createIndex({a: 1}));
+
+// Tries to modify with a string 'unique' value.
+assert.commandFailedWithCode(
+ db.runCommand({collMod: collName, index: {keyPattern: {a: 1}, unique: '100'}}),
+ ErrorCodes.TypeMismatch);
+
+// Tries to modify with a false 'unique' value.
+assert.commandFailedWithCode(db.runCommand({
+ collMod: collName,
+ index: {keyPattern: {a: 1}, unique: false},
+}),
+ ErrorCodes.BadValue);
+
+assert.commandWorked(coll.insert({_id: 1, a: 100}));
+assert.commandWorked(coll.insert({_id: 2, a: 100}));
+assert.commandWorked(coll.remove({_id: 2}));
+
+// Successfully converts to a unique index.
+const result = assert.commandWorked(
+ db.runCommand({collMod: collName, index: {keyPattern: {a: 1}, unique: true}}));
+
+// New index state should be reflected in 'unique_new' field in collMod response.
+const assertUniqueNew = function(result) {
+ assert(result.hasOwnProperty('unique_new'), tojson(result));
+ assert(result.unique_new, tojson(result));
+};
+if (db.getMongo().isMongos()) {
+ // Check the first shard's result from mongos.
+ assert(result.hasOwnProperty('raw'), tojson(result));
+ assertUniqueNew(Object.values(result.raw)[0]);
+} else {
+ assertUniqueNew(result);
+}
+
+// Look up index details in listIndexes output.
+assert.eq(countUnique({a: 1}), 0, 'index should not be unique yet: ' + tojson(coll.getIndexes()));
+
+// Test uniqueness constraint.
+assert.commandWorked(coll.insert({_id: 100, a: 100}));
+})(); \ No newline at end of file
diff --git a/src/mongo/db/auth/auth_op_observer.cpp b/src/mongo/db/auth/auth_op_observer.cpp
index 378c3052645..e059a08ff26 100644
--- a/src/mongo/db/auth/auth_op_observer.cpp
+++ b/src/mongo/db/auth/auth_op_observer.cpp
@@ -111,11 +111,11 @@ void AuthOpObserver::onCollMod(OperationContext* opCtx,
OptionalCollectionUUID uuid,
const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<TTLCollModInfo> ttlInfo) {
+ boost::optional<IndexCollModInfo> indexInfo) {
const auto cmdNss = nss.getCommandNS();
// Create the 'o' field object.
- const auto cmdObj = makeCollModCmdObj(collModCmd, oldCollOptions, ttlInfo);
+ const auto cmdObj = makeCollModCmdObj(collModCmd, oldCollOptions, indexInfo);
AuthorizationManager::get(opCtx->getServiceContext())
->logOp(opCtx, "c", cmdNss, cmdObj, nullptr);
diff --git a/src/mongo/db/auth/auth_op_observer.h b/src/mongo/db/auth/auth_op_observer.h
index d5c5ec8f85b..e68929b5461 100644
--- a/src/mongo/db/auth/auth_op_observer.h
+++ b/src/mongo/db/auth/auth_op_observer.h
@@ -109,7 +109,7 @@ public:
OptionalCollectionUUID uuid,
const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<TTLCollModInfo> ttlInfo) final;
+ boost::optional<IndexCollModInfo> indexInfo) final;
void onDropDatabase(OperationContext* opCtx, const std::string& dbName) final;
diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp
index 582d073e664..040cc631a97 100644
--- a/src/mongo/db/catalog/coll_mod.cpp
+++ b/src/mongo/db/catalog/coll_mod.cpp
@@ -53,6 +53,7 @@
#include "mongo/db/service_context.h"
#include "mongo/db/storage/durable_catalog.h"
#include "mongo/db/storage/recovery_unit.h"
+#include "mongo/db/storage/storage_parameters_gen.h"
#include "mongo/db/views/view_catalog.h"
#include "mongo/util/fail_point_service.h"
#include "mongo/util/log.h"
@@ -67,6 +68,7 @@ MONGO_FAIL_POINT_DEFINE(assertAfterIndexUpdate);
struct CollModRequest {
const IndexDescriptor* idx = nullptr;
BSONElement indexExpireAfterSeconds = {};
+ BSONElement indexUnique = {};
BSONElement viewPipeLine = {};
std::string viewOn = {};
boost::optional<BSONObj> collValidator;
@@ -122,13 +124,24 @@ StatusWith<CollModRequest> parseCollModRequest(OperationContext* opCtx,
}
cmr.indexExpireAfterSeconds = indexObj["expireAfterSeconds"];
- if (cmr.indexExpireAfterSeconds.eoo()) {
- return Status(ErrorCodes::InvalidOptions, "no expireAfterSeconds field");
+ cmr.indexUnique = indexObj["unique"];
+
+ if (cmr.indexUnique) {
+ uassert(ErrorCodes::InvalidOptions,
+ "collMod does not support converting an index to unique",
+ gCollModIndexUnique);
+ }
+
+ if (!cmr.indexExpireAfterSeconds && !cmr.indexUnique) {
+ return Status(ErrorCodes::InvalidOptions, "no expireAfterSeconds or unique field");
}
- if (!cmr.indexExpireAfterSeconds.isNumber()) {
+ if (cmr.indexExpireAfterSeconds && !cmr.indexExpireAfterSeconds.isNumber()) {
return Status(ErrorCodes::InvalidOptions,
"expireAfterSeconds field must be a number");
}
+ if (cmr.indexUnique && !cmr.indexUnique.isBoolean()) {
+ return Status(ErrorCodes::InvalidOptions, "unique field must be a boolean");
+ }
if (!indexName.empty()) {
cmr.idx = coll->getIndexCatalog()->findIndexByName(opCtx, indexName);
@@ -158,13 +171,20 @@ StatusWith<CollModRequest> parseCollModRequest(OperationContext* opCtx,
cmr.idx = indexes[0];
}
- BSONElement oldExpireSecs = cmr.idx->infoObj().getField("expireAfterSeconds");
- if (oldExpireSecs.eoo()) {
- return Status(ErrorCodes::InvalidOptions, "no expireAfterSeconds field to update");
+ if (cmr.indexExpireAfterSeconds) {
+ BSONElement oldExpireSecs = cmr.idx->infoObj().getField("expireAfterSeconds");
+ if (oldExpireSecs.eoo()) {
+ return Status(ErrorCodes::InvalidOptions,
+ "no expireAfterSeconds field to update");
+ }
+ if (!oldExpireSecs.isNumber()) {
+ return Status(ErrorCodes::InvalidOptions,
+ "existing expireAfterSeconds field is not a number");
+ }
}
- if (!oldExpireSecs.isNumber()) {
- return Status(ErrorCodes::InvalidOptions,
- "existing expireAfterSeconds field is not a number");
+
+ if (cmr.indexUnique && !cmr.indexUnique.trueValue()) {
+ return Status(ErrorCodes::BadValue, "Cannot make index non-unique");
}
} else if (fieldName == "validator" && !isView) {
@@ -335,36 +355,52 @@ Status _collModInternal(OperationContext* opCtx,
CollectionOptions oldCollOptions = DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, nss);
- boost::optional<TTLCollModInfo> ttlInfo;
+ boost::optional<IndexCollModInfo> indexCollModInfo;
+ BSONElement newExpireSecs = {};
+ BSONElement oldExpireSecs = {};
+ BSONElement newUnique = {};
// Handle collMod operation type appropriately.
- // TTLIndex
- if (!cmr.indexExpireAfterSeconds.eoo()) {
- BSONElement& newExpireSecs = cmr.indexExpireAfterSeconds;
- BSONElement oldExpireSecs = cmr.idx->infoObj().getField("expireAfterSeconds");
+ if (cmr.idx) {
+ // TTLIndex
+ if (cmr.indexExpireAfterSeconds) {
+ newExpireSecs = cmr.indexExpireAfterSeconds;
+ oldExpireSecs = cmr.idx->infoObj().getField("expireAfterSeconds");
- if (SimpleBSONElementComparator::kInstance.evaluate(oldExpireSecs != newExpireSecs)) {
- result->appendAs(oldExpireSecs, "expireAfterSeconds_old");
+ if (SimpleBSONElementComparator::kInstance.evaluate(oldExpireSecs != newExpireSecs)) {
+ result->appendAs(oldExpireSecs, "expireAfterSeconds_old");
- // Change the value of "expireAfterSeconds" on disk.
- DurableCatalog::get(opCtx)->updateTTLSetting(
- opCtx, coll->ns(), cmr.idx->indexName(), newExpireSecs.safeNumberLong());
+ // Change the value of "expireAfterSeconds" on disk.
+ DurableCatalog::get(opCtx)->updateTTLSetting(
+ opCtx, coll->ns(), cmr.idx->indexName(), newExpireSecs.safeNumberLong());
- // Notify the index catalog that the definition of this index changed.
- cmr.idx = coll->getIndexCatalog()->refreshEntry(opCtx, cmr.idx);
- result->appendAs(newExpireSecs, "expireAfterSeconds_new");
+ // Notify the index catalog that the definition of this index changed.
+ cmr.idx = coll->getIndexCatalog()->refreshEntry(opCtx, cmr.idx);
+ result->appendAs(newExpireSecs, "expireAfterSeconds_new");
- if (MONGO_FAIL_POINT(assertAfterIndexUpdate)) {
- log() << "collMod - assertAfterIndexUpdate fail point enabled.";
- uasserted(50970, "trigger rollback after the index update");
+ if (MONGO_FAIL_POINT(assertAfterIndexUpdate)) {
+ log() << "collMod - assertAfterIndexUpdate fail point enabled.";
+ uasserted(50970, "trigger rollback after the index update");
+ }
+ }
+ }
+
+ // UniqueIndex
+ if (cmr.indexUnique) {
+ if (!cmr.idx->infoObj().getField("unique").trueValue()) {
+ newUnique = cmr.indexUnique;
+ result->appendAs(newUnique, "unique_new");
}
}
- // Save previous TTL index expiration.
- ttlInfo = TTLCollModInfo{Seconds(newExpireSecs.safeNumberLong()),
- Seconds(oldExpireSecs.safeNumberLong()),
- cmr.idx->indexName()};
+ indexCollModInfo =
+ IndexCollModInfo{!cmr.indexExpireAfterSeconds ? boost::optional<Seconds>()
+ : Seconds(newExpireSecs.safeNumberLong()),
+ !cmr.indexExpireAfterSeconds ? boost::optional<Seconds>()
+ : Seconds(oldExpireSecs.safeNumberLong()),
+ !cmr.indexUnique ? boost::optional<bool>() : newUnique.booleanSafe(),
+ cmr.idx->indexName()};
}
if (cmr.collValidator) {
@@ -407,7 +443,7 @@ Status _collModInternal(OperationContext* opCtx,
// Only observe non-view collMods, as view operations are observed as operations on the
// system.views collection.
getGlobalServiceContext()->getOpObserver()->onCollMod(
- opCtx, nss, coll->uuid(), oplogEntryBuilder.obj(), oldCollOptions, ttlInfo);
+ opCtx, nss, coll->uuid(), oplogEntryBuilder.obj(), oldCollOptions, indexCollModInfo);
wunit.commit();
diff --git a/src/mongo/db/free_mon/free_mon_op_observer.h b/src/mongo/db/free_mon/free_mon_op_observer.h
index e3e591973fa..a3d4e5f45bb 100644
--- a/src/mongo/db/free_mon/free_mon_op_observer.h
+++ b/src/mongo/db/free_mon/free_mon_op_observer.h
@@ -109,7 +109,7 @@ public:
OptionalCollectionUUID uuid,
const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<TTLCollModInfo> ttlInfo) final {}
+ boost::optional<IndexCollModInfo> indexInfo) final {}
void onDropDatabase(OperationContext* opCtx, const std::string& dbName) final {}
diff --git a/src/mongo/db/op_observer.h b/src/mongo/db/op_observer.h
index b5b4a992246..e73fcb66171 100644
--- a/src/mongo/db/op_observer.h
+++ b/src/mongo/db/op_observer.h
@@ -60,9 +60,10 @@ struct OplogUpdateEntryArgs {
: updateArgs(std::move(updateArgs)), nss(std::move(nss)), uuid(std::move(uuid)) {}
};
-struct TTLCollModInfo {
- Seconds expireAfterSeconds;
- Seconds oldExpireAfterSeconds;
+struct IndexCollModInfo {
+ boost::optional<Seconds> expireAfterSeconds;
+ boost::optional<Seconds> oldExpireAfterSeconds;
+ boost::optional<bool> unique;
std::string indexName;
};
@@ -179,7 +180,7 @@ public:
*
* To facilitate the rollback process, 'oldCollOptions' contains the previous state of all
* collection options i.e. the state prior to completion of the current collMod command.
- * 'ttlInfo' contains the index name and previous expiration time of a TTL index. The old
+ * 'indexInfo' contains the index name and previous expiration time of a TTL index. The old
* collection options will be stored in the 'o2.collectionOptions_old' field, and the old TTL
* expiration value in the 'o2.expireAfterSeconds_old' field.
*
@@ -206,7 +207,7 @@ public:
OptionalCollectionUUID uuid,
const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<TTLCollModInfo> ttlInfo) = 0;
+ boost::optional<IndexCollModInfo> indexInfo) = 0;
virtual void onDropDatabase(OperationContext* opCtx, const std::string& dbName) = 0;
/**
diff --git a/src/mongo/db/op_observer_impl.cpp b/src/mongo/db/op_observer_impl.cpp
index 4ba2ccf847b..8643d03649f 100644
--- a/src/mongo/db/op_observer_impl.cpp
+++ b/src/mongo/db/op_observer_impl.cpp
@@ -791,18 +791,21 @@ void OpObserverImpl::onCollMod(OperationContext* opCtx,
OptionalCollectionUUID uuid,
const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<TTLCollModInfo> ttlInfo) {
+ boost::optional<IndexCollModInfo> indexInfo) {
const auto cmdNss = nss.getCommandNS();
// Create the 'o' field object.
- const auto cmdObj = makeCollModCmdObj(collModCmd, oldCollOptions, ttlInfo);
+ const auto cmdObj = makeCollModCmdObj(collModCmd, oldCollOptions, indexInfo);
// Create the 'o2' field object. We save the old collection metadata and TTL expiration.
BSONObjBuilder o2Builder;
o2Builder.append("collectionOptions_old", oldCollOptions.toBSON());
- if (ttlInfo) {
- auto oldExpireAfterSeconds = durationCount<Seconds>(ttlInfo->oldExpireAfterSeconds);
- o2Builder.append("expireAfterSeconds_old", oldExpireAfterSeconds);
+ if (indexInfo) {
+ if (indexInfo->oldExpireAfterSeconds) {
+ auto oldExpireAfterSeconds =
+ durationCount<Seconds>(indexInfo->oldExpireAfterSeconds.get());
+ o2Builder.append("expireAfterSeconds_old", oldExpireAfterSeconds);
+ }
}
const auto o2Obj = o2Builder.done();
diff --git a/src/mongo/db/op_observer_impl.h b/src/mongo/db/op_observer_impl.h
index 9fb50fda884..6f4ee4a401d 100644
--- a/src/mongo/db/op_observer_impl.h
+++ b/src/mongo/db/op_observer_impl.h
@@ -99,7 +99,7 @@ public:
OptionalCollectionUUID uuid,
const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<TTLCollModInfo> ttlInfo) final;
+ boost::optional<IndexCollModInfo> indexInfo) final;
void onDropDatabase(OperationContext* opCtx, const std::string& dbName) final;
repl::OpTime onDropCollection(OperationContext* opCtx,
const NamespaceString& collectionName,
diff --git a/src/mongo/db/op_observer_impl_test.cpp b/src/mongo/db/op_observer_impl_test.cpp
index acb75e80994..ad809413f1e 100644
--- a/src/mongo/db/op_observer_impl_test.cpp
+++ b/src/mongo/db/op_observer_impl_test.cpp
@@ -251,16 +251,16 @@ TEST_F(OpObserverTest, CollModWithCollectionOptionsAndTTLInfo) {
oldCollOpts.validationLevel = "strict";
oldCollOpts.validationAction = "error";
- TTLCollModInfo ttlInfo;
- ttlInfo.expireAfterSeconds = Seconds(10);
- ttlInfo.oldExpireAfterSeconds = Seconds(5);
- ttlInfo.indexName = "name_of_index";
+ IndexCollModInfo indexInfo;
+ indexInfo.expireAfterSeconds = Seconds(10);
+ indexInfo.oldExpireAfterSeconds = Seconds(5);
+ indexInfo.indexName = "name_of_index";
// Write to the oplog.
{
AutoGetCollection autoColl(opCtx.get(), nss, MODE_IX, MODE_X);
WriteUnitOfWork wunit(opCtx.get());
- opObserver.onCollMod(opCtx.get(), nss, uuid, collModCmd, oldCollOpts, ttlInfo);
+ opObserver.onCollMod(opCtx.get(), nss, uuid, collModCmd, oldCollOpts, indexInfo);
wunit.commit();
}
@@ -268,14 +268,14 @@ TEST_F(OpObserverTest, CollModWithCollectionOptionsAndTTLInfo) {
// Ensure that collMod fields were properly added to the oplog entry.
auto o = oplogEntry.getObjectField("o");
- auto oExpected =
- BSON("collMod" << nss.coll() << "validationLevel"
- << "off"
- << "validationAction"
- << "warn"
- << "index"
- << BSON("name" << ttlInfo.indexName << "expireAfterSeconds"
- << durationCount<Seconds>(ttlInfo.expireAfterSeconds)));
+ auto oExpected = BSON(
+ "collMod" << nss.coll() << "validationLevel"
+ << "off"
+ << "validationAction"
+ << "warn"
+ << "index"
+ << BSON("name" << indexInfo.indexName << "expireAfterSeconds"
+ << durationCount<Seconds>(indexInfo.expireAfterSeconds.get())));
ASSERT_BSONOBJ_EQ(oExpected, o);
// Ensure that the old collection metadata was saved.
@@ -284,7 +284,8 @@ TEST_F(OpObserverTest, CollModWithCollectionOptionsAndTTLInfo) {
BSON("collectionOptions_old"
<< BSON("validationLevel" << oldCollOpts.validationLevel << "validationAction"
<< oldCollOpts.validationAction)
- << "expireAfterSeconds_old" << durationCount<Seconds>(ttlInfo.oldExpireAfterSeconds));
+ << "expireAfterSeconds_old"
+ << durationCount<Seconds>(indexInfo.oldExpireAfterSeconds.get()));
ASSERT_BSONOBJ_EQ(o2Expected, o2);
}
diff --git a/src/mongo/db/op_observer_noop.h b/src/mongo/db/op_observer_noop.h
index f3543e3e1ae..b9aa1b90d2e 100644
--- a/src/mongo/db/op_observer_noop.h
+++ b/src/mongo/db/op_observer_noop.h
@@ -93,7 +93,7 @@ public:
OptionalCollectionUUID uuid,
const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<TTLCollModInfo> ttlInfo) override {}
+ boost::optional<IndexCollModInfo> indexInfo) override {}
void onDropDatabase(OperationContext* opCtx, const std::string& dbName) override {}
repl::OpTime onDropCollection(OperationContext* opCtx,
const NamespaceString& collectionName,
diff --git a/src/mongo/db/op_observer_registry.h b/src/mongo/db/op_observer_registry.h
index ba1ef6ba91e..4d4b9fd3896 100644
--- a/src/mongo/db/op_observer_registry.h
+++ b/src/mongo/db/op_observer_registry.h
@@ -165,10 +165,10 @@ public:
OptionalCollectionUUID uuid,
const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<TTLCollModInfo> ttlInfo) override {
+ boost::optional<IndexCollModInfo> indexInfo) override {
ReservedTimes times{opCtx};
for (auto& o : _observers)
- o->onCollMod(opCtx, nss, uuid, collModCmd, oldCollOptions, ttlInfo);
+ o->onCollMod(opCtx, nss, uuid, collModCmd, oldCollOptions, indexInfo);
}
void onDropDatabase(OperationContext* const opCtx, const std::string& dbName) override {
diff --git a/src/mongo/db/op_observer_util.cpp b/src/mongo/db/op_observer_util.cpp
index b1bc7074915..f7512cc21a7 100644
--- a/src/mongo/db/op_observer_util.cpp
+++ b/src/mongo/db/op_observer_util.cpp
@@ -42,21 +42,24 @@ namespace mongo {
*/
BSONObj makeCollModCmdObj(const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<TTLCollModInfo> ttlInfo) {
+ boost::optional<IndexCollModInfo> indexInfo) {
BSONObjBuilder cmdObjBuilder;
- std::string ttlIndexFieldName = "index";
+ std::string indexFieldName = "index";
// Add all fields from the original collMod command.
for (auto elem : collModCmd) {
// We normalize all TTL collMod oplog entry objects to use the index name, even if the
// command used an index key pattern.
- if (elem.fieldNameStringData() == ttlIndexFieldName && ttlInfo) {
- BSONObjBuilder ttlIndexObjBuilder;
- ttlIndexObjBuilder.append("name", ttlInfo->indexName);
- ttlIndexObjBuilder.append("expireAfterSeconds",
- durationCount<Seconds>(ttlInfo->expireAfterSeconds));
+ if (elem.fieldNameStringData() == indexFieldName && indexInfo) {
+ BSONObjBuilder indexObjBuilder;
+ indexObjBuilder.append("name", indexInfo->indexName);
+ if (indexInfo->expireAfterSeconds)
+ indexObjBuilder.append("expireAfterSeconds",
+ durationCount<Seconds>(indexInfo->expireAfterSeconds.get()));
+ if (indexInfo->unique)
+ indexObjBuilder.append("unique", indexInfo->unique.get());
- cmdObjBuilder.append(ttlIndexFieldName, ttlIndexObjBuilder.obj());
+ cmdObjBuilder.append(indexFieldName, indexObjBuilder.obj());
} else {
cmdObjBuilder.append(elem);
}
diff --git a/src/mongo/db/op_observer_util.h b/src/mongo/db/op_observer_util.h
index 7e60c66cca8..568c05e2fc7 100644
--- a/src/mongo/db/op_observer_util.h
+++ b/src/mongo/db/op_observer_util.h
@@ -41,5 +41,5 @@ BSONObj makeCreateCollCmdObj(const NamespaceString& collectionName,
BSONObj makeCollModCmdObj(const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<TTLCollModInfo> ttlInfo);
+ boost::optional<IndexCollModInfo> indexInfo);
} // namespace mongo
diff --git a/src/mongo/db/s/config_server_op_observer.h b/src/mongo/db/s/config_server_op_observer.h
index 93d4ef813d2..60e50c2f719 100644
--- a/src/mongo/db/s/config_server_op_observer.h
+++ b/src/mongo/db/s/config_server_op_observer.h
@@ -109,7 +109,7 @@ public:
OptionalCollectionUUID uuid,
const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<TTLCollModInfo> ttlInfo) override {}
+ boost::optional<IndexCollModInfo> indexInfo) override {}
void onDropDatabase(OperationContext* opCtx, const std::string& dbName) override {}
diff --git a/src/mongo/db/s/shard_server_op_observer.h b/src/mongo/db/s/shard_server_op_observer.h
index 52c35c5f1ce..e88f2b1c8ee 100644
--- a/src/mongo/db/s/shard_server_op_observer.h
+++ b/src/mongo/db/s/shard_server_op_observer.h
@@ -110,7 +110,7 @@ public:
OptionalCollectionUUID uuid,
const BSONObj& collModCmd,
const CollectionOptions& oldCollOptions,
- boost::optional<TTLCollModInfo> ttlInfo) override {}
+ boost::optional<IndexCollModInfo> indexInfo) override {}
void onDropDatabase(OperationContext* opCtx, const std::string& dbName) override {}