summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/catalog/collection_compact.cpp36
-rw-r--r--src/mongo/db/catalog/database.cpp14
-rw-r--r--src/mongo/db/catalog/index_catalog.cpp123
-rw-r--r--src/mongo/db/catalog/index_catalog.h4
-rw-r--r--src/mongo/db/catalog/index_create.cpp10
-rw-r--r--src/mongo/db/catalog/index_create.h7
-rw-r--r--src/mongo/db/catalog/index_key_validate.cpp40
-rw-r--r--src/mongo/db/cloner.cpp64
-rw-r--r--src/mongo/db/commands/create_indexes.cpp94
-rw-r--r--src/mongo/db/commands/drop_indexes.cpp42
-rw-r--r--src/mongo/db/commands/mr.cpp10
-rw-r--r--src/mongo/db/dbhelpers.cpp4
-rw-r--r--src/mongo/db/dbhelpers.h2
-rw-r--r--src/mongo/db/index/index_descriptor.cpp35
-rw-r--r--src/mongo/db/index/index_descriptor.h29
-rw-r--r--src/mongo/db/index_builder.cpp2
-rw-r--r--src/mongo/db/repair_database.cpp32
-rw-r--r--src/mongo/db/repl/collection_bulk_loader_impl.cpp4
-rw-r--r--src/mongo/db/repl/oplog.cpp31
-rw-r--r--src/mongo/db/repl/rs_rollback_test.cpp9
-rw-r--r--src/mongo/db/repl/storage_interface_impl_test.cpp7
-rw-r--r--src/mongo/db/s/migration_destination_manager.cpp36
-rw-r--r--src/mongo/db/storage/mmap_v1/repair_database.cpp2
-rw-r--r--src/mongo/dbtests/counttests.cpp6
-rw-r--r--src/mongo/dbtests/dbtests.cpp13
-rw-r--r--src/mongo/dbtests/indexcatalogtests.cpp16
-rw-r--r--src/mongo/dbtests/indexupdatetests.cpp74
-rw-r--r--src/mongo/dbtests/multikey_paths_test.cpp31
-rw-r--r--src/mongo/dbtests/query_stage_ixscan.cpp8
-rw-r--r--src/mongo/dbtests/querytests.cpp8
-rw-r--r--src/mongo/dbtests/rollbacktests.cpp24
-rw-r--r--src/mongo/dbtests/validate_tests.cpp28
32 files changed, 582 insertions, 263 deletions
diff --git a/src/mongo/db/catalog/collection_compact.cpp b/src/mongo/db/catalog/collection_compact.cpp
index afba5e94987..a89ce69fbd7 100644
--- a/src/mongo/db/catalog/collection_compact.cpp
+++ b/src/mongo/db/catalog/collection_compact.cpp
@@ -42,6 +42,7 @@
#include "mongo/db/commands/server_status.h"
#include "mongo/db/curop.h"
#include "mongo/db/index/index_access_method.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/operation_context.h"
#include "mongo/util/log.h"
#include "mongo/util/touch_pages.h"
@@ -51,25 +52,32 @@ namespace mongo {
using std::endl;
using std::vector;
+using IndexVersion = IndexDescriptor::IndexVersion;
+
namespace {
BSONObj _compactAdjustIndexSpec(const BSONObj& oldSpec) {
- BSONObjBuilder b;
- BSONObj::iterator i(oldSpec);
- while (i.more()) {
- BSONElement e = i.next();
- if (str::equals(e.fieldName(), "v")) {
- // Drop any preexisting index version spec. The default index version will
- // be used instead for the new index.
- continue;
- }
- if (str::equals(e.fieldName(), "background")) {
+ BSONObjBuilder bob;
+
+ for (auto&& indexSpecElem : oldSpec) {
+ auto indexSpecElemFieldName = indexSpecElem.fieldNameStringData();
+ if (IndexDescriptor::kIndexVersionFieldName == indexSpecElemFieldName) {
+ IndexVersion indexVersion = static_cast<IndexVersion>(indexSpecElem.numberInt());
+ if (IndexVersion::kV0 == indexVersion) {
+ // We automatically upgrade v=0 indexes to v=1 indexes.
+ bob.append(IndexDescriptor::kIndexVersionFieldName,
+ static_cast<int>(IndexVersion::kV1));
+ } else {
+ bob.append(IndexDescriptor::kIndexVersionFieldName, static_cast<int>(indexVersion));
+ }
+ } else if (IndexDescriptor::kBackgroundFieldName == indexSpecElemFieldName) {
// Create the new index in the foreground.
continue;
+ } else {
+ bob.append(indexSpecElem);
}
- // Pass the element through to the new index spec.
- b.append(e);
}
- return b.obj();
+
+ return bob.obj();
}
class MyCompactAdaptor : public RecordStoreCompactAdaptor {
@@ -182,7 +190,7 @@ StatusWith<CompactStats> Collection::compact(OperationContext* txn,
indexer.allowInterruption();
indexer.ignoreUniqueConstraint(); // in compact we should be doing no checking
- Status status = indexer.init(indexSpecs);
+ Status status = indexer.init(indexSpecs).getStatus();
if (!status.isOK())
return StatusWith<CompactStats>(status);
diff --git a/src/mongo/db/catalog/database.cpp b/src/mongo/db/catalog/database.cpp
index feb4111edac..005a4f23abf 100644
--- a/src/mongo/db/catalog/database.cpp
+++ b/src/mongo/db/catalog/database.cpp
@@ -56,6 +56,7 @@
#include "mongo/db/query/collation/collator_factory_interface.h"
#include "mongo/db/repl/oplog.h"
#include "mongo/db/repl/replication_coordinator_global.h"
+#include "mongo/db/server_options.h"
#include "mongo/db/server_parameters.h"
#include "mongo/db/service_context.h"
#include "mongo/db/service_context_d.h"
@@ -576,8 +577,19 @@ Collection* Database::createCollection(OperationContext* txn,
if (collection->requiresIdIndex()) {
if (options.autoIndexId == CollectionOptions::YES ||
options.autoIndexId == CollectionOptions::DEFAULT) {
+ // The creation of the _id index isn't replicated and is instead implicit in the
+ // creation of the collection. This means that the version of the _id index to build
+ // is technically unspecified. However, we're able to use the
+ // featureCompatibilityVersion of this server to determine the default index version
+ // to use because we apply commands (opType == 'c') in their own batch. This
+ // guarantees the write to the admin.system.version collection from the
+ // "setFeatureCompatibilityVersion" command either happens entirely before the
+ // collection creation or it happens entirely after.
+ const auto featureCompatibilityVersion =
+ serverGlobalParams.featureCompatibilityVersion.load();
IndexCatalog* ic = collection->getIndexCatalog();
- uassertStatusOK(ic->createIndexOnEmptyCollection(txn, ic->getDefaultIdIndexSpec()));
+ uassertStatusOK(ic->createIndexOnEmptyCollection(
+ txn, ic->getDefaultIdIndexSpec(featureCompatibilityVersion)));
}
}
diff --git a/src/mongo/db/catalog/index_catalog.cpp b/src/mongo/db/catalog/index_catalog.cpp
index 02158d2d6db..123f7722024 100644
--- a/src/mongo/db/catalog/index_catalog.cpp
+++ b/src/mongo/db/catalog/index_catalog.cpp
@@ -59,6 +59,7 @@
#include "mongo/db/matcher/extensions_callback_disallow_extensions.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/ops/delete.h"
+#include "mongo/db/query/collation/collation_spec.h"
#include "mongo/db/query/collation/collator_factory_interface.h"
#include "mongo/db/query/internal_plans.h"
#include "mongo/db/repl/replication_coordinator_global.h"
@@ -468,36 +469,41 @@ Status IndexCatalog::_isSpecOk(OperationContext* txn, const BSONObj& spec) const
const NamespaceString& nss = _collection->ns();
BSONElement vElt = spec["v"];
- if (!vElt.eoo()) {
- if (!vElt.isNumber()) {
- return Status(ErrorCodes::CannotCreateIndex,
- str::stream() << "non-numeric value for \"v\" field: " << vElt);
- }
+ if (!vElt) {
+ return {ErrorCodes::InternalError,
+ str::stream()
+ << "An internal operation failed to specify the 'v' field, which is a required "
+ "property of an index specification: "
+ << spec};
+ }
- auto vEltAsInt = representAs<int>(vElt.number());
- if (!vEltAsInt) {
- return {
- ErrorCodes::CannotCreateIndex,
+ if (!vElt.isNumber()) {
+ return Status(ErrorCodes::CannotCreateIndex,
+ str::stream() << "non-numeric value for \"v\" field: " << vElt);
+ }
+
+ auto vEltAsInt = representAs<int>(vElt.number());
+ if (!vEltAsInt) {
+ return {ErrorCodes::CannotCreateIndex,
str::stream() << "Index version must be representable as a 32-bit integer, but got "
<< vElt.toString(false, false)};
- }
+ }
- auto indexVersion = static_cast<IndexVersion>(*vEltAsInt);
+ auto indexVersion = static_cast<IndexVersion>(*vEltAsInt);
- // SERVER-16893 Forbid use of v0 indexes with non-mmapv1 engines
- if (indexVersion == IndexVersion::kV0 &&
- !txn->getServiceContext()->getGlobalStorageEngine()->isMmapV1()) {
- return Status(ErrorCodes::CannotCreateIndex,
- str::stream() << "use of v0 indexes is only allowed with the "
- << "mmapv1 storage engine");
- }
+ // SERVER-16893 Forbid use of v0 indexes with non-mmapv1 engines
+ if (indexVersion == IndexVersion::kV0 &&
+ !txn->getServiceContext()->getGlobalStorageEngine()->isMmapV1()) {
+ return Status(ErrorCodes::CannotCreateIndex,
+ str::stream() << "use of v0 indexes is only allowed with the "
+ << "mmapv1 storage engine");
+ }
- if (!IndexDescriptor::isIndexVersionSupported(indexVersion)) {
- return Status(ErrorCodes::CannotCreateIndex,
- str::stream() << "this version of mongod cannot build new indexes "
- << "of version number "
- << static_cast<int>(indexVersion));
- }
+ if (!IndexDescriptor::isIndexVersionSupported(indexVersion)) {
+ return Status(ErrorCodes::CannotCreateIndex,
+ str::stream() << "this version of mongod cannot build new indexes "
+ << "of version number "
+ << static_cast<int>(indexVersion));
}
if (nss.isSystemDotIndexes())
@@ -566,7 +572,15 @@ Status IndexCatalog::_isSpecOk(OperationContext* txn, const BSONObj& spec) const
}
collator = std::move(statusWithCollator.getValue());
- if (vElt && static_cast<IndexVersion>(vElt.numberInt()) < IndexVersion::kV2) {
+ if (!collator) {
+ return {ErrorCodes::InternalError,
+ str::stream() << "An internal operation specified the collation "
+ << CollationSpec::kSimpleSpec
+ << " explicitly, which should instead be implied by omitting the "
+ "'collation' field from the index specification"};
+ }
+
+ if (static_cast<IndexVersion>(vElt.numberInt()) < IndexVersion::kV2) {
return {ErrorCodes::CannotCreateIndex,
str::stream() << "Index version " << vElt.fieldNameStringData() << "="
<< vElt.numberInt()
@@ -576,8 +590,8 @@ Status IndexCatalog::_isSpecOk(OperationContext* txn, const BSONObj& spec) const
}
string pluginName = IndexNames::findPluginName(key);
- if (collator && (pluginName != IndexNames::BTREE) &&
- (pluginName != IndexNames::GEO_2DSPHERE) && (pluginName != IndexNames::HASHED)) {
+ if ((pluginName != IndexNames::BTREE) && (pluginName != IndexNames::GEO_2DSPHERE) &&
+ (pluginName != IndexNames::HASHED)) {
return Status(ErrorCodes::CannotCreateIndex,
str::stream() << "Index type '" << pluginName
<< "' does not support collation: "
@@ -769,13 +783,21 @@ Status IndexCatalog::_doesSpecConflictWithExisting(OperationContext* txn,
return Status::OK();
}
-BSONObj IndexCatalog::getDefaultIdIndexSpec() const {
+BSONObj IndexCatalog::getDefaultIdIndexSpec(
+ ServerGlobalParams::FeatureCompatibilityVersions featureCompatibilityVersion) const {
dassert(_idObj["_id"].type() == NumberInt);
+ const auto indexVersion = IndexDescriptor::getDefaultIndexVersion(featureCompatibilityVersion);
+
BSONObjBuilder b;
+ b.append("v", static_cast<int>(indexVersion));
b.append("name", "_id_");
b.append("ns", _collection->ns().ns());
b.append("key", _idObj);
+ if (_collection->getDefaultCollator() && indexVersion >= IndexVersion::kV2) {
+ // Creating an index with the "collation" option requires a v=2 index.
+ b.append("collation", _collection->getDefaultCollator()->getSpec().toBSON());
+ }
return b.obj();
}
@@ -1353,16 +1375,12 @@ StatusWith<BSONObj> IndexCatalog::_fixIndexSpec(OperationContext* txn,
BSONObjBuilder b;
- auto indexVersion = IndexDescriptor::getDefaultIndexVersion(
- serverGlobalParams.featureCompatibilityVersion.load());
- if (!o["v"].eoo()) {
- // We've already verified in IndexCatalog::_isSpecOk() that the index version is
- // representable as a 32-bit integer.
- indexVersion = static_cast<IndexVersion>(o["v"].numberInt());
- }
+ // We've already verified in IndexCatalog::_isSpecOk() that the index version is present and
+ // that it is representable as a 32-bit integer.
+ auto vElt = o["v"];
+ invariant(vElt);
- // idea is to put things we use a lot earlier
- b.append("v", static_cast<int>(indexVersion));
+ b.append("v", vElt.numberInt());
if (o["unique"].trueValue())
b.appendBool("unique", true); // normalize to bool true in case was int 1 or something...
@@ -1376,35 +1394,6 @@ StatusWith<BSONObj> IndexCatalog::_fixIndexSpec(OperationContext* txn,
}
b.append("name", name);
- if (auto collationElt = spec["collation"]) {
- // This should already have been verified by _isSpecOk().
- invariant(collationElt.type() == BSONType::Object);
-
- auto collator = CollatorFactoryInterface::get(txn->getServiceContext())
- ->makeFromBSON(collationElt.Obj());
- if (!collator.isOK()) {
- return collator.getStatus();
- }
-
- // If the collator factory returned a non-null collator, set the collation option to the
- // result of serializing the collator's spec back into BSON. We do this in order to fill in
- // all options that the user omitted.
- //
- // If the collator factory returned a null collator (representing the "simple" collation),
- // we simply omit the "collation" from the index spec. This ensures that indices with the
- // simple collation built on versions which do not support the collation feature have the
- // same format for representing the simple collation as indices built on this version.
- if (collator.getValue()) {
- b.append("collation", collator.getValue()->getSpec().toBSON());
- }
- } else if (collection->getDefaultCollator() && indexVersion >= IndexVersion::kV2) {
- // The user did not specify an explicit collation for this index and the collection has a
- // default collator. If we're building a v=2 index, then we should inherit the collection
- // default. However, if we're building a v=1 index, then we're implicitly building an index
- // that's using the "simple" collation.
- b.append("collation", collection->getDefaultCollator()->getSpec().toBSON());
- }
-
{
BSONObjIterator i(o);
while (i.more()) {
@@ -1415,7 +1404,7 @@ StatusWith<BSONObj> IndexCatalog::_fixIndexSpec(OperationContext* txn,
// skip
} else if (s == "dropDups") {
// dropDups is silently ignored and removed from the spec as of SERVER-14710.
- } else if (s == "v" || s == "unique" || s == "key" || s == "name" || s == "collation") {
+ } else if (s == "v" || s == "unique" || s == "key" || s == "name") {
// covered above
} else {
b.append(e);
diff --git a/src/mongo/db/catalog/index_catalog.h b/src/mongo/db/catalog/index_catalog.h
index 37ec3305615..4ff19ddd60f 100644
--- a/src/mongo/db/catalog/index_catalog.h
+++ b/src/mongo/db/catalog/index_catalog.h
@@ -37,6 +37,7 @@
#include "mongo/db/jsobj.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/record_id.h"
+#include "mongo/db/server_options.h"
#include "mongo/db/storage/record_store.h"
#include "mongo/platform/unordered_map.h"
@@ -81,7 +82,8 @@ public:
/**
* Returns the spec for the id index to create by default for this collection.
*/
- BSONObj getDefaultIdIndexSpec() const;
+ BSONObj getDefaultIdIndexSpec(
+ ServerGlobalParams::FeatureCompatibilityVersions featureCompatibilityVersion) const;
IndexDescriptor* findIdIndex(OperationContext* txn) const;
diff --git a/src/mongo/db/catalog/index_create.cpp b/src/mongo/db/catalog/index_create.cpp
index 7f27589085d..8549b4f8b0c 100644
--- a/src/mongo/db/catalog/index_create.cpp
+++ b/src/mongo/db/catalog/index_create.cpp
@@ -147,12 +147,12 @@ void MultiIndexBlock::removeExistingIndexes(std::vector<BSONObj>* specs) const {
}
}
-Status MultiIndexBlock::init(const BSONObj& spec) {
+StatusWith<std::vector<BSONObj>> MultiIndexBlock::init(const BSONObj& spec) {
const auto indexes = std::vector<BSONObj>(1, spec);
return init(indexes);
}
-Status MultiIndexBlock::init(const std::vector<BSONObj>& indexSpecs) {
+StatusWith<std::vector<BSONObj>> MultiIndexBlock::init(const std::vector<BSONObj>& indexSpecs) {
WriteUnitOfWork wunit(_txn);
invariant(_indexes.empty());
@@ -182,6 +182,9 @@ Status MultiIndexBlock::init(const std::vector<BSONObj>& indexSpecs) {
_buildInBackground = (_buildInBackground && info["background"].trueValue());
}
+ std::vector<BSONObj> indexInfoObjs;
+ indexInfoObjs.reserve(indexSpecs.size());
+
for (size_t i = 0; i < indexSpecs.size(); i++) {
BSONObj info = indexSpecs[i];
StatusWith<BSONObj> statusWithInfo =
@@ -190,6 +193,7 @@ Status MultiIndexBlock::init(const std::vector<BSONObj>& indexSpecs) {
if (!status.isOK())
return status;
info = statusWithInfo.getValue();
+ indexInfoObjs.push_back(info);
IndexToBuild index;
index.block.reset(new IndexCatalog::IndexBuildBlock(_txn, _collection, info));
@@ -241,7 +245,7 @@ Status MultiIndexBlock::init(const std::vector<BSONObj>& indexSpecs) {
}
}
- return Status::OK();
+ return indexInfoObjs;
}
Status MultiIndexBlock::insertAllDocumentsInCollection(std::set<RecordId>* dupsOut) {
diff --git a/src/mongo/db/catalog/index_create.h b/src/mongo/db/catalog/index_create.h
index e5f18a42ed3..88dd5db8393 100644
--- a/src/mongo/db/catalog/index_create.h
+++ b/src/mongo/db/catalog/index_create.h
@@ -106,14 +106,15 @@ public:
void removeExistingIndexes(std::vector<BSONObj>* specs) const;
/**
- * Prepares the index(es) for building.
+ * Prepares the index(es) for building and returns the canonicalized form of the requested index
+ * specifications.
*
* Does not need to be called inside of a WriteUnitOfWork (but can be due to nesting).
*
* Requires holding an exclusive database lock.
*/
- Status init(const std::vector<BSONObj>& specs);
- Status init(const BSONObj& spec);
+ StatusWith<std::vector<BSONObj>> init(const std::vector<BSONObj>& specs);
+ StatusWith<std::vector<BSONObj>> init(const BSONObj& spec);
/**
* Inserts all documents in the Collection into the indexes and logs with timing info.
diff --git a/src/mongo/db/catalog/index_key_validate.cpp b/src/mongo/db/catalog/index_key_validate.cpp
index 44c2db2d5e7..c211d22b1d4 100644
--- a/src/mongo/db/catalog/index_key_validate.cpp
+++ b/src/mongo/db/catalog/index_key_validate.cpp
@@ -50,13 +50,6 @@ using std::string;
using IndexVersion = IndexDescriptor::IndexVersion;
-namespace {
-const StringData kKeyPatternFieldName = "key"_sd;
-const StringData kNamespaceFieldName = "ns"_sd;
-const StringData kVersionFieldName = "v"_sd;
-const StringData kCollationFieldName = "collation"_sd;
-} // namespace
-
Status validateKeyPattern(const BSONObj& key) {
const ErrorCodes::Error code = ErrorCodes::CannotCreateIndex;
@@ -158,10 +151,10 @@ StatusWith<BSONObj> validateIndexSpec(
for (auto&& indexSpecElem : indexSpec) {
auto indexSpecElemFieldName = indexSpecElem.fieldNameStringData();
- if (kKeyPatternFieldName == indexSpecElemFieldName) {
+ if (IndexDescriptor::kKeyPatternFieldName == indexSpecElemFieldName) {
if (indexSpecElem.type() != BSONType::Object) {
return {ErrorCodes::TypeMismatch,
- str::stream() << "The field '" << kKeyPatternFieldName
+ str::stream() << "The field '" << IndexDescriptor::kKeyPatternFieldName
<< "' must be an object, but got "
<< typeName(indexSpecElem.type())};
}
@@ -179,10 +172,10 @@ StatusWith<BSONObj> validateIndexSpec(
}
hasKeyPatternField = true;
- } else if (kNamespaceFieldName == indexSpecElemFieldName) {
+ } else if (IndexDescriptor::kNamespaceFieldName == indexSpecElemFieldName) {
if (indexSpecElem.type() != BSONType::String) {
return {ErrorCodes::TypeMismatch,
- str::stream() << "The field '" << kNamespaceFieldName
+ str::stream() << "The field '" << IndexDescriptor::kNamespaceFieldName
<< "' must be a string, but got "
<< typeName(indexSpecElem.type())};
}
@@ -190,13 +183,15 @@ StatusWith<BSONObj> validateIndexSpec(
StringData ns = indexSpecElem.valueStringData();
if (ns.empty()) {
return {ErrorCodes::BadValue,
- str::stream() << "The field '" << kNamespaceFieldName
+ str::stream() << "The field '" << IndexDescriptor::kNamespaceFieldName
<< "' cannot be an empty string"};
}
if (ns != expectedNamespace.ns()) {
return {ErrorCodes::BadValue,
- str::stream() << "The value of the field '" << kNamespaceFieldName << "' ("
+ str::stream() << "The value of the field '"
+ << IndexDescriptor::kNamespaceFieldName
+ << "' ("
<< ns
<< ") doesn't match the namespace '"
<< expectedNamespace.ns()
@@ -204,10 +199,10 @@ StatusWith<BSONObj> validateIndexSpec(
}
hasNamespaceField = true;
- } else if (kVersionFieldName == indexSpecElemFieldName) {
+ } else if (IndexDescriptor::kIndexVersionFieldName == indexSpecElemFieldName) {
if (!indexSpecElem.isNumber()) {
return {ErrorCodes::TypeMismatch,
- str::stream() << "The field '" << kVersionFieldName
+ str::stream() << "The field '" << IndexDescriptor::kIndexVersionFieldName
<< "' must be a number, but got "
<< typeName(indexSpecElem.type())};
}
@@ -230,10 +225,10 @@ StatusWith<BSONObj> validateIndexSpec(
hasVersionField = true;
resolvedIndexVersion = requestedIndexVersion;
- } else if (kCollationFieldName == indexSpecElemFieldName) {
+ } else if (IndexDescriptor::kCollationFieldName == indexSpecElemFieldName) {
if (indexSpecElem.type() != BSONType::Object) {
return {ErrorCodes::TypeMismatch,
- str::stream() << "The field '" << kNamespaceFieldName
+ str::stream() << "The field '" << IndexDescriptor::kNamespaceFieldName
<< "' must be an object, but got "
<< typeName(indexSpecElem.type())};
}
@@ -251,7 +246,7 @@ StatusWith<BSONObj> validateIndexSpec(
if (!hasKeyPatternField) {
return {ErrorCodes::FailedToParse,
- str::stream() << "The '" << kKeyPatternFieldName
+ str::stream() << "The '" << IndexDescriptor::kKeyPatternFieldName
<< "' field is a required property of an index specification"};
}
@@ -259,9 +254,9 @@ StatusWith<BSONObj> validateIndexSpec(
return {ErrorCodes::CannotCreateIndex,
str::stream() << "Invalid index specification " << indexSpec
<< "; cannot create an index with the '"
- << kCollationFieldName
+ << IndexDescriptor::kCollationFieldName
<< "' option and "
- << kVersionFieldName
+ << IndexDescriptor::kIndexVersionFieldName
<< "="
<< static_cast<int>(*resolvedIndexVersion)};
}
@@ -272,13 +267,14 @@ StatusWith<BSONObj> validateIndexSpec(
if (!hasNamespaceField) {
// We create a new index specification with the 'ns' field set as 'expectedNamespace' if
// the field was omitted.
- bob.append(kNamespaceFieldName, expectedNamespace.ns());
+ bob.append(IndexDescriptor::kNamespaceFieldName, expectedNamespace.ns());
}
if (!hasVersionField) {
// We create a new index specification with the 'v' field set as 'defaultIndexVersion'
// if the field was omitted.
- bob.append(kVersionFieldName, static_cast<int>(*resolvedIndexVersion));
+ bob.append(IndexDescriptor::kIndexVersionFieldName,
+ static_cast<int>(*resolvedIndexVersion));
}
bob.appendElements(indexSpec);
diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp
index 249b807ab53..e935e38b9f7 100644
--- a/src/mongo/db/cloner.cpp
+++ b/src/mongo/db/cloner.cpp
@@ -52,6 +52,7 @@
#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/dbhelpers.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/index_builder.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/namespace_string.h"
@@ -75,6 +76,8 @@ using std::string;
using std::unique_ptr;
using std::vector;
+using IndexVersion = IndexDescriptor::IndexVersion;
+
MONGO_EXPORT_SERVER_PARAMETER(skipCorruptDocumentsWhenCloning, bool, false);
BSONElement getErrField(const BSONObj& o);
@@ -84,33 +87,32 @@ BSONElement getErrField(const BSONObj& o);
we need to fix up the value in the "ns" parameter so that the name prefix is correct on a
copy to a new name.
*/
-BSONObj fixindex(const string& newDbName, BSONObj o) {
- BSONObjBuilder b;
- BSONObjIterator i(o);
- while (i.moreWithEOO()) {
- BSONElement e = i.next();
- if (e.eoo())
- break;
-
- // for now, skip the "v" field so that v:0 indexes will be upgraded to v:1
- if (string("v") == e.fieldName()) {
- continue;
- }
-
- if (string("ns") == e.fieldName()) {
- uassert(10024, "bad ns field for index during dbcopy", e.type() == String);
- const char* p = strchr(e.valuestr(), '.');
+BSONObj fixIndexSpec(const string& newDbName, BSONObj indexSpec) {
+ BSONObjBuilder bob;
+
+ for (auto&& indexSpecElem : indexSpec) {
+ auto indexSpecElemFieldName = indexSpecElem.fieldNameStringData();
+ if (IndexDescriptor::kIndexVersionFieldName == indexSpecElemFieldName) {
+ IndexVersion indexVersion = static_cast<IndexVersion>(indexSpecElem.numberInt());
+ if (IndexVersion::kV0 == indexVersion) {
+ // We automatically upgrade v=0 indexes to v=1 indexes.
+ bob.append(IndexDescriptor::kIndexVersionFieldName,
+ static_cast<int>(IndexVersion::kV1));
+ } else {
+ bob.append(IndexDescriptor::kIndexVersionFieldName, static_cast<int>(indexVersion));
+ }
+ } else if (IndexDescriptor::kNamespaceFieldName == indexSpecElemFieldName) {
+ uassert(10024, "bad ns field for index during dbcopy", indexSpecElem.type() == String);
+ const char* p = strchr(indexSpecElem.valuestr(), '.');
uassert(10025, "bad ns field for index during dbcopy [2]", p);
string newname = newDbName + p;
- b.append("ns", newname);
+ bob.append(IndexDescriptor::kNamespaceFieldName, newname);
} else {
- b.append(e);
+ bob.append(indexSpecElem);
}
}
- BSONObj res = b.obj();
-
- return res;
+ return bob.obj();
}
Cloner::Cloner() {}
@@ -328,7 +330,7 @@ void Cloner::copyIndexes(OperationContext* txn,
_conn->getIndexSpecs(from_collection.ns(), slaveOk ? QueryOption_SlaveOk : 0);
for (list<BSONObj>::const_iterator it = sourceIndexes.begin(); it != sourceIndexes.end();
++it) {
- indexesToBuild.push_back(fixindex(to_collection.db().toString(), *it));
+ indexesToBuild.push_back(fixIndexSpec(to_collection.db().toString(), *it));
}
}
@@ -375,7 +377,7 @@ void Cloner::copyIndexes(OperationContext* txn,
if (indexesToBuild.empty())
return;
- uassertStatusOK(indexer.init(indexesToBuild));
+ auto indexInfoObjs = uassertStatusOK(indexer.init(indexesToBuild));
uassertStatusOK(indexer.insertAllDocumentsInCollection());
WriteUnitOfWork wunit(txn);
@@ -383,10 +385,8 @@ void Cloner::copyIndexes(OperationContext* txn,
if (txn->writesAreReplicated()) {
const string targetSystemIndexesCollectionName = to_collection.getSystemIndexesCollection();
const char* createIndexNs = targetSystemIndexesCollectionName.c_str();
- for (vector<BSONObj>::const_iterator it = indexesToBuild.begin();
- it != indexesToBuild.end();
- ++it) {
- getGlobalServiceContext()->getOpObserver()->onCreateIndex(txn, createIndexNs, *it);
+ for (auto&& infoObj : indexInfoObjs) {
+ getGlobalServiceContext()->getOpObserver()->onCreateIndex(txn, createIndexNs, infoObj);
}
}
wunit.commit();
@@ -674,7 +674,11 @@ Status Cloner::copyDb(OperationContext* txn,
MultiIndexBlock indexer(txn, c);
indexer.allowInterruption();
- uassertStatusOK(indexer.init(c->getIndexCatalog()->getDefaultIdIndexSpec()));
+ const auto featureCompatibilityVersion =
+ serverGlobalParams.featureCompatibilityVersion.load();
+ auto indexInfoObjs = uassertStatusOK(indexer.init(
+ c->getIndexCatalog()->getDefaultIdIndexSpec(featureCompatibilityVersion)));
+ invariant(indexInfoObjs.size() == 1);
uassertStatusOK(indexer.insertAllDocumentsInCollection(&dups));
// This must be done before we commit the indexer. See the comment about
@@ -694,9 +698,7 @@ Status Cloner::copyDb(OperationContext* txn,
indexer.commit();
if (txn->writesAreReplicated()) {
getGlobalServiceContext()->getOpObserver()->onCreateIndex(
- txn,
- c->ns().getSystemIndexesCollection().c_str(),
- c->getIndexCatalog()->getDefaultIdIndexSpec());
+ txn, c->ns().getSystemIndexesCollection().c_str(), indexInfoObjs[0]);
}
wunit.commit();
}
diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp
index fc0c78b8e3a..176b6a84b6d 100644
--- a/src/mongo/db/commands/create_indexes.cpp
+++ b/src/mongo/db/commands/create_indexes.cpp
@@ -42,8 +42,10 @@
#include "mongo/db/commands.h"
#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/curop.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/op_observer.h"
#include "mongo/db/ops/insert.h"
+#include "mongo/db/query/collation/collator_factory_interface.h"
#include "mongo/db/repl/repl_client_info.h"
#include "mongo/db/repl/replication_coordinator_global.h"
#include "mongo/db/s/collection_metadata.h"
@@ -58,6 +60,8 @@ namespace mongo {
using std::string;
+using IndexVersion = IndexDescriptor::IndexVersion;
+
namespace {
const StringData kIndexesFieldName = "indexes"_sd;
@@ -121,6 +125,79 @@ StatusWith<std::vector<BSONObj>> parseAndValidateIndexSpecs(
return indexSpecs;
}
+/**
+ * Returns index specifications with attributes (such as "collation") that are inherited from the
+ * collection filled in.
+ *
+ * The returned index specifications will not be equivalent to the ones specified as 'indexSpecs' if
+ * any missing attributes were filled in; however, the returned index specifications will match the
+ * form stored in the IndexCatalog should any of these indexes already exist.
+ */
+StatusWith<std::vector<BSONObj>> resolveCollectionDefaultProperties(
+ OperationContext* txn, const Collection* collection, std::vector<BSONObj> indexSpecs) {
+ std::vector<BSONObj> indexSpecsWithDefaults = std::move(indexSpecs);
+
+ for (size_t i = 0, numIndexSpecs = indexSpecsWithDefaults.size(); i < numIndexSpecs; ++i) {
+ const BSONObj& indexSpec = indexSpecsWithDefaults[i];
+ if (auto collationElem = indexSpec[IndexDescriptor::kCollationFieldName]) {
+ // validateIndexSpec() should have already verified that 'collationElem' is an object.
+ invariant(collationElem.type() == BSONType::Object);
+
+ auto collator = CollatorFactoryInterface::get(txn->getServiceContext())
+ ->makeFromBSON(collationElem.Obj());
+ if (!collator.isOK()) {
+ return collator.getStatus();
+ }
+
+ if (collator.getValue()) {
+ // If the collator factory returned a non-null collator, then inject the entire
+ // collation specification into the index specification. This is necessary to fill
+ // in any options that the user omitted.
+ BSONObjBuilder bob;
+
+ for (auto&& indexSpecElem : indexSpec) {
+ if (IndexDescriptor::kCollationFieldName !=
+ indexSpecElem.fieldNameStringData()) {
+ bob.append(indexSpecElem);
+ }
+ }
+ bob.append(IndexDescriptor::kCollationFieldName,
+ collator.getValue()->getSpec().toBSON());
+
+ indexSpecsWithDefaults[i] = bob.obj();
+ } else {
+ // If the collator factory returned a null collator (representing the "simple"
+ // collation), then we simply omit the "collation" from the index specification.
+ // This is desirable to make the representation for the "simple" collation
+ // consistent between v=1 and v=2 indexes.
+ indexSpecsWithDefaults[i] =
+ indexSpec.removeField(IndexDescriptor::kCollationFieldName);
+ }
+ } else if (collection->getDefaultCollator()) {
+ // validateIndexSpec() should have added the "v" field if it was not present and
+ // verified that 'versionElem' is a number.
+ auto versionElem = indexSpec[IndexDescriptor::kIndexVersionFieldName];
+ invariant(versionElem.isNumber());
+
+ if (IndexVersion::kV2 <= static_cast<IndexVersion>(versionElem.numberInt())) {
+ // The user did not specify an explicit collation for this index and the collection
+ // has a default collator. If we're building a v=2 index, then we should inherit the
+ // collection default. However, if we're building a v=1 index, then we're implicitly
+ // building an index that's using the "simple" collation.
+ BSONObjBuilder bob;
+
+ bob.appendElements(indexSpec);
+ bob.append(IndexDescriptor::kCollationFieldName,
+ collection->getDefaultCollator()->getSpec().toBSON());
+
+ indexSpecsWithDefaults[i] = bob.obj();
+ }
+ }
+ }
+
+ return indexSpecsWithDefaults;
+}
+
} // namespace
/**
@@ -203,6 +280,13 @@ public:
result.appendBool("createdCollectionAutomatically", true);
}
+ auto indexSpecsWithDefaults =
+ resolveCollectionDefaultProperties(txn, collection, std::move(specs));
+ if (!indexSpecsWithDefaults.isOK()) {
+ return appendCommandStatus(result, indexSpecsWithDefaults.getStatus());
+ }
+ specs = std::move(indexSpecsWithDefaults.getValue());
+
const int numIndexesBefore = collection->getIndexCatalog()->numIndexesTotal(txn);
result.append("numIndexesBefore", numIndexesBefore);
@@ -240,8 +324,9 @@ public:
}
}
+ std::vector<BSONObj> indexInfoObjs;
MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
- uassertStatusOK(indexer.init(specs));
+ indexInfoObjs = uassertStatusOK(indexer.init(specs));
}
MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "createIndexes", ns.ns());
@@ -306,11 +391,12 @@ public:
indexer.commit();
- for (size_t i = 0; i < specs.size(); i++) {
+ for (auto&& infoObj : indexInfoObjs) {
std::string systemIndexes = ns.getSystemIndexesCollection();
auto opObserver = getGlobalServiceContext()->getOpObserver();
- if (opObserver)
- opObserver->onCreateIndex(txn, systemIndexes, specs[i]);
+ if (opObserver) {
+ opObserver->onCreateIndex(txn, systemIndexes, infoObj);
+ }
}
wunit.commit();
diff --git a/src/mongo/db/commands/drop_indexes.cpp b/src/mongo/db/commands/drop_indexes.cpp
index 347e3762d9e..cdca8e10bcb 100644
--- a/src/mongo/db/commands/drop_indexes.cpp
+++ b/src/mongo/db/commands/drop_indexes.cpp
@@ -144,14 +144,38 @@ public:
BackgroundOperation::assertNoBgOpInProgForNs(toReIndexNs.ns());
+ const auto featureCompatibilityVersion =
+ serverGlobalParams.featureCompatibilityVersion.load();
+ const auto defaultIndexVersion =
+ IndexDescriptor::getDefaultIndexVersion(featureCompatibilityVersion);
+
vector<BSONObj> all;
{
vector<string> indexNames;
collection->getCatalogEntry()->getAllIndexes(txn, &indexNames);
+ all.reserve(indexNames.size());
+
for (size_t i = 0; i < indexNames.size(); i++) {
const string& name = indexNames[i];
BSONObj spec = collection->getCatalogEntry()->getIndexSpec(txn, name);
- all.push_back(spec.removeField("v").getOwned());
+
+ {
+ BSONObjBuilder bob;
+
+ for (auto&& indexSpecElem : spec) {
+ auto indexSpecElemFieldName = indexSpecElem.fieldNameStringData();
+ if (IndexDescriptor::kIndexVersionFieldName == indexSpecElemFieldName) {
+ // We create a new index specification with the 'v' field set as
+ // 'defaultIndexVersion'.
+ bob.append(IndexDescriptor::kIndexVersionFieldName,
+ static_cast<int>(defaultIndexVersion));
+ } else {
+ bob.append(indexSpecElem);
+ }
+ }
+
+ all.push_back(bob.obj());
+ }
const BSONObj key = spec.getObjectField("key");
const Status keyStatus = validateKeyPattern(key);
@@ -179,13 +203,15 @@ public:
MultiIndexBlock indexer(txn, collection);
// do not want interruption as that will leave us without indexes.
- Status status = indexer.init(all);
- if (!status.isOK())
- return appendCommandStatus(result, status);
+ auto indexInfoObjs = indexer.init(all);
+ if (!indexInfoObjs.isOK()) {
+ return appendCommandStatus(result, indexInfoObjs.getStatus());
+ }
- status = indexer.insertAllDocumentsInCollection();
- if (!status.isOK())
+ auto status = indexer.insertAllDocumentsInCollection();
+ if (!status.isOK()) {
return appendCommandStatus(result, status);
+ }
{
WriteUnitOfWork wunit(txn);
@@ -202,8 +228,8 @@ public:
replCoord->forceSnapshotCreation(); // Ensures a newer snapshot gets created even if idle.
collection->setMinimumVisibleSnapshot(snapshotName);
- result.append("nIndexes", (int)all.size());
- result.append("indexes", all);
+ result.append("nIndexes", static_cast<int>(indexInfoObjs.getValue().size()));
+ result.append("indexes", indexInfoObjs.getValue());
return true;
}
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp
index e4efbba4d2f..eb304a56f49 100644
--- a/src/mongo/db/commands/mr.cpp
+++ b/src/mongo/db/commands/mr.cpp
@@ -94,6 +94,8 @@ using std::stringstream;
using std::unique_ptr;
using std::vector;
+using IndexVersion = IndexDescriptor::IndexVersion;
+
namespace dps = ::mongo::dotted_path_support;
namespace mr {
@@ -414,8 +416,14 @@ void State::prepTempCollection() {
incColl = incCtx.db()->createCollection(_txn, _config.incLong, options);
invariant(incColl);
+ // We explicitly create a v=2 index on the "0" field so that it is always possible for a
+ // user to emit() decimal keys. Since the incremental collection is not replicated to
+ // any secondaries, there is no risk of inadvertently crashing an older version of
+ // MongoDB when the featureCompatibilityVersion of this server is 3.2.
BSONObj indexSpec = BSON("key" << BSON("0" << 1) << "ns" << _config.incLong << "name"
- << "_temp_0");
+ << "_temp_0"
+ << "v"
+ << static_cast<int>(IndexVersion::kV2));
Status status =
incColl->getIndexCatalog()->createIndexOnEmptyCollection(_txn, indexSpec);
if (!status.isOK()) {
diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp
index fa728c3bdca..53e73c11119 100644
--- a/src/mongo/db/dbhelpers.cpp
+++ b/src/mongo/db/dbhelpers.cpp
@@ -85,18 +85,20 @@ using logger::LogComponent;
void Helpers::ensureIndex(OperationContext* txn,
Collection* collection,
BSONObj keyPattern,
+ IndexDescriptor::IndexVersion indexVersion,
bool unique,
const char* name) {
BSONObjBuilder b;
b.append("name", name);
b.append("ns", collection->ns().ns());
b.append("key", keyPattern);
+ b.append("v", static_cast<int>(indexVersion));
b.appendBool("unique", unique);
BSONObj o = b.done();
MultiIndexBlock indexer(txn, collection);
- Status status = indexer.init(o);
+ Status status = indexer.init(o).getStatus();
if (status.code() == ErrorCodes::IndexAlreadyExists)
return;
uassertStatusOK(status);
diff --git a/src/mongo/db/dbhelpers.h b/src/mongo/db/dbhelpers.h
index 6386a943552..f3acb9f190c 100644
--- a/src/mongo/db/dbhelpers.h
+++ b/src/mongo/db/dbhelpers.h
@@ -32,6 +32,7 @@
#include <memory>
#include "mongo/db/db.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/record_id.h"
#include "mongo/db/storage/data_protector.h"
@@ -66,6 +67,7 @@ struct Helpers {
static void ensureIndex(OperationContext* txn,
Collection* collection,
BSONObj keyPattern,
+ IndexDescriptor::IndexVersion indexVersion,
bool unique,
const char* name);
diff --git a/src/mongo/db/index/index_descriptor.cpp b/src/mongo/db/index/index_descriptor.cpp
index def508b07af..d86ee74498b 100644
--- a/src/mongo/db/index/index_descriptor.cpp
+++ b/src/mongo/db/index/index_descriptor.cpp
@@ -50,21 +50,38 @@ void populateOptionsMap(std::map<StringData, BSONElement>& theMap, const BSONObj
const BSONElement e = it.next();
StringData fieldName = e.fieldNameStringData();
- if (fieldName == "key" || fieldName == "ns" || fieldName == "name" ||
- fieldName == "v" || // not considered for equivalence
- fieldName == "textIndexVersion" || // same as "v"
- fieldName == "2dsphereIndexVersion" || // same as "v"
- fieldName == "background" || // this is a creation time option only
- fieldName == "dropDups" || // this is now ignored
- fieldName == "sparse" || // checked specially
- fieldName == "unique" // check specially
+ if (fieldName == IndexDescriptor::kKeyPatternFieldName ||
+ fieldName == IndexDescriptor::kNamespaceFieldName ||
+ fieldName == IndexDescriptor::kIndexNameFieldName ||
+ fieldName ==
+ IndexDescriptor::kIndexVersionFieldName || // not considered for equivalence
+ fieldName == IndexDescriptor::kTextVersionFieldName || // same as index version
+ fieldName == IndexDescriptor::k2dsphereVersionFieldName || // same as index version
+ fieldName ==
+ IndexDescriptor::kBackgroundFieldName || // this is a creation time option only
+ fieldName == IndexDescriptor::kDropDuplicatesFieldName || // this is now ignored
+ fieldName == IndexDescriptor::kSparseFieldName || // checked specially
+ fieldName == IndexDescriptor::kUniqueFieldName // check specially
) {
continue;
}
theMap[fieldName] = e;
}
}
-}
+} // namespace
+
+const StringData IndexDescriptor::k2dsphereVersionFieldName = "2dsphereIndexVersion"_sd;
+const StringData IndexDescriptor::kBackgroundFieldName = "background"_sd;
+const StringData IndexDescriptor::kCollationFieldName = "collation"_sd;
+const StringData IndexDescriptor::kDropDuplicatesFieldName = "dropDups"_sd;
+const StringData IndexDescriptor::kIndexNameFieldName = "name"_sd;
+const StringData IndexDescriptor::kIndexVersionFieldName = "v"_sd;
+const StringData IndexDescriptor::kKeyPatternFieldName = "key"_sd;
+const StringData IndexDescriptor::kNamespaceFieldName = "ns"_sd;
+const StringData IndexDescriptor::kPartialFilterExprFieldName = "partialFilterExpression"_sd;
+const StringData IndexDescriptor::kSparseFieldName = "sparse"_sd;
+const StringData IndexDescriptor::kTextVersionFieldName = "textIndexVersion"_sd;
+const StringData IndexDescriptor::kUniqueFieldName = "unique"_sd;
bool IndexDescriptor::isIndexVersionSupported(IndexVersion indexVersion) {
switch (indexVersion) {
diff --git a/src/mongo/db/index/index_descriptor.h b/src/mongo/db/index/index_descriptor.h
index 429f24fcf1e..581548b8b34 100644
--- a/src/mongo/db/index/index_descriptor.h
+++ b/src/mongo/db/index/index_descriptor.h
@@ -56,6 +56,19 @@ class IndexDescriptor {
public:
enum class IndexVersion { kV0 = 0, kV1 = 1, kV2 = 2 };
+ static const StringData k2dsphereVersionFieldName;
+ static const StringData kBackgroundFieldName;
+ static const StringData kCollationFieldName;
+ static const StringData kDropDuplicatesFieldName;
+ static const StringData kIndexNameFieldName;
+ static const StringData kIndexVersionFieldName;
+ static const StringData kKeyPatternFieldName;
+ static const StringData kNamespaceFieldName;
+ static const StringData kPartialFilterExprFieldName;
+ static const StringData kSparseFieldName;
+ static const StringData kTextVersionFieldName;
+ static const StringData kUniqueFieldName;
+
/**
* OnDiskIndexData is a pointer to the memory mapped per-index data.
* infoObj is a copy of the index-describing BSONObj contained in the OnDiskIndexData.
@@ -64,19 +77,19 @@ public:
: _collection(collection),
_accessMethodName(accessMethodName),
_infoObj(infoObj.getOwned()),
- _numFields(infoObj.getObjectField("key").nFields()),
- _keyPattern(infoObj.getObjectField("key").getOwned()),
- _indexName(infoObj.getStringField("name")),
- _parentNS(infoObj.getStringField("ns")),
+ _numFields(infoObj.getObjectField(IndexDescriptor::kKeyPatternFieldName).nFields()),
+ _keyPattern(infoObj.getObjectField(IndexDescriptor::kKeyPatternFieldName).getOwned()),
+ _indexName(infoObj.getStringField(IndexDescriptor::kIndexNameFieldName)),
+ _parentNS(infoObj.getStringField(IndexDescriptor::kNamespaceFieldName)),
_isIdIndex(isIdIndexPattern(_keyPattern)),
- _sparse(infoObj["sparse"].trueValue()),
- _unique(_isIdIndex || infoObj["unique"].trueValue()),
- _partial(!infoObj["partialFilterExpression"].eoo()),
+ _sparse(infoObj[IndexDescriptor::kSparseFieldName].trueValue()),
+ _unique(_isIdIndex || infoObj[kUniqueFieldName].trueValue()),
+ _partial(!infoObj[kPartialFilterExprFieldName].eoo()),
_cachedEntry(NULL) {
_indexNamespace = makeIndexNamespace(_parentNS, _indexName);
_version = IndexVersion::kV0;
- BSONElement e = _infoObj["v"];
+ BSONElement e = _infoObj[IndexDescriptor::kIndexVersionFieldName];
if (e.isNumber()) {
_version = static_cast<IndexVersion>(e.numberInt());
}
diff --git a/src/mongo/db/index_builder.cpp b/src/mongo/db/index_builder.cpp
index fbefb512ff2..352b5f2d5cc 100644
--- a/src/mongo/db/index_builder.cpp
+++ b/src/mongo/db/index_builder.cpp
@@ -161,7 +161,7 @@ Status IndexBuilder::_build(OperationContext* txn,
try {
- status = indexer.init(_index);
+ status = indexer.init(_index).getStatus();
if (status.code() == ErrorCodes::IndexAlreadyExists) {
if (allowBackgroundBuilding) {
// Must set this in case anyone is waiting for this build.
diff --git a/src/mongo/db/repair_database.cpp b/src/mongo/db/repair_database.cpp
index 4f5665e55da..9172b2f3a1d 100644
--- a/src/mongo/db/repair_database.cpp
+++ b/src/mongo/db/repair_database.cpp
@@ -44,6 +44,7 @@
#include "mongo/db/catalog/document_validation.h"
#include "mongo/db/catalog/index_create.h"
#include "mongo/db/catalog/index_key_validate.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/db/storage/mmap_v1/mmap_v1_engine.h"
#include "mongo/db/storage/storage_engine.h"
@@ -55,6 +56,8 @@ namespace mongo {
using std::endl;
using std::string;
+using IndexVersion = IndexDescriptor::IndexVersion;
+
namespace {
Status rebuildIndexesOnCollection(OperationContext* txn,
DatabaseCatalogEntry* dbce,
@@ -66,10 +69,35 @@ Status rebuildIndexesOnCollection(OperationContext* txn,
{
// Fetch all indexes
cce->getAllIndexes(txn, &indexNames);
+ indexSpecs.reserve(indexNames.size());
+
for (size_t i = 0; i < indexNames.size(); i++) {
const string& name = indexNames[i];
BSONObj spec = cce->getIndexSpec(txn, name);
- indexSpecs.push_back(spec.removeField("v").getOwned());
+
+ {
+ BSONObjBuilder bob;
+
+ for (auto&& indexSpecElem : spec) {
+ auto indexSpecElemFieldName = indexSpecElem.fieldNameStringData();
+ if (IndexDescriptor::kIndexVersionFieldName == indexSpecElemFieldName) {
+ IndexVersion indexVersion =
+ static_cast<IndexVersion>(indexSpecElem.numberInt());
+ if (IndexVersion::kV0 == indexVersion) {
+ // We automatically upgrade v=0 indexes to v=1 indexes.
+ bob.append(IndexDescriptor::kIndexVersionFieldName,
+ static_cast<int>(IndexVersion::kV1));
+ } else {
+ bob.append(IndexDescriptor::kIndexVersionFieldName,
+ static_cast<int>(indexVersion));
+ }
+ } else {
+ bob.append(indexSpecElem);
+ }
+ }
+
+ indexSpecs.push_back(bob.obj());
+ }
const BSONObj key = spec.getObjectField("key");
const Status keyStatus = validateKeyPattern(key);
@@ -116,7 +144,7 @@ Status rebuildIndexesOnCollection(OperationContext* txn,
collection.reset(new Collection(txn, ns, cce, dbce->getRecordStore(ns), dbce));
indexer.reset(new MultiIndexBlock(txn, collection.get()));
- Status status = indexer->init(indexSpecs);
+ Status status = indexer->init(indexSpecs).getStatus();
if (!status.isOK()) {
// The WUOW will handle cleanup, so the indexer shouldn't do its own.
indexer->abortWithoutCleanup();
diff --git a/src/mongo/db/repl/collection_bulk_loader_impl.cpp b/src/mongo/db/repl/collection_bulk_loader_impl.cpp
index 3f8e78d46ca..c3354e3f225 100644
--- a/src/mongo/db/repl/collection_bulk_loader_impl.cpp
+++ b/src/mongo/db/repl/collection_bulk_loader_impl.cpp
@@ -93,7 +93,7 @@ Status CollectionBulkLoaderImpl::init(OperationContext* txn,
invariant(txn->getClient() == &cc());
if (secondaryIndexSpecs.size()) {
_secondaryIndexesBlock->ignoreUniqueConstraint();
- auto status = _secondaryIndexesBlock->init(secondaryIndexSpecs);
+ auto status = _secondaryIndexesBlock->init(secondaryIndexSpecs).getStatus();
if (!status.isOK()) {
return status;
}
@@ -101,7 +101,7 @@ Status CollectionBulkLoaderImpl::init(OperationContext* txn,
_secondaryIndexesBlock.reset();
}
if (!_idIndexSpec.isEmpty()) {
- auto status = _idIndexBlock->init(_idIndexSpec);
+ auto status = _idIndexBlock->init(_idIndexSpec).getStatus();
if (!status.isOK()) {
return status;
}
diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp
index ac2d26bc1b8..16f655443f0 100644
--- a/src/mongo/db/repl/oplog.cpp
+++ b/src/mongo/db/repl/oplog.cpp
@@ -64,6 +64,7 @@
#include "mongo/db/dbhelpers.h"
#include "mongo/db/global_timestamp.h"
#include "mongo/db/index/index_access_method.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/index_builder.h"
#include "mongo/db/keypattern.h"
#include "mongo/db/namespace_string.h"
@@ -102,6 +103,8 @@ using std::stringstream;
using std::unique_ptr;
using std::vector;
+using IndexVersion = IndexDescriptor::IndexVersion;
+
namespace repl {
std::string rsOplogName = "local.oplog.rs";
std::string masterSlaveOplogName = "local.oplog.$main";
@@ -708,9 +711,10 @@ Status applyOperation_inlock(OperationContext* txn,
uassert(ErrorCodes::TypeMismatch,
str::stream() << "Expected object for index spec in field 'o': " << op,
fieldO.isABSONObj());
+ BSONObj indexSpec = fieldO.embeddedObject();
std::string indexNs;
- uassertStatusOK(bsonExtractStringField(o, "ns", &indexNs));
+ uassertStatusOK(bsonExtractStringField(indexSpec, "ns", &indexNs));
const NamespaceString indexNss(indexNs);
uassert(ErrorCodes::InvalidNamespace,
str::stream() << "Invalid namespace in index spec: " << op,
@@ -723,24 +727,39 @@ Status applyOperation_inlock(OperationContext* txn,
nsToDatabaseSubstring(ns) == indexNss.db());
opCounters->gotInsert();
- if (o["background"].trueValue()) {
+
+ if (!indexSpec["v"]) {
+ // If the "v" field isn't present in the index specification, then we assume it is a
+ // v=1 index from an older version of MongoDB. This is because
+ // (1) we haven't built v=0 indexes as the default for a long time, and
+ // (2) the index version has been included in the corresponding oplog entry since
+ // v=2 indexes were introduced.
+ BSONObjBuilder bob;
+
+ bob.append("v", static_cast<int>(IndexVersion::kV1));
+ bob.appendElements(indexSpec);
+
+ indexSpec = bob.obj();
+ }
+
+ if (indexSpec["background"].trueValue()) {
Lock::TempRelease release(txn->lockState());
if (txn->lockState()->isLocked()) {
// If TempRelease fails, background index build will deadlock.
- LOG(3) << "apply op: building background index " << o
+ LOG(3) << "apply op: building background index " << indexSpec
<< " in the foreground because temp release failed";
- IndexBuilder builder(o);
+ IndexBuilder builder(indexSpec);
Status status = builder.buildInForeground(txn, db);
uassertStatusOK(status);
} else {
- IndexBuilder* builder = new IndexBuilder(o);
+ IndexBuilder* builder = new IndexBuilder(indexSpec);
// This spawns a new thread and returns immediately.
builder->go();
// Wait for thread to start and register itself
IndexBuilder::waitForBgIndexStarting();
}
} else {
- IndexBuilder builder(o);
+ IndexBuilder builder(indexSpec);
Status status = builder.buildInForeground(txn, db);
uassertStatusOK(status);
}
diff --git a/src/mongo/db/repl/rs_rollback_test.cpp b/src/mongo/db/repl/rs_rollback_test.cpp
index 7bbe51cde11..14f42cb7158 100644
--- a/src/mongo/db/repl/rs_rollback_test.cpp
+++ b/src/mongo/db/repl/rs_rollback_test.cpp
@@ -42,6 +42,7 @@
#include "mongo/db/concurrency/d_concurrency.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/dbhelpers.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/repl/oplog.h"
#include "mongo/db/repl/oplog_interface.h"
@@ -61,6 +62,8 @@ namespace {
using namespace mongo;
using namespace mongo::repl;
+const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
+
const OplogInterfaceMock::Operations kEmptyMockOperations;
ReplSettings createReplSettings() {
@@ -423,11 +426,13 @@ TEST_F(RSRollbackTest, RollbackCreateIndexCommand) {
<< "key"
<< BSON("a" << 1)
<< "name"
- << "a_1");
+ << "a_1"
+ << "v"
+ << static_cast<int>(kIndexVersion));
{
Lock::DBLock dbLock(_txn->lockState(), "test", MODE_X);
MultiIndexBlock indexer(_txn.get(), collection);
- ASSERT_OK(indexer.init(indexSpec));
+ ASSERT_OK(indexer.init(indexSpec).getStatus());
WriteUnitOfWork wunit(_txn.get());
indexer.commit();
wunit.commit();
diff --git a/src/mongo/db/repl/storage_interface_impl_test.cpp b/src/mongo/db/repl/storage_interface_impl_test.cpp
index 3fd75e28429..218f925b97d 100644
--- a/src/mongo/db/repl/storage_interface_impl_test.cpp
+++ b/src/mongo/db/repl/storage_interface_impl_test.cpp
@@ -41,6 +41,7 @@
#include "mongo/db/curop.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/dbhelpers.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/repl/oplog.h"
@@ -60,13 +61,17 @@ namespace {
using namespace mongo;
using namespace mongo::repl;
+const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
+
BSONObj makeIdIndexSpec(const NamespaceString& nss) {
return BSON("ns" << nss.toString() << "name"
<< "_id_"
<< "key"
<< BSON("_id" << 1)
<< "unique"
- << true);
+ << true
+ << "v"
+ << static_cast<int>(kIndexVersion));
}
/**
diff --git a/src/mongo/db/s/migration_destination_manager.cpp b/src/mongo/db/s/migration_destination_manager.cpp
index dac91d5ba69..2368ade2b07 100644
--- a/src/mongo/db/s/migration_destination_manager.cpp
+++ b/src/mongo/db/s/migration_destination_manager.cpp
@@ -44,11 +44,9 @@
#include "mongo/db/catalog/index_create.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/dbhelpers.h"
-#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/operation_context.h"
#include "mongo/db/ops/delete.h"
-#include "mongo/db/query/collation/collation_spec.h"
#include "mongo/db/range_deleter_service.h"
#include "mongo/db/repl/repl_client_info.h"
#include "mongo/db/repl/replication_coordinator_global.h"
@@ -73,8 +71,6 @@ namespace mongo {
using std::string;
using str::stream;
-using IndexVersion = IndexDescriptor::IndexVersion;
-
namespace {
Tee* migrateLog = RamLog::get("migrate");
@@ -563,33 +559,16 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* txn,
return;
}
- // Attach simple collation if the index does not specify a collation. Otherwise, this
- // will be back-filled with the collection default collation.
- std::vector<BSONObj> indexSpecsWithCollation;
- for (const BSONObj& spec : indexSpecs) {
- if (spec["collation"]) {
- indexSpecsWithCollation.push_back(spec.getOwned());
- } else if (IndexVersion::kV2 <= static_cast<IndexVersion>(spec["v"].numberInt())) {
- indexSpecsWithCollation.emplace_back(
- BSONObjBuilder()
- .appendElements(spec)
- .append("collation", CollationSpec::kSimpleSpec)
- .obj());
- } else {
- indexSpecsWithCollation.push_back(spec.getOwned());
- }
- }
-
- Status status = indexer.init(indexSpecsWithCollation);
- if (!status.isOK()) {
+ auto indexInfoObjs = indexer.init(indexSpecs);
+ if (!indexInfoObjs.isOK()) {
errmsg = str::stream() << "failed to create index before migrating data. "
- << " error: " << redact(status);
+ << " error: " << redact(indexInfoObjs.getStatus());
warning() << errmsg;
setState(FAIL);
return;
}
- status = indexer.insertAllDocumentsInCollection();
+ auto status = indexer.insertAllDocumentsInCollection();
if (!status.isOK()) {
errmsg = str::stream() << "failed to create index before migrating data. "
<< " error: " << redact(status);
@@ -601,13 +580,10 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* txn,
WriteUnitOfWork wunit(txn);
indexer.commit();
- for (size_t i = 0; i < indexSpecsWithCollation.size(); i++) {
+ for (auto&& infoObj : indexInfoObjs.getValue()) {
// make sure to create index on secondaries as well
getGlobalServiceContext()->getOpObserver()->onCreateIndex(
- txn,
- db->getSystemIndexesName(),
- indexSpecsWithCollation[i],
- true /* fromMigrate */);
+ txn, db->getSystemIndexesName(), infoObj, true /* fromMigrate */);
}
wunit.commit();
diff --git a/src/mongo/db/storage/mmap_v1/repair_database.cpp b/src/mongo/db/storage/mmap_v1/repair_database.cpp
index 6b4284ee57a..d82a89031d6 100644
--- a/src/mongo/db/storage/mmap_v1/repair_database.cpp
+++ b/src/mongo/db/storage/mmap_v1/repair_database.cpp
@@ -397,7 +397,7 @@ Status MMAPV1Engine::repairDatabase(OperationContext* txn,
indexes.push_back(desc->infoObj());
}
- Status status = indexer.init(indexes);
+ Status status = indexer.init(indexes).getStatus();
if (!status.isOK()) {
return status;
}
diff --git a/src/mongo/dbtests/counttests.cpp b/src/mongo/dbtests/counttests.cpp
index 2e28621b833..689b87fe599 100644
--- a/src/mongo/dbtests/counttests.cpp
+++ b/src/mongo/dbtests/counttests.cpp
@@ -36,6 +36,7 @@
#include "mongo/db/db_raii.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/dbhelpers.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/json.h"
#include "mongo/stdx/thread.h"
@@ -43,6 +44,10 @@
namespace CountTests {
+namespace {
+const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
+} // namespace
+
class Base {
public:
Base()
@@ -83,6 +88,7 @@ protected:
Helpers::ensureIndex(&_txn,
_collection,
key,
+ kIndexVersion,
/*unique=*/false,
/*name=*/key.firstElementFieldName());
}
diff --git a/src/mongo/dbtests/dbtests.cpp b/src/mongo/dbtests/dbtests.cpp
index 96ad9253f08..8ddd7f4aa4c 100644
--- a/src/mongo/dbtests/dbtests.cpp
+++ b/src/mongo/dbtests/dbtests.cpp
@@ -39,6 +39,7 @@
#include "mongo/db/catalog/index_create.h"
#include "mongo/db/commands.h"
#include "mongo/db/db_raii.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/repl/replication_coordinator_global.h"
#include "mongo/db/repl/replication_coordinator_mock.h"
#include "mongo/db/service_context.h"
@@ -54,6 +55,9 @@
namespace mongo {
namespace dbtests {
+namespace {
+const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
+} // namespace
void initWireSpec() {
WireSpec& spec = WireSpec::instance();
@@ -67,9 +71,12 @@ void initWireSpec() {
Status createIndex(OperationContext* txn, StringData ns, const BSONObj& keys, bool unique) {
BSONObjBuilder specBuilder;
- specBuilder << "name" << DBClientBase::genIndexName(keys) << "ns" << ns << "key" << keys;
+ specBuilder.append("name", DBClientBase::genIndexName(keys));
+ specBuilder.append("ns", ns);
+ specBuilder.append("key", keys);
+ specBuilder.append("v", static_cast<int>(kIndexVersion));
if (unique) {
- specBuilder << "unique" << true;
+ specBuilder.appendBool("unique", true);
}
return createIndexFromSpec(txn, ns, specBuilder.done());
}
@@ -84,7 +91,7 @@ Status createIndexFromSpec(OperationContext* txn, StringData ns, const BSONObj&
wunit.commit();
}
MultiIndexBlock indexer(txn, coll);
- Status status = indexer.init(spec);
+ Status status = indexer.init(spec).getStatus();
if (status == ErrorCodes::IndexAlreadyExists) {
return Status::OK();
}
diff --git a/src/mongo/dbtests/indexcatalogtests.cpp b/src/mongo/dbtests/indexcatalogtests.cpp
index ef2f1effb81..068ede905a1 100644
--- a/src/mongo/dbtests/indexcatalogtests.cpp
+++ b/src/mongo/dbtests/indexcatalogtests.cpp
@@ -29,6 +29,9 @@
#include "mongo/dbtests/dbtests.h"
namespace IndexCatalogTests {
+namespace {
+const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
+} // namespace
static const char* const _ns = "unittests.indexcatalog";
@@ -135,12 +138,13 @@ public:
OldClientWriteContext ctx(&txn, _ns);
const std::string indexName = "x_1";
- ASSERT_OK(dbtests::createIndexFromSpec(&txn,
- _ns,
- BSON("name" << indexName << "ns" << _ns << "key"
- << BSON("x" << 1)
- << "expireAfterSeconds"
- << 5)));
+ ASSERT_OK(dbtests::createIndexFromSpec(
+ &txn,
+ _ns,
+ BSON("name" << indexName << "ns" << _ns << "key" << BSON("x" << 1) << "v"
+ << static_cast<int>(kIndexVersion)
+ << "expireAfterSeconds"
+ << 5)));
const IndexDescriptor* desc = _catalog->findIndexByName(&txn, indexName);
ASSERT(desc);
diff --git a/src/mongo/dbtests/indexupdatetests.cpp b/src/mongo/dbtests/indexupdatetests.cpp
index 6b9ee3e23ae..0a379851b09 100644
--- a/src/mongo/dbtests/indexupdatetests.cpp
+++ b/src/mongo/dbtests/indexupdatetests.cpp
@@ -48,6 +48,10 @@ namespace IndexUpdateTests {
using std::unique_ptr;
+namespace {
+const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
+} // namespace
+
static const char* const _ns = "unittests.indexupdate";
/**
@@ -376,12 +380,14 @@ public:
<< coll->ns().ns()
<< "key"
<< BSON("a" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "unique"
<< true
<< "background"
<< background);
- ASSERT_OK(indexer.init(spec));
+ ASSERT_OK(indexer.init(spec).getStatus());
ASSERT_OK(indexer.insertAllDocumentsInCollection());
WriteUnitOfWork wunit(&_txn);
@@ -428,12 +434,14 @@ public:
<< coll->ns().ns()
<< "key"
<< BSON("a" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "unique"
<< true
<< "background"
<< background);
- ASSERT_OK(indexer.init(spec));
+ ASSERT_OK(indexer.init(spec).getStatus());
const Status status = indexer.insertAllDocumentsInCollection();
ASSERT_EQUALS(status.code(), ErrorCodes::DuplicateKey);
}
@@ -479,12 +487,14 @@ public:
<< coll->ns().ns()
<< "key"
<< BSON("a" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "unique"
<< true
<< "background"
<< background);
- ASSERT_OK(indexer.init(spec));
+ ASSERT_OK(indexer.init(spec).getStatus());
std::set<RecordId> dups;
ASSERT_OK(indexer.insertAllDocumentsInCollection(&dups));
@@ -524,7 +534,9 @@ public:
// Request an interrupt.
getGlobalServiceContext()->setKillAllOperations();
BSONObj indexInfo = BSON("key" << BSON("a" << 1) << "ns" << _ns << "name"
- << "a_1");
+ << "a_1"
+ << "v"
+ << static_cast<int>(kIndexVersion));
// The call is interrupted because mayInterrupt == true.
ASSERT_TRUE(buildIndexInterrupted(indexInfo, true));
// only want to interrupt the index build
@@ -557,7 +569,9 @@ public:
// Request an interrupt.
getGlobalServiceContext()->setKillAllOperations();
BSONObj indexInfo = BSON("key" << BSON("a" << 1) << "ns" << _ns << "name"
- << "a_1");
+ << "a_1"
+ << "v"
+ << static_cast<int>(kIndexVersion));
// The call is not interrupted because mayInterrupt == false.
ASSERT_FALSE(buildIndexInterrupted(indexInfo, false));
// only want to interrupt the index build
@@ -593,7 +607,9 @@ public:
// Request an interrupt.
getGlobalServiceContext()->setKillAllOperations();
BSONObj indexInfo = BSON("key" << BSON("_id" << 1) << "ns" << _ns << "name"
- << "_id_");
+ << "_id_"
+ << "v"
+ << static_cast<int>(kIndexVersion));
// The call is interrupted because mayInterrupt == true.
ASSERT_TRUE(buildIndexInterrupted(indexInfo, true));
// only want to interrupt the index build
@@ -629,7 +645,9 @@ public:
// Request an interrupt.
getGlobalServiceContext()->setKillAllOperations();
BSONObj indexInfo = BSON("key" << BSON("_id" << 1) << "ns" << _ns << "name"
- << "_id_");
+ << "_id_"
+ << "v"
+ << static_cast<int>(kIndexVersion));
// The call is not interrupted because mayInterrupt == false.
ASSERT_FALSE(buildIndexInterrupted(indexInfo, false));
// only want to interrupt the index build
@@ -653,7 +671,7 @@ public:
// Request an interrupt.
getGlobalServiceContext()->setKillAllOperations();
// The call is not interrupted.
- Helpers::ensureIndex(&_txn, collection(), BSON("a" << 1), false, "a_1");
+ Helpers::ensureIndex(&_txn, collection(), BSON("a" << 1), kIndexVersion, false, "a_1");
// only want to interrupt the index build
getGlobalServiceContext()->unsetKillAllOperations();
// The new index is listed in getIndexSpecs because the index build completed.
@@ -721,7 +739,7 @@ public:
Status IndexBuildBase::createIndex(const std::string& dbname, const BSONObj& indexSpec) {
MultiIndexBlock indexer(&_txn, collection());
- Status status = indexer.init(indexSpec);
+ Status status = indexer.init(indexSpec).getStatus();
if (status == ErrorCodes::IndexAlreadyExists) {
return Status::OK();
}
@@ -750,7 +768,9 @@ public:
<< "ns"
<< _ns
<< "key"
- << BSON("x" << 1 << "y" << 1))));
+ << BSON("x" << 1 << "y" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion))));
}
};
@@ -767,7 +787,9 @@ public:
<< "unique"
<< true
<< "key"
- << BSON("x" << 1 << "y" << 1))));
+ << BSON("x" << 1 << "y" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion))));
}
};
@@ -780,7 +802,9 @@ public:
<< "ns"
<< _ns
<< "key"
- << BSON("x" << 1 << "y" << 1))));
+ << BSON("x" << 1 << "y" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion))));
}
};
@@ -795,7 +819,9 @@ public:
<< "ns"
<< _ns
<< "key"
- << BSON("y" << 1 << "x" << 1))));
+ << BSON("y" << 1 << "x" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion))));
}
};
@@ -818,7 +844,9 @@ public:
<< 3600
<< "key"
<< BSON("superIdx"
- << "2d"))));
+ << "2d")
+ << "v"
+ << static_cast<int>(kIndexVersion))));
}
};
@@ -840,7 +868,9 @@ public:
<< 1
<< "key"
<< BSON("superIdx"
- << "2d"))));
+ << "2d")
+ << "v"
+ << static_cast<int>(kIndexVersion))));
}
};
@@ -864,7 +894,9 @@ public:
<< 3600
<< "key"
<< BSON("superIdx"
- << "2d"))));
+ << "2d")
+ << "v"
+ << static_cast<int>(kIndexVersion))));
}
};
@@ -887,7 +919,9 @@ public:
<< 3600
<< "key"
<< BSON("superIdx"
- << "2d"))));
+ << "2d")
+ << "v"
+ << static_cast<int>(kIndexVersion))));
}
};
@@ -908,7 +942,9 @@ public:
<< 2400
<< "key"
<< BSON("superIdx"
- << "2d"))));
+ << "2d")
+ << "v"
+ << static_cast<int>(kIndexVersion))));
}
};
@@ -959,6 +995,8 @@ protected:
<< _ns
<< "key"
<< BSON("a" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "storageEngine"
<< storageEngineValue);
}
diff --git a/src/mongo/dbtests/multikey_paths_test.cpp b/src/mongo/dbtests/multikey_paths_test.cpp
index ccbaa741983..b9ad16ce17b 100644
--- a/src/mongo/dbtests/multikey_paths_test.cpp
+++ b/src/mongo/dbtests/multikey_paths_test.cpp
@@ -34,6 +34,7 @@
#include "mongo/db/catalog/index_create.h"
#include "mongo/db/client.h"
#include "mongo/db/db_raii.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/index/multikey_paths.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/service_context.h"
@@ -44,6 +45,8 @@
namespace mongo {
namespace {
+const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
+
/**
* Fixture for testing correctness of multikey paths.
*
@@ -157,7 +160,9 @@ TEST_F(MultikeyPathsTest, PathsUpdatedOnIndexCreation) {
<< "ns"
<< _nss.ns()
<< "key"
- << keyPattern));
+ << keyPattern
+ << "v"
+ << static_cast<int>(kIndexVersion)));
assertMultikeyPaths(collection, keyPattern, {std::set<size_t>{}, {0U}});
}
@@ -191,7 +196,9 @@ TEST_F(MultikeyPathsTest, PathsUpdatedOnIndexCreationWithMultipleDocuments) {
<< "ns"
<< _nss.ns()
<< "key"
- << keyPattern));
+ << keyPattern
+ << "v"
+ << static_cast<int>(kIndexVersion)));
assertMultikeyPaths(collection, keyPattern, {{0U}, {0U}});
}
@@ -208,7 +215,9 @@ TEST_F(MultikeyPathsTest, PathsUpdatedOnDocumentInsert) {
<< "ns"
<< _nss.ns()
<< "key"
- << keyPattern));
+ << keyPattern
+ << "v"
+ << static_cast<int>(kIndexVersion)));
{
WriteUnitOfWork wuow(_opCtx.get());
@@ -251,7 +260,9 @@ TEST_F(MultikeyPathsTest, PathsUpdatedOnDocumentUpdate) {
<< "ns"
<< _nss.ns()
<< "key"
- << keyPattern));
+ << keyPattern
+ << "v"
+ << static_cast<int>(kIndexVersion)));
{
WriteUnitOfWork wuow(_opCtx.get());
@@ -304,7 +315,9 @@ TEST_F(MultikeyPathsTest, PathsNotUpdatedOnDocumentDelete) {
<< "ns"
<< _nss.ns()
<< "key"
- << keyPattern));
+ << keyPattern
+ << "v"
+ << static_cast<int>(kIndexVersion)));
{
WriteUnitOfWork wuow(_opCtx.get());
@@ -348,7 +361,9 @@ TEST_F(MultikeyPathsTest, PathsUpdatedForMultipleIndexesOnDocumentInsert) {
<< "ns"
<< _nss.ns()
<< "key"
- << keyPatternAB));
+ << keyPatternAB
+ << "v"
+ << static_cast<int>(kIndexVersion)));
BSONObj keyPatternAC = BSON("a" << 1 << "c" << 1);
createIndex(collection,
@@ -357,7 +372,9 @@ TEST_F(MultikeyPathsTest, PathsUpdatedForMultipleIndexesOnDocumentInsert) {
<< "ns"
<< _nss.ns()
<< "key"
- << keyPatternAC));
+ << keyPatternAC
+ << "v"
+ << static_cast<int>(kIndexVersion)));
{
WriteUnitOfWork wuow(_opCtx.get());
OpDebug* const nullOpDebug = nullptr;
diff --git a/src/mongo/dbtests/query_stage_ixscan.cpp b/src/mongo/dbtests/query_stage_ixscan.cpp
index 3d22cf19fd9..7ad4e1a0b84 100644
--- a/src/mongo/dbtests/query_stage_ixscan.cpp
+++ b/src/mongo/dbtests/query_stage_ixscan.cpp
@@ -32,11 +32,15 @@
#include "mongo/db/db_raii.h"
#include "mongo/db/exec/index_scan.h"
#include "mongo/db/exec/working_set.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/dbtests/dbtests.h"
namespace QueryStageIxscan {
+namespace {
+const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
+} // namespace
class IndexScanTest {
public:
@@ -57,7 +61,9 @@ public:
ASSERT_OK(_coll->getIndexCatalog()->createIndexOnEmptyCollection(
&_txn,
BSON("ns" << ns() << "key" << BSON("x" << 1) << "name"
- << DBClientBase::genIndexName(BSON("x" << 1)))));
+ << DBClientBase::genIndexName(BSON("x" << 1))
+ << "v"
+ << static_cast<int>(kIndexVersion))));
wunit.commit();
}
diff --git a/src/mongo/dbtests/querytests.cpp b/src/mongo/dbtests/querytests.cpp
index 888d9bd4454..de55f54f45d 100644
--- a/src/mongo/dbtests/querytests.cpp
+++ b/src/mongo/dbtests/querytests.cpp
@@ -40,6 +40,7 @@
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/dbhelpers.h"
#include "mongo/db/global_timestamp.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/json.h"
#include "mongo/db/lasterror.h"
#include "mongo/db/query/find.h"
@@ -56,6 +57,10 @@ using std::endl;
using std::string;
using std::vector;
+namespace {
+const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
+} // namespace
+
class Base {
public:
Base() : _scopedXact(&_txn, MODE_X), _lk(_txn.lockState()), _context(&_txn, ns()) {
@@ -89,7 +94,8 @@ protected:
}
void addIndex(const BSONObj& key) {
- Helpers::ensureIndex(&_txn, _collection, key, false, key.firstElementFieldName());
+ Helpers::ensureIndex(
+ &_txn, _collection, key, kIndexVersion, false, key.firstElementFieldName());
}
void insert(const char* s) {
diff --git a/src/mongo/dbtests/rollbacktests.cpp b/src/mongo/dbtests/rollbacktests.cpp
index 99d90fec617..0986db98aa6 100644
--- a/src/mongo/dbtests/rollbacktests.cpp
+++ b/src/mongo/dbtests/rollbacktests.cpp
@@ -36,6 +36,7 @@
#include "mongo/db/catalog/index_create.h"
#include "mongo/db/client.h"
#include "mongo/db/db_raii.h"
+#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/record_id.h"
#include "mongo/dbtests/dbtests.h"
#include "mongo/unittest/unittest.h"
@@ -47,6 +48,8 @@ using std::string;
namespace RollbackTests {
namespace {
+const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
+
void dropDatabase(OperationContext* txn, const NamespaceString& nss) {
ScopedTransaction transaction(txn, MODE_X);
Lock::GlobalWrite globalWriteLock(txn->lockState());
@@ -477,7 +480,8 @@ public:
IndexCatalog* catalog = coll->getIndexCatalog();
string idxName = "a";
- BSONObj spec = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxName);
+ BSONObj spec = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxName << "v"
+ << static_cast<int>(kIndexVersion));
// END SETUP / START TEST
@@ -518,7 +522,8 @@ public:
IndexCatalog* catalog = coll->getIndexCatalog();
string idxName = "a";
- BSONObj spec = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxName);
+ BSONObj spec = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxName << "v"
+ << static_cast<int>(kIndexVersion));
{
WriteUnitOfWork uow(&txn);
@@ -571,7 +576,8 @@ public:
IndexCatalog* catalog = coll->getIndexCatalog();
string idxName = "a";
- BSONObj spec = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxName);
+ BSONObj spec = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxName << "v"
+ << static_cast<int>(kIndexVersion));
// END SETUP / START TEST
@@ -615,7 +621,8 @@ public:
IndexCatalog* catalog = coll->getIndexCatalog();
string idxName = "a";
- BSONObj spec = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxName);
+ BSONObj spec = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxName << "v"
+ << static_cast<int>(kIndexVersion));
{
WriteUnitOfWork uow(&txn);
@@ -677,9 +684,12 @@ public:
string idxNameA = "indexA";
string idxNameB = "indexB";
string idxNameC = "indexC";
- BSONObj specA = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxNameA);
- BSONObj specB = BSON("ns" << ns << "key" << BSON("b" << 1) << "name" << idxNameB);
- BSONObj specC = BSON("ns" << ns << "key" << BSON("c" << 1) << "name" << idxNameC);
+ BSONObj specA = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxNameA << "v"
+ << static_cast<int>(kIndexVersion));
+ BSONObj specB = BSON("ns" << ns << "key" << BSON("b" << 1) << "name" << idxNameB << "v"
+ << static_cast<int>(kIndexVersion));
+ BSONObj specC = BSON("ns" << ns << "key" << BSON("c" << 1) << "name" << idxNameC << "v"
+ << static_cast<int>(kIndexVersion));
// END SETUP / START TEST
diff --git a/src/mongo/dbtests/validate_tests.cpp b/src/mongo/dbtests/validate_tests.cpp
index 14da85c8844..3eb1706fbce 100644
--- a/src/mongo/dbtests/validate_tests.cpp
+++ b/src/mongo/dbtests/validate_tests.cpp
@@ -46,6 +46,10 @@ namespace ValidateTests {
using std::unique_ptr;
+namespace {
+const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
+} // namespace
+
static const char* const _ns = "unittests.validate_tests";
/**
@@ -175,6 +179,8 @@ public:
<< coll->ns().ns()
<< "key"
<< BSON("a" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "background"
<< false));
@@ -236,6 +242,8 @@ public:
<< coll->ns().ns()
<< "key"
<< BSON("a" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "background"
<< false));
@@ -369,6 +377,8 @@ public:
<< coll->ns().ns()
<< "key"
<< BSON("a.b" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "background"
<< false));
@@ -433,6 +443,8 @@ public:
<< coll->ns().ns()
<< "key"
<< BSON("a" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "background"
<< false
<< "sparse"
@@ -491,6 +503,8 @@ public:
<< coll->ns().ns()
<< "key"
<< BSON("a" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "background"
<< false
<< "partialFilterExpression"
@@ -545,6 +559,8 @@ public:
<< "key"
<< BSON("x"
<< "2dsphere")
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "background"
<< false
<< "partialFilterExpression"
@@ -561,6 +577,8 @@ public:
<< "key"
<< BSON("x"
<< "2dsphere")
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "background"
<< false
<< "partialFilterExpression"
@@ -606,6 +624,8 @@ public:
<< coll->ns().ns()
<< "key"
<< BSON("a" << 1 << "b" << -1)
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "background"
<< false));
ASSERT_OK(status);
@@ -618,6 +638,8 @@ public:
<< coll->ns().ns()
<< "key"
<< BSON("a" << -1 << "b" << 1)
+ << "v"
+ << static_cast<int>(kIndexVersion)
<< "background"
<< false));
@@ -666,7 +688,8 @@ public:
auto status = dbtests::createIndexFromSpec(
&_txn,
coll->ns().ns(),
- BSON("name" << indexName << "ns" << coll->ns().ns() << "key" << BSON("a" << 1)
+ BSON("name" << indexName << "ns" << coll->ns().ns() << "key" << BSON("a" << 1) << "v"
+ << static_cast<int>(kIndexVersion)
<< "background"
<< false));
@@ -727,7 +750,8 @@ public:
auto status = dbtests::createIndexFromSpec(
&_txn,
coll->ns().ns(),
- BSON("name" << indexName << "ns" << coll->ns().ns() << "key" << BSON("a" << 1)
+ BSON("name" << indexName << "ns" << coll->ns().ns() << "key" << BSON("a" << 1) << "v"
+ << static_cast<int>(kIndexVersion)
<< "background"
<< false));