summaryrefslogtreecommitdiff
path: root/src/mongo/dbtests/indexupdatetests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/dbtests/indexupdatetests.cpp')
-rw-r--r--src/mongo/dbtests/indexupdatetests.cpp265
1 files changed, 144 insertions, 121 deletions
diff --git a/src/mongo/dbtests/indexupdatetests.cpp b/src/mongo/dbtests/indexupdatetests.cpp
index 19b1a22a8c5..21e45f0adbd 100644
--- a/src/mongo/dbtests/indexupdatetests.cpp
+++ b/src/mongo/dbtests/indexupdatetests.cpp
@@ -34,6 +34,8 @@
#include "mongo/db/catalog/collection.h"
#include "mongo/db/catalog/index_catalog.h"
#include "mongo/db/catalog/multi_index_block.h"
+#include "mongo/db/catalog/uncommitted_collections.h"
+#include "mongo/db/catalog_raii.h"
#include "mongo/db/client.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/dbdirectclient.h"
@@ -58,33 +60,46 @@ static const NamespaceString _nss = NamespaceString(_ns);
*/
class IndexBuildBase {
public:
- IndexBuildBase() : _ctx(&_opCtx, _ns), _client(&_opCtx) {
- _client.createCollection(_ns);
+ IndexBuildBase() {
+ regenOpCtx();
+
+ AutoGetOrCreateDb db(_opCtx, _nss.db(), LockMode::MODE_IX);
+ WriteUnitOfWork wuow(_opCtx);
+ Lock::CollectionLock lk(_opCtx, _nss, LockMode::MODE_IX);
+ db.getDb()->createCollection(_opCtx, _nss);
+ wuow.commit();
}
+
~IndexBuildBase() {
- _client.dropCollection(_ns);
getGlobalServiceContext()->unsetKillAllOperations();
+
+ AutoGetOrCreateDb db(_opCtx, _nss.db(), LockMode::MODE_IX);
+ WriteUnitOfWork wuow(_opCtx);
+ Lock::CollectionLock lk(_opCtx, _nss, LockMode::MODE_X);
+ ASSERT_OK(db.getDb()->dropCollection(_opCtx, _nss, {}));
+ wuow.commit();
}
+
Collection* collection() {
- return _ctx.getCollection();
+ return CollectionCatalog::get(_opCtx).lookupCollectionByNamespace(_opCtx, _nss);
}
protected:
- Status createIndex(const std::string& dbname, const BSONObj& indexSpec);
+ Status createIndex(const BSONObj& indexSpec);
bool buildIndexInterrupted(const BSONObj& key) {
try {
MultiIndexBlock indexer;
ON_BLOCK_EXIT([&] {
- indexer.cleanUpAfterBuild(&_opCtx, collection(), MultiIndexBlock::kNoopOnCleanUpFn);
+ indexer.cleanUpAfterBuild(_opCtx, collection(), MultiIndexBlock::kNoopOnCleanUpFn);
});
uassertStatusOK(
- indexer.init(&_opCtx, collection(), key, MultiIndexBlock::kNoopOnInitFn));
- uassertStatusOK(indexer.insertAllDocumentsInCollection(&_opCtx, collection()));
- WriteUnitOfWork wunit(&_opCtx);
- ASSERT_OK(indexer.commit(&_opCtx,
+ indexer.init(_opCtx, collection(), key, MultiIndexBlock::kNoopOnInitFn));
+ uassertStatusOK(indexer.insertAllDocumentsInCollection(_opCtx, collection()));
+ WriteUnitOfWork wunit(_opCtx);
+ ASSERT_OK(indexer.commit(_opCtx,
collection(),
MultiIndexBlock::kNoopOnCreateEachFn,
MultiIndexBlock::kNoopOnCommitFn));
@@ -98,10 +113,14 @@ protected:
return false;
}
- const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext();
- OperationContext& _opCtx = *_txnPtr;
- dbtests::WriteContextForTests _ctx;
- DBDirectClient _client;
+ void regenOpCtx() {
+ _txnPtr = nullptr;
+ _txnPtr = cc().makeOperationContext();
+ _opCtx = _txnPtr.get();
+ }
+
+ ServiceContext::UniqueOperationContext _txnPtr; // = cc().makeOperationContext();
+ OperationContext* _opCtx; // = _txnPtr.get();
};
/** Index creation ignores unique constraints when told to. */
@@ -109,21 +128,18 @@ template <bool background>
class InsertBuildIgnoreUnique : public IndexBuildBase {
public:
void run() {
- // Create a new collection.
- Database* db = _ctx.db();
- Collection* coll;
+ AutoGetOrCreateDb dbRaii(_opCtx, _nss.db(), LockMode::MODE_IX);
+ Lock::CollectionLock collLk(_opCtx, _nss, LockMode::MODE_X);
+ Collection* coll = collection();
{
- WriteUnitOfWork wunit(&_opCtx);
- ASSERT_OK(db->dropCollection(&_opCtx, _nss));
- coll = db->createCollection(&_opCtx, _nss);
-
+ WriteUnitOfWork wunit(_opCtx);
OpDebug* const nullOpDebug = nullptr;
- ASSERT_OK(coll->insertDocument(&_opCtx,
+ ASSERT_OK(coll->insertDocument(_opCtx,
InsertStatement(BSON("_id" << 1 << "a"
<< "dup")),
nullOpDebug,
true));
- ASSERT_OK(coll->insertDocument(&_opCtx,
+ ASSERT_OK(coll->insertDocument(_opCtx,
InsertStatement(BSON("_id" << 2 << "a"
<< "dup")),
nullOpDebug,
@@ -141,15 +157,15 @@ public:
<< "background" << background);
ON_BLOCK_EXIT(
- [&] { indexer.cleanUpAfterBuild(&_opCtx, coll, MultiIndexBlock::kNoopOnCleanUpFn); });
+ [&] { indexer.cleanUpAfterBuild(_opCtx, coll, MultiIndexBlock::kNoopOnCleanUpFn); });
- ASSERT_OK(indexer.init(&_opCtx, coll, spec, MultiIndexBlock::kNoopOnInitFn).getStatus());
- ASSERT_OK(indexer.insertAllDocumentsInCollection(&_opCtx, coll));
- ASSERT_OK(indexer.checkConstraints(&_opCtx));
+ ASSERT_OK(indexer.init(_opCtx, coll, spec, MultiIndexBlock::kNoopOnInitFn).getStatus());
+ ASSERT_OK(indexer.insertAllDocumentsInCollection(_opCtx, coll));
+ ASSERT_OK(indexer.checkConstraints(_opCtx));
- WriteUnitOfWork wunit(&_opCtx);
+ WriteUnitOfWork wunit(_opCtx);
ASSERT_OK(indexer.commit(
- &_opCtx, coll, MultiIndexBlock::kNoopOnCreateEachFn, MultiIndexBlock::kNoopOnCommitFn));
+ _opCtx, coll, MultiIndexBlock::kNoopOnCreateEachFn, MultiIndexBlock::kNoopOnCommitFn));
wunit.commit();
}
};
@@ -160,20 +176,19 @@ class InsertBuildEnforceUnique : public IndexBuildBase {
public:
void run() {
// Create a new collection.
- Database* db = _ctx.db();
- Collection* coll;
+ AutoGetOrCreateDb dbRaii(_opCtx, _nss.db(), LockMode::MODE_IX);
+ boost::optional<Lock::CollectionLock> collLk;
+ collLk.emplace(_opCtx, _nss, LockMode::MODE_IX);
+ Collection* coll = collection();
{
- WriteUnitOfWork wunit(&_opCtx);
- ASSERT_OK(db->dropCollection(&_opCtx, _nss));
- coll = db->createCollection(&_opCtx, _nss);
-
+ WriteUnitOfWork wunit(_opCtx);
OpDebug* const nullOpDebug = nullptr;
- ASSERT_OK(coll->insertDocument(&_opCtx,
+ ASSERT_OK(coll->insertDocument(_opCtx,
InsertStatement(BSON("_id" << 1 << "a"
<< "dup")),
nullOpDebug,
true));
- ASSERT_OK(coll->insertDocument(&_opCtx,
+ ASSERT_OK(coll->insertDocument(_opCtx,
InsertStatement(BSON("_id" << 2 << "a"
<< "dup")),
nullOpDebug,
@@ -189,19 +204,20 @@ public:
<< static_cast<int>(kIndexVersion) << "unique" << true
<< "background" << background);
+ collLk.emplace(_opCtx, _nss, LockMode::MODE_X);
ON_BLOCK_EXIT(
- [&] { indexer.cleanUpAfterBuild(&_opCtx, coll, MultiIndexBlock::kNoopOnCleanUpFn); });
+ [&] { indexer.cleanUpAfterBuild(_opCtx, coll, MultiIndexBlock::kNoopOnCleanUpFn); });
- ASSERT_OK(indexer.init(&_opCtx, coll, spec, MultiIndexBlock::kNoopOnInitFn).getStatus());
+ ASSERT_OK(indexer.init(_opCtx, coll, spec, MultiIndexBlock::kNoopOnInitFn).getStatus());
auto desc =
- coll->getIndexCatalog()->findIndexByName(&_opCtx, "a", true /* includeUnfinished */);
+ coll->getIndexCatalog()->findIndexByName(_opCtx, "a", true /* includeUnfinished */);
ASSERT(desc);
// Hybrid index builds check duplicates explicitly.
- ASSERT_OK(indexer.insertAllDocumentsInCollection(&_opCtx, coll));
+ ASSERT_OK(indexer.insertAllDocumentsInCollection(_opCtx, coll));
- auto status = indexer.checkConstraints(&_opCtx);
+ auto status = indexer.checkConstraints(_opCtx);
ASSERT_EQUALS(status.code(), ErrorCodes::DuplicateKey);
}
};
@@ -210,35 +226,42 @@ public:
class InsertBuildIndexInterrupt : public IndexBuildBase {
public:
void run() {
- // Create a new collection.
- Database* db = _ctx.db();
- Collection* coll;
{
- WriteUnitOfWork wunit(&_opCtx);
- ASSERT_OK(db->dropCollection(&_opCtx, _nss));
- coll = db->createCollection(&_opCtx, _nss);
- // Drop all indexes including id index.
- coll->getIndexCatalog()->dropAllIndexes(&_opCtx, true);
- // Insert some documents.
- int32_t nDocs = 1000;
- OpDebug* const nullOpDebug = nullptr;
- for (int32_t i = 0; i < nDocs; ++i) {
- ASSERT_OK(
- coll->insertDocument(&_opCtx, InsertStatement(BSON("a" << i)), nullOpDebug));
+ AutoGetOrCreateDb dbRaii(_opCtx, _nss.db(), LockMode::MODE_IX);
+ boost::optional<Lock::CollectionLock> collLk;
+ collLk.emplace(_opCtx, _nss, LockMode::MODE_X);
+
+ Collection* coll = collection();
+ {
+ WriteUnitOfWork wunit(_opCtx);
+ // Drop all indexes including id index.
+ coll->getIndexCatalog()->dropAllIndexes(_opCtx, true);
+ // Insert some documents.
+ int32_t nDocs = 1000;
+ OpDebug* const nullOpDebug = nullptr;
+ for (int32_t i = 0; i < nDocs; ++i) {
+ ASSERT_OK(
+ coll->insertDocument(_opCtx, InsertStatement(BSON("a" << i)), nullOpDebug));
+ }
+ wunit.commit();
}
- wunit.commit();
+ // Request an interrupt.
+ getGlobalServiceContext()->setKillAllOperations();
+ BSONObj indexInfo = BSON("key" << BSON("a" << 1) << "name"
+ << "a_1"
+ << "v" << static_cast<int>(kIndexVersion));
+ // The call is interrupted because mayInterrupt == true.
+ ASSERT_TRUE(buildIndexInterrupted(indexInfo));
+ // only want to interrupt the index build
+ getGlobalServiceContext()->unsetKillAllOperations();
}
- // Request an interrupt.
- getGlobalServiceContext()->setKillAllOperations();
- BSONObj indexInfo = BSON("key" << BSON("a" << 1) << "name"
- << "a_1"
- << "v" << static_cast<int>(kIndexVersion));
- // The call is interrupted because mayInterrupt == true.
- ASSERT_TRUE(buildIndexInterrupted(indexInfo));
- // only want to interrupt the index build
- getGlobalServiceContext()->unsetKillAllOperations();
+
+ regenOpCtx();
+ AutoGetDb dbRaii(_opCtx, _nss.db(), LockMode::MODE_IX);
+ boost::optional<Lock::CollectionLock> collLk;
+ collLk.emplace(_opCtx, _nss, LockMode::MODE_IX);
// The new index is not listed in the index catalog because the index build failed.
- ASSERT(!coll->getIndexCatalog()->findIndexByName(&_opCtx, "a_1"));
+ ASSERT(!collection()->getIndexCatalog()->findIndexByName(_opCtx, "a_1"));
}
};
@@ -251,62 +274,73 @@ public:
return;
}
- // Recreate the collection as capped, without an _id index.
- Database* db = _ctx.db();
- Collection* coll;
{
- WriteUnitOfWork wunit(&_opCtx);
- ASSERT_OK(db->dropCollection(&_opCtx, _nss));
+ // Recreate the collection as capped, without an _id index.
+ AutoGetOrCreateDb dbRaii(_opCtx, _nss.db(), LockMode::MODE_IX);
+ Database* db = dbRaii.getDb();
+ boost::optional<Lock::CollectionLock> collLk;
+ collLk.emplace(_opCtx, _nss, LockMode::MODE_X);
+
+ WriteUnitOfWork wunit(_opCtx);
+ ASSERT_OK(db->dropCollection(_opCtx, _nss));
CollectionOptions options;
options.capped = true;
options.cappedSize = 10 * 1024;
- coll = db->createCollection(&_opCtx, _nss, options);
- coll->getIndexCatalog()->dropAllIndexes(&_opCtx, true);
+ Collection* coll = db->createCollection(_opCtx, _nss, options);
+ coll->getIndexCatalog()->dropAllIndexes(_opCtx, true);
// Insert some documents.
int32_t nDocs = 1000;
OpDebug* const nullOpDebug = nullptr;
for (int32_t i = 0; i < nDocs; ++i) {
ASSERT_OK(coll->insertDocument(
- &_opCtx, InsertStatement(BSON("_id" << i)), nullOpDebug, true));
+ _opCtx, InsertStatement(BSON("_id" << i)), nullOpDebug, true));
}
wunit.commit();
+ // Request an interrupt.
+ getGlobalServiceContext()->setKillAllOperations();
+ BSONObj indexInfo = BSON("key" << BSON("_id" << 1) << "name"
+ << "_id_"
+ << "v" << static_cast<int>(kIndexVersion));
+ ASSERT_TRUE(buildIndexInterrupted(indexInfo));
+ // only want to interrupt the index build
+ getGlobalServiceContext()->unsetKillAllOperations();
}
- // Request an interrupt.
- getGlobalServiceContext()->setKillAllOperations();
- BSONObj indexInfo = BSON("key" << BSON("_id" << 1) << "name"
- << "_id_"
- << "v" << static_cast<int>(kIndexVersion));
- ASSERT_TRUE(buildIndexInterrupted(indexInfo));
- // only want to interrupt the index build
- getGlobalServiceContext()->unsetKillAllOperations();
+ regenOpCtx();
+ AutoGetOrCreateDb dbRaii(_opCtx, _nss.db(), LockMode::MODE_IX);
+ boost::optional<Lock::CollectionLock> collLk;
+ collLk.emplace(_opCtx, _nss, LockMode::MODE_IX);
+
// The new index is not listed in the index catalog because the index build failed.
- ASSERT(!coll->getIndexCatalog()->findIndexByName(&_opCtx, "_id_"));
+ ASSERT(!collection()->getIndexCatalog()->findIndexByName(_opCtx, "_id_"));
}
-};
+}; // namespace IndexUpdateTests
+
+Status IndexBuildBase::createIndex(const BSONObj& indexSpec) {
+ Lock::DBLock dbLk(_opCtx, _nss.db(), MODE_IX);
+ Lock::CollectionLock collLk(_opCtx, _nss, MODE_X);
-Status IndexBuildBase::createIndex(const std::string& dbname, const BSONObj& indexSpec) {
MultiIndexBlock indexer;
ON_BLOCK_EXIT([&] {
- indexer.cleanUpAfterBuild(&_opCtx, collection(), MultiIndexBlock::kNoopOnCleanUpFn);
+ indexer.cleanUpAfterBuild(_opCtx, collection(), MultiIndexBlock::kNoopOnCleanUpFn);
});
Status status =
- indexer.init(&_opCtx, collection(), indexSpec, MultiIndexBlock::kNoopOnInitFn).getStatus();
+ indexer.init(_opCtx, collection(), indexSpec, MultiIndexBlock::kNoopOnInitFn).getStatus();
if (status == ErrorCodes::IndexAlreadyExists) {
return Status::OK();
}
if (!status.isOK()) {
return status;
}
- status = indexer.insertAllDocumentsInCollection(&_opCtx, collection());
+ status = indexer.insertAllDocumentsInCollection(_opCtx, collection());
if (!status.isOK()) {
return status;
}
- status = indexer.checkConstraints(&_opCtx);
+ status = indexer.checkConstraints(_opCtx);
if (!status.isOK()) {
return status;
}
- WriteUnitOfWork wunit(&_opCtx);
- ASSERT_OK(indexer.commit(&_opCtx,
+ WriteUnitOfWork wunit(_opCtx);
+ ASSERT_OK(indexer.commit(_opCtx,
collection(),
MultiIndexBlock::kNoopOnCreateEachFn,
MultiIndexBlock::kNoopOnCommitFn));
@@ -320,8 +354,7 @@ Status IndexBuildBase::createIndex(const std::string& dbname, const BSONObj& ind
class SimpleCompoundIndex : public IndexBuildBase {
public:
SimpleCompoundIndex() {
- ASSERT_OK(createIndex("unittest",
- BSON("name"
+ ASSERT_OK(createIndex(BSON("name"
<< "x"
<< "key" << BSON("x" << 1 << "y" << 1) << "v"
<< static_cast<int>(kIndexVersion))));
@@ -333,8 +366,7 @@ public:
void run() {
// Cannot have same key spec with an option different from the existing one.
ASSERT_EQUALS(ErrorCodes::IndexOptionsConflict,
- createIndex("unittest",
- BSON("name"
+ createIndex(BSON("name"
<< "x"
<< "unique" << true << "key" << BSON("x" << 1 << "y" << 1)
<< "v" << static_cast<int>(kIndexVersion))));
@@ -344,8 +376,7 @@ public:
class SameSpecSameOptions : public SimpleCompoundIndex {
public:
void run() {
- ASSERT_OK(createIndex("unittest",
- BSON("name"
+ ASSERT_OK(createIndex(BSON("name"
<< "x"
<< "key" << BSON("x" << 1 << "y" << 1) << "v"
<< static_cast<int>(kIndexVersion))));
@@ -357,8 +388,7 @@ public:
void run() {
// Cannot create a different index with the same name as the existing one.
ASSERT_EQUALS(ErrorCodes::IndexKeySpecsConflict,
- createIndex("unittest",
- BSON("name"
+ createIndex(BSON("name"
<< "x"
<< "key" << BSON("y" << 1 << "x" << 1) << "v"
<< static_cast<int>(kIndexVersion))));
@@ -371,8 +401,7 @@ public:
class ComplexIndex : public IndexBuildBase {
public:
ComplexIndex() {
- ASSERT_OK(createIndex("unittests",
- BSON("name"
+ ASSERT_OK(createIndex(BSON("name"
<< "super"
<< "unique" << 1 << "sparse" << true << "expireAfterSeconds"
<< 3600 << "key"
@@ -389,8 +418,7 @@ public:
// the original. This will throw an IndexOptionsConflict as the index already exists under
// another name.
ASSERT_EQUALS(ErrorCodes::IndexOptionsConflict,
- createIndex("unittests",
- BSON("name"
+ createIndex(BSON("name"
<< "super2"
<< "expireAfterSeconds" << 3600 << "sparse" << true
<< "unique" << 1 << "key"
@@ -405,8 +433,7 @@ public:
void run() {
// Exactly the same specs with the existing one, only specified in a different order than
// the original, but with the same name.
- ASSERT_OK(createIndex("unittests",
- BSON("name"
+ ASSERT_OK(createIndex(BSON("name"
<< "super"
<< "expireAfterSeconds" << 3600 << "sparse" << true << "unique"
<< 1 << "key"
@@ -423,8 +450,7 @@ class SameSpecDifferentUnique : public ComplexIndex {
public:
void run() {
ASSERT_EQUALS(ErrorCodes::IndexOptionsConflict,
- createIndex("unittest",
- BSON("name"
+ createIndex(BSON("name"
<< "super2"
<< "unique" << false << "sparse" << true
<< "expireAfterSeconds" << 3600 << "key"
@@ -438,8 +464,7 @@ class SameSpecDifferentSparse : public ComplexIndex {
public:
void run() {
ASSERT_EQUALS(ErrorCodes::IndexOptionsConflict,
- createIndex("unittest",
- BSON("name"
+ createIndex(BSON("name"
<< "super2"
<< "unique" << 1 << "sparse" << false << "background" << true
<< "expireAfterSeconds" << 3600 << "key"
@@ -453,8 +478,7 @@ class SameSpecDifferentTTL : public ComplexIndex {
public:
void run() {
ASSERT_EQUALS(ErrorCodes::IndexOptionsConflict,
- createIndex("unittest",
- BSON("name"
+ createIndex(BSON("name"
<< "super2"
<< "unique" << 1 << "sparse" << true << "expireAfterSeconds"
<< 2400 << "key"
@@ -468,13 +492,13 @@ class StorageEngineOptions : public IndexBuildBase {
public:
void run() {
// "storageEngine" field has to be an object if present.
- ASSERT_NOT_OK(createIndex("unittest", _createSpec(12345)));
+ ASSERT_NOT_OK(createIndex(_createSpec(12345)));
// 'storageEngine' must not be empty.
- ASSERT_NOT_OK(createIndex("unittest", _createSpec(BSONObj())));
+ ASSERT_NOT_OK(createIndex(_createSpec(BSONObj())));
// Every field under "storageEngine" must match a registered storage engine.
- ASSERT_NOT_OK(createIndex("unittest", _createSpec(BSON("unknownEngine" << BSONObj()))));
+ ASSERT_NOT_OK(createIndex(_createSpec(BSON("unknownEngine" << BSONObj()))));
// Testing with 'wiredTiger' because the registered storage engine factory
// supports custom index options under 'storageEngine'.
@@ -483,20 +507,19 @@ public:
// Run 'wiredTiger' tests if the storage engine is supported.
if (isRegisteredStorageEngine(getGlobalServiceContext(), storageEngineName)) {
// Every field under "storageEngine" has to be an object.
- ASSERT_NOT_OK(createIndex("unittest", _createSpec(BSON(storageEngineName << 1))));
+ ASSERT_NOT_OK(createIndex(_createSpec(BSON(storageEngineName << 1))));
// Storage engine options must pass validation by the storage engine factory.
// For 'wiredTiger', embedded document must contain 'configString'.
- ASSERT_NOT_OK(createIndex(
- "unittest", _createSpec(BSON(storageEngineName << BSON("unknown" << 1)))));
+ ASSERT_NOT_OK(
+ createIndex(_createSpec(BSON(storageEngineName << BSON("unknown" << 1)))));
// Configuration string for 'wiredTiger' must be a string.
- ASSERT_NOT_OK(createIndex(
- "unittest", _createSpec(BSON(storageEngineName << BSON("configString" << 1)))));
+ ASSERT_NOT_OK(
+ createIndex(_createSpec(BSON(storageEngineName << BSON("configString" << 1)))));
// Valid 'wiredTiger' configuration.
ASSERT_OK(createIndex(
- "unittest",
_createSpec(BSON(storageEngineName << BSON("configString"
<< "block_compressor=zlib")))));
}