diff options
author | Tess Avitabile <tess.avitabile@mongodb.com> | 2016-10-24 12:04:42 -0400 |
---|---|---|
committer | Tess Avitabile <tess.avitabile@mongodb.com> | 2016-10-28 19:07:00 -0400 |
commit | e923952dd2c492ab19c34bfe094da6b855d0f99d (patch) | |
tree | ac1fdf64ee83055c63de3f62f3720a4dffcfea92 /src/mongo/db | |
parent | 8ac6f69b0879df0e69b8d9929badb472772a3bca (diff) | |
download | mongo-e923952dd2c492ab19c34bfe094da6b855d0f99d.tar.gz |
SERVER-26515 Create collection with v=2 index should include full index spec in oplog
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/catalog/collection.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/catalog/database.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_catalog.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_catalog.h | 5 | ||||
-rw-r--r-- | src/mongo/db/commands/mr.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/op_observer.cpp | 15 | ||||
-rw-r--r-- | src/mongo/db/op_observer.h | 3 | ||||
-rw-r--r-- | src/mongo/db/repl/oplog.cpp | 17 |
8 files changed, 48 insertions, 21 deletions
diff --git a/src/mongo/db/catalog/collection.cpp b/src/mongo/db/catalog/collection.cpp index 0df69a9d2e6..cccaa6b257b 100644 --- a/src/mongo/db/catalog/collection.cpp +++ b/src/mongo/db/catalog/collection.cpp @@ -918,7 +918,7 @@ Status Collection::truncate(OperationContext* txn) { // 4) re-create indexes for (size_t i = 0; i < indexSpecs.size(); i++) { - status = _indexCatalog.createIndexOnEmptyCollection(txn, indexSpecs[i]); + status = _indexCatalog.createIndexOnEmptyCollection(txn, indexSpecs[i]).getStatus(); if (!status.isOK()) return status; } diff --git a/src/mongo/db/catalog/database.cpp b/src/mongo/db/catalog/database.cpp index b667e5022a3..438c8ed91fe 100644 --- a/src/mongo/db/catalog/database.cpp +++ b/src/mongo/db/catalog/database.cpp @@ -579,22 +579,16 @@ Collection* Database::createCollection(OperationContext* txn, invariant(collection); _collections[ns] = collection; + BSONObj fullIdIndexSpec; + if (createIdIndex) { 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.featureCompatibility.version.load(); IndexCatalog* ic = collection->getIndexCatalog(); - uassertStatusOK(ic->createIndexOnEmptyCollection( + fullIdIndexSpec = uassertStatusOK(ic->createIndexOnEmptyCollection( txn, !idIndex.isEmpty() ? idIndex : ic->getDefaultIdIndexSpec(featureCompatibilityVersion))); @@ -608,7 +602,7 @@ Collection* Database::createCollection(OperationContext* txn, auto opObserver = getGlobalServiceContext()->getOpObserver(); if (opObserver) - opObserver->onCreateCollection(txn, nss, options); + opObserver->onCreateCollection(txn, nss, options, fullIdIndexSpec); return collection; } diff --git a/src/mongo/db/catalog/index_catalog.cpp b/src/mongo/db/catalog/index_catalog.cpp index e680a852360..f8d3a04f4c1 100644 --- a/src/mongo/db/catalog/index_catalog.cpp +++ b/src/mongo/db/catalog/index_catalog.cpp @@ -299,7 +299,8 @@ StatusWith<BSONObj> IndexCatalog::prepareSpecForCreate(OperationContext* txn, return fixed; } -Status IndexCatalog::createIndexOnEmptyCollection(OperationContext* txn, BSONObj spec) { +StatusWith<BSONObj> IndexCatalog::createIndexOnEmptyCollection(OperationContext* txn, + BSONObj spec) { invariant(txn->lockState()->isCollectionLockedForMode(_collection->ns().toString(), MODE_X)); invariant(_collection->numRecords(txn) == 0); @@ -342,7 +343,7 @@ Status IndexCatalog::createIndexOnEmptyCollection(OperationContext* txn, BSONObj // sanity check invariant(_collection->getCatalogEntry()->isIndexReady(txn, descriptor->indexName())); - return Status::OK(); + return spec; } IndexCatalog::IndexBuildBlock::IndexBuildBlock(OperationContext* txn, diff --git a/src/mongo/db/catalog/index_catalog.h b/src/mongo/db/catalog/index_catalog.h index 446a949ff2f..bd0c919076a 100644 --- a/src/mongo/db/catalog/index_catalog.h +++ b/src/mongo/db/catalog/index_catalog.h @@ -211,9 +211,10 @@ public: /** * Call this only on an empty collection from inside a WriteUnitOfWork. Index creation on an - * empty collection can be rolled back as part of a larger WUOW. + * empty collection can be rolled back as part of a larger WUOW. Returns the full specification + * of the created index, as it is stored in this index catalog. */ - Status createIndexOnEmptyCollection(OperationContext* txn, BSONObj spec); + StatusWith<BSONObj> createIndexOnEmptyCollection(OperationContext* txn, BSONObj spec); StatusWith<BSONObj> prepareSpecForCreate(OperationContext* txn, const BSONObj& original) const; diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index 920eb9aa980..3f2f13d2db0 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -424,8 +424,9 @@ void State::prepTempCollection() { << "_temp_0" << "v" << static_cast<int>(IndexVersion::kV2)); - Status status = - incColl->getIndexCatalog()->createIndexOnEmptyCollection(_txn, indexSpec); + Status status = incColl->getIndexCatalog() + ->createIndexOnEmptyCollection(_txn, indexSpec) + .getStatus(); if (!status.isOK()) { uasserted(17305, str::stream() << "createIndex failed for mr incLong ns: " @@ -486,7 +487,8 @@ void State::prepTempCollection() { for (vector<BSONObj>::iterator it = indexesToInsert.begin(); it != indexesToInsert.end(); ++it) { - Status status = tempColl->getIndexCatalog()->createIndexOnEmptyCollection(_txn, *it); + Status status = + tempColl->getIndexCatalog()->createIndexOnEmptyCollection(_txn, *it).getStatus(); if (!status.isOK()) { if (status.code() == ErrorCodes::IndexAlreadyExists) { continue; diff --git a/src/mongo/db/op_observer.cpp b/src/mongo/db/op_observer.cpp index 8defc1c71fe..99e1fe2f649 100644 --- a/src/mongo/db/op_observer.cpp +++ b/src/mongo/db/op_observer.cpp @@ -34,6 +34,7 @@ #include "mongo/db/catalog/collection_options.h" #include "mongo/db/commands/dbhash.h" #include "mongo/db/commands/feature_compatibility_version.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" @@ -173,11 +174,23 @@ void OpObserver::onOpMessage(OperationContext* txn, const BSONObj& msgObj) { void OpObserver::onCreateCollection(OperationContext* txn, const NamespaceString& collectionName, - const CollectionOptions& options) { + const CollectionOptions& options, + const BSONObj& idIndex) { std::string dbName = collectionName.db().toString() + ".$cmd"; BSONObjBuilder b; b.append("create", collectionName.coll().toString()); b.appendElements(options.toBSON()); + + // Include the full _id index spec in the oplog for index versions >= 2. + if (!idIndex.isEmpty()) { + auto versionElem = idIndex[IndexDescriptor::kIndexVersionFieldName]; + invariant(versionElem.isNumber()); + if (IndexDescriptor::IndexVersion::kV2 <= + static_cast<IndexDescriptor::IndexVersion>(versionElem.numberInt())) { + b.append("idIndex", idIndex); + } + } + BSONObj cmdObj = b.obj(); if (!collectionName.isSystemDotProfile()) { diff --git a/src/mongo/db/op_observer.h b/src/mongo/db/op_observer.h index b5a2d926489..e9c6f7d7425 100644 --- a/src/mongo/db/op_observer.h +++ b/src/mongo/db/op_observer.h @@ -95,7 +95,8 @@ public: void onOpMessage(OperationContext* txn, const BSONObj& msgObj); void onCreateCollection(OperationContext* txn, const NamespaceString& collectionName, - const CollectionOptions& options); + const CollectionOptions& options, + const BSONObj& idIndex); void onCollMod(OperationContext* txn, const std::string& dbName, const BSONObj& collModCmd); void onDropDatabase(OperationContext* txn, const std::string& dbName); void onDropCollection(OperationContext* txn, const NamespaceString& collectionName); diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index cfd4b5792cc..a2fd477ab9d 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -575,7 +575,22 @@ struct ApplyOpMetadata { std::map<std::string, ApplyOpMetadata> opsMap = { {"create", {[](OperationContext* txn, const char* ns, BSONObj& cmd) -> Status { - return createCollection(txn, NamespaceString(ns).db().toString(), cmd); + const NamespaceString nss(parseNs(ns, cmd)); + if (auto idIndexElem = cmd["idIndex"]) { + // Remove "idIndex" field from command. + auto cmdWithoutIdIndex = cmd.removeField("idIndex"); + return createCollection( + txn, nss.db().toString(), cmdWithoutIdIndex, idIndexElem.Obj()); + } + + // No _id index spec was provided, so we should build a v:1 _id index. + BSONObjBuilder idIndexSpecBuilder; + idIndexSpecBuilder.append(IndexDescriptor::kIndexVersionFieldName, + static_cast<int>(IndexVersion::kV1)); + idIndexSpecBuilder.append(IndexDescriptor::kIndexNameFieldName, "_id_"); + idIndexSpecBuilder.append(IndexDescriptor::kNamespaceFieldName, nss.ns()); + idIndexSpecBuilder.append(IndexDescriptor::kKeyPatternFieldName, BSON("_id" << 1)); + return createCollection(txn, nss.db().toString(), cmd, idIndexSpecBuilder.done()); }, {ErrorCodes::NamespaceExists}}}, {"collMod", {[](OperationContext* txn, const char* ns, BSONObj& cmd) -> Status { |