diff options
-rw-r--r-- | jstests/replsets/drop_collections_two_phase_long_index_names.js | 13 | ||||
-rw-r--r-- | src/mongo/db/catalog/database_impl.cpp | 71 |
2 files changed, 49 insertions, 35 deletions
diff --git a/jstests/replsets/drop_collections_two_phase_long_index_names.js b/jstests/replsets/drop_collections_two_phase_long_index_names.js index 576d1a0b425..46745a27427 100644 --- a/jstests/replsets/drop_collections_two_phase_long_index_names.js +++ b/jstests/replsets/drop_collections_two_phase_long_index_names.js @@ -55,6 +55,19 @@ assert(indexes.find(idx => idx.name === shortIndexName)); assert.eq(undefined, indexes.find(idx => idx.name === longIndexName)); + // Check that index drop appears before collection drop in the oplog. + const oplogColl = primary.getCollection('local.oplog.rs'); + const cmdNs = primaryDB.getCollection('$cmd').getFullName(); + const dropOplogEntry = oplogColl.findOne({ns: cmdNs, o: {drop: collName}}); + const dropIndexOplogEntry = + oplogColl.findOne({ns: cmdNs, o: {dropIndexes: collName, index: longIndexName}}); + const dropTimestamp = dropOplogEntry.ts; + const dropIndexTimestamp = dropIndexOplogEntry.ts; + assert.lt(dropIndexTimestamp, + dropTimestamp, + 'index was not dropped before collection. index drop: ' + + tojson(dropIndexOplogEntry) + ' . collection drop: ' + tojson(dropOplogEntry)); + twoPhaseDropTest.commitDropCollection(collName); replTest.stopSet(); diff --git a/src/mongo/db/catalog/database_impl.cpp b/src/mongo/db/catalog/database_impl.cpp index 22399430260..7b829e6da16 100644 --- a/src/mongo/db/catalog/database_impl.cpp +++ b/src/mongo/db/catalog/database_impl.cpp @@ -523,39 +523,11 @@ Status DatabaseImpl::dropCollectionEvenIfSystem(OperationContext* opCtx, // Replicated collections will be renamed with a special drop-pending namespace and dropped when // the replica set optime reaches the drop optime. if (dropOpTime.isNull()) { - dropOpTime = opObserver->onDropCollection(opCtx, fullns, uuid); - - // Drop collection immediately if OpObserver did not write entry to oplog. - // After writing the oplog entry, all errors are fatal. See getNextOpTime() comments in - // oplog.cpp. - if (dropOpTime.isNull()) { - log() << "dropCollection: " << fullns - << " - no drop optime available for pending-drop. " - << "Dropping collection immediately."; - fassertStatusOK(40462, _finishDropCollection(opCtx, fullns, collection)); - return Status::OK(); - } - } else { - // If we are provided with a valid 'dropOpTime', it means we are dropping this collection - // in the context of applying an oplog entry on a secondary. - // OpObserver::onDropCollection() should be returning a null OpTime because we should not be - // writing to the oplog. - auto opTime = opObserver->onDropCollection(opCtx, fullns, uuid); - if (!opTime.isNull()) { - severe() << "dropCollection: " << fullns - << " - unexpected oplog entry written to the oplog with optime " << opTime; - fassertFailed(40468); - } - } - - auto dpns = fullns.makeDropPendingNamespace(dropOpTime); - - // MMAPv1 requires that index namespaces are subject to the same length constraints as indexes - // in collections that are not in a drop-pending state. Therefore, we check if the drop-pending - // namespace is too long for any index names in the collection. - // These indexes are dropped regardless of the storage engine on the current node because we may - // still have nodes running MMAPv1 in the replica set. - { + // MMAPv1 requires that index namespaces are subject to the same length constraints as + // indexes in collections that are not in a drop-pending state. Therefore, we check if the + // drop-pending namespace is too long for any index names in the collection. + // These indexes are dropped regardless of the storage engine on the current node because we + // may still have nodes running MMAPv1 in the replica set. // Compile a list of any indexes that would become too long following the drop-pending // rename. In the case that this collection drop gets rolled back, this will incur a @@ -564,10 +536,12 @@ Status DatabaseImpl::dropCollectionEvenIfSystem(OperationContext* opCtx, std::vector<IndexDescriptor*> indexesToDrop; auto indexIter = collection->getIndexCatalog()->getIndexIterator(opCtx, true); - // Determine which index names are too long. + // Determine which index names are too long. Since we don't have the collection drop optime + // at this time, use the maximum optime to check the index names. + auto longDpns = fullns.makeDropPendingNamespace(repl::OpTime::max()); while (indexIter.more()) { auto index = indexIter.next(); - auto status = dpns.checkLengthForRename(index->indexName().size()); + auto status = longDpns.checkLengthForRename(index->indexName().size()); if (!status.isOK()) { indexesToDrop.push_back(index); } @@ -582,8 +556,35 @@ Status DatabaseImpl::dropCollectionEvenIfSystem(OperationContext* opCtx, opObserver->onDropIndex( opCtx, fullns, collection->uuid(), index->indexName(), index->infoObj()); } + + // Log oplog entry for collection drop and proceed to complete rest of two phase drop + // process. + dropOpTime = opObserver->onDropCollection(opCtx, fullns, uuid); + + // Drop collection immediately if OpObserver did not write entry to oplog. + // After writing the oplog entry, all errors are fatal. See getNextOpTime() comments in + // oplog.cpp. + if (dropOpTime.isNull()) { + log() << "dropCollection: " << fullns + << " - no drop optime available for pending-drop. " + << "Dropping collection immediately."; + fassertStatusOK(40462, _finishDropCollection(opCtx, fullns, collection)); + return Status::OK(); + } + } else { + // If we are provided with a valid 'dropOpTime', it means we are dropping this collection + // in the context of applying an oplog entry on a secondary. + // OpObserver::onDropCollection() should be returning a null OpTime because we should not be + // writing to the oplog. + auto opTime = opObserver->onDropCollection(opCtx, fullns, uuid); + if (!opTime.isNull()) { + severe() << "dropCollection: " << fullns + << " - unexpected oplog entry written to the oplog with optime " << opTime; + fassertFailed(40468); + } } + auto dpns = fullns.makeDropPendingNamespace(dropOpTime); // Rename collection using drop-pending namespace generated from drop optime. const bool stayTemp = true; |