diff options
Diffstat (limited to 'src/mongo/db/catalog')
-rw-r--r-- | src/mongo/db/catalog/coll_mod.cpp | 27 | ||||
-rw-r--r-- | src/mongo/db/catalog/coll_mod_index.cpp | 36 | ||||
-rw-r--r-- | src/mongo/db/catalog/coll_mod_index.h | 1 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection.h | 5 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_impl.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_impl.h | 2 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_mock.h | 2 |
7 files changed, 63 insertions, 14 deletions
diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp index 0ffc15e0e60..747de3e044a 100644 --- a/src/mongo/db/catalog/coll_mod.cpp +++ b/src/mongo/db/catalog/coll_mod.cpp @@ -185,7 +185,8 @@ StatusWith<ParsedCollModRequest> parseCollModRequest(OperationContext* opCtx, } if (!cmdIndex.getExpireAfterSeconds() && !cmdIndex.getHidden() && - !cmdIndex.getUnique() && !cmdIndex.getPrepareUnique()) { + !cmdIndex.getUnique() && !cmdIndex.getPrepareUnique() && + !cmdIndex.getForceNonUnique()) { return Status(ErrorCodes::InvalidOptions, "no expireAfterSeconds, hidden, unique, or prepareUnique field"); } @@ -201,6 +202,13 @@ StatusWith<ParsedCollModRequest> parseCollModRequest(OperationContext* opCtx, serverGlobalParams.featureCompatibility)); } + if (cmdIndex.getUnique() && cmdIndex.getForceNonUnique()) { + return Status( + ErrorCodes::InvalidOptions, + "collMod does not support 'unique' and 'forceNonUnique' options at the " + "same time"); + } + if (cmdIndex.getExpireAfterSeconds()) { if (isTimeseries) { return Status(ErrorCodes::InvalidOptions, @@ -305,7 +313,7 @@ StatusWith<ParsedCollModRequest> parseCollModRequest(OperationContext* opCtx, cmr.numModifications++; if (bool unique = *cmdIndex.getUnique(); !unique) { - return Status(ErrorCodes::BadValue, "Cannot make index non-unique"); + return Status(ErrorCodes::BadValue, "'Unique: false' option is not supported"); } // Attempting to converting a unique index should be treated as a no-op. @@ -350,6 +358,21 @@ StatusWith<ParsedCollModRequest> parseCollModRequest(OperationContext* opCtx, } } + if (cmdIndex.getForceNonUnique()) { + cmr.numModifications++; + if (bool unique = *cmdIndex.getForceNonUnique(); !unique) { + return Status(ErrorCodes::BadValue, "'forceNonUnique: false' is not supported"); + } + + // Attempting to convert a non-unique index should be treated as a no-op. + if (!cmrIndex->idx->unique()) { + indexObjForOplog = + indexObjForOplog.removeField(CollModIndex::kForceNonUniqueFieldName); + } else { + cmrIndex->indexForceNonUnique = true; + } + } + // The index options doc must contain either the name or key pattern, but not both. // If we have just one field, the index modifications requested matches the current // state in catalog and there is nothing further to do. diff --git a/src/mongo/db/catalog/coll_mod_index.cpp b/src/mongo/db/catalog/coll_mod_index.cpp index 7be401d110b..4a6a26237ea 100644 --- a/src/mongo/db/catalog/coll_mod_index.cpp +++ b/src/mongo/db/catalog/coll_mod_index.cpp @@ -128,8 +128,7 @@ void getKeysForIndex(OperationContext* opCtx, } /** - * Adjusts unique setting on an index. - * An index can be converted to unique but removing the uniqueness property is not allowed. + * Adjusts unique setting on an index to true. */ void _processCollModIndexRequestUnique(OperationContext* opCtx, AutoGetCollection* autoColl, @@ -150,7 +149,7 @@ void _processCollModIndexRequestUnique(OperationContext* opCtx, } *newUnique = true; - autoColl->getWritableCollection(opCtx)->updateUniqueSetting(opCtx, idx->indexName()); + autoColl->getWritableCollection(opCtx)->updateUniqueSetting(opCtx, idx->indexName(), true); // Resets 'prepareUnique' to false after converting to unique index; autoColl->getWritableCollection(opCtx)->updatePrepareUniqueSetting( opCtx, idx->indexName(), false); @@ -173,6 +172,19 @@ void _processCollModIndexRequestPrepareUnique(OperationContext* opCtx, } } +/** + * Adjusts unique setting on an index to false. + */ +void _processCollModIndexRequestForceNonUnique(OperationContext* opCtx, + AutoGetCollection* autoColl, + const IndexDescriptor* idx, + boost::optional<bool>* newForceNonUnique) { + invariant(idx->unique(), str::stream() << "Index is already non-unique: " << idx->infoObj()); + + *newForceNonUnique = true; + autoColl->getWritableCollection(opCtx)->updateUniqueSetting(opCtx, idx->indexName(), false); +} + } // namespace void processCollModIndexRequest(OperationContext* opCtx, @@ -186,9 +198,11 @@ void processCollModIndexRequest(OperationContext* opCtx, auto indexHidden = collModIndexRequest.indexHidden; auto indexUnique = collModIndexRequest.indexUnique; auto indexPrepareUnique = collModIndexRequest.indexPrepareUnique; + auto indexForceNonUnique = collModIndexRequest.indexForceNonUnique; // Return early if there are no index modifications requested. - if (!indexExpireAfterSeconds && !indexHidden && !indexUnique && !indexPrepareUnique) { + if (!indexExpireAfterSeconds && !indexHidden && !indexUnique && !indexPrepareUnique && + !indexForceNonUnique) { return; } @@ -199,6 +213,7 @@ void processCollModIndexRequest(OperationContext* opCtx, boost::optional<bool> newUnique; boost::optional<bool> newPrepareUnique; boost::optional<bool> oldPrepareUnique; + boost::optional<bool> newForceNonUnique; // TTL Index if (indexExpireAfterSeconds) { @@ -224,6 +239,11 @@ void processCollModIndexRequest(OperationContext* opCtx, opCtx, autoColl, idx, *indexPrepareUnique, &newPrepareUnique, &oldPrepareUnique); } + // User wants to convert an index back to be non-unique. + if (indexForceNonUnique) { + _processCollModIndexRequestForceNonUnique(opCtx, autoColl, idx, &newForceNonUnique); + } + *indexCollModInfo = IndexCollModInfo{!newExpireSecs ? boost::optional<Seconds>() : Seconds(*newExpireSecs), !oldExpireSecs ? boost::optional<Seconds>() : Seconds(*oldExpireSecs), @@ -232,13 +252,14 @@ void processCollModIndexRequest(OperationContext* opCtx, newUnique, newPrepareUnique, oldPrepareUnique, + newForceNonUnique, idx->indexName()}; // This matches the default for IndexCatalog::refreshEntry(). auto flags = CreateIndexEntryFlags::kIsReady; // Update data format version in storage engine metadata for index. - if (indexUnique) { + if (indexUnique || indexForceNonUnique) { flags = CreateIndexEntryFlags::kIsReady | CreateIndexEntryFlags::kUpdateMetadata; } @@ -254,6 +275,7 @@ void processCollModIndexRequest(OperationContext* opCtx, newUnique, oldPrepareUnique, newPrepareUnique, + newForceNonUnique, result](boost::optional<Timestamp>) { // add the fields to BSONObjBuilder result if (oldExpireSecs) { @@ -276,6 +298,10 @@ void processCollModIndexRequest(OperationContext* opCtx, result->append("prepareUnique_old", *oldPrepareUnique); result->append("prepareUnique_new", *newPrepareUnique); } + if (newForceNonUnique) { + invariant(*newForceNonUnique); + result->appendBool("forceNonUnique_new", true); + } }); if (MONGO_unlikely(assertAfterIndexUpdate.shouldFail())) { diff --git a/src/mongo/db/catalog/coll_mod_index.h b/src/mongo/db/catalog/coll_mod_index.h index acd7849d70e..ed6f24f4dd5 100644 --- a/src/mongo/db/catalog/coll_mod_index.h +++ b/src/mongo/db/catalog/coll_mod_index.h @@ -49,6 +49,7 @@ struct ParsedCollModIndexRequest { boost::optional<bool> indexHidden; boost::optional<bool> indexUnique; boost::optional<bool> indexPrepareUnique; + boost::optional<bool> indexForceNonUnique; }; /** diff --git a/src/mongo/db/catalog/collection.h b/src/mongo/db/catalog/collection.h index aa5bc579c4e..d2e76c12993 100644 --- a/src/mongo/db/catalog/collection.h +++ b/src/mongo/db/catalog/collection.h @@ -604,10 +604,9 @@ public: virtual void updateHiddenSetting(OperationContext* opCtx, StringData idxName, bool hidden) = 0; /* - * Converts the the given index to be unique. - * This is a one-way transformation - the uniqueness constraint cannot be removed. + * Converts the the given index to be unique or non-unique. */ - virtual void updateUniqueSetting(OperationContext* opCtx, StringData idxName) = 0; + virtual void updateUniqueSetting(OperationContext* opCtx, StringData idxName, bool unique) = 0; /* * Disallows or allows new duplicates in the given index. diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp index fa9a7d0dff4..92aec2083c5 100644 --- a/src/mongo/db/catalog/collection_impl.cpp +++ b/src/mongo/db/catalog/collection_impl.cpp @@ -1979,12 +1979,12 @@ void CollectionImpl::updateHiddenSetting(OperationContext* opCtx, StringData idx }); } -void CollectionImpl::updateUniqueSetting(OperationContext* opCtx, StringData idxName) { +void CollectionImpl::updateUniqueSetting(OperationContext* opCtx, StringData idxName, bool unique) { int offset = _metadata->findIndexOffset(idxName); invariant(offset >= 0); _writeMetadata(opCtx, [&](BSONCollectionCatalogEntry::MetaData& md) { - md.indexes[offset].updateUniqueSetting(); + md.indexes[offset].updateUniqueSetting(unique); }); } diff --git a/src/mongo/db/catalog/collection_impl.h b/src/mongo/db/catalog/collection_impl.h index 5c21e188dc1..f89cdf96ede 100644 --- a/src/mongo/db/catalog/collection_impl.h +++ b/src/mongo/db/catalog/collection_impl.h @@ -443,7 +443,7 @@ public: void updateHiddenSetting(OperationContext* opCtx, StringData idxName, bool hidden) final; - void updateUniqueSetting(OperationContext* opCtx, StringData idxName) final; + void updateUniqueSetting(OperationContext* opCtx, StringData idxName, bool unique) final; void updatePrepareUniqueSetting(OperationContext* opCtx, StringData idxName, diff --git a/src/mongo/db/catalog/collection_mock.h b/src/mongo/db/catalog/collection_mock.h index 65529dfd820..6f9f4736af4 100644 --- a/src/mongo/db/catalog/collection_mock.h +++ b/src/mongo/db/catalog/collection_mock.h @@ -411,7 +411,7 @@ public: std::abort(); } - void updateUniqueSetting(OperationContext* opCtx, StringData idxName) { + void updateUniqueSetting(OperationContext* opCtx, StringData idxName, bool unique) { std::abort(); } |