void run() { string ns = "unittests.rollback_create_collection_and_indexes"; const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; NamespaceString nss(ns); dropDatabase(&opCtx, nss); Lock::DBLock dbXLock(&opCtx, nss.db(), MODE_X); OldClientContext ctx(&opCtx, nss.ns()); string idxNameA = "indexA"; string idxNameB = "indexB"; string idxNameC = "indexC"; 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 { WriteUnitOfWork uow(&opCtx); ASSERT(!collectionExists(&ctx, nss.ns())); ASSERT_OK(userCreateNS( &opCtx, ctx.db(), nss.ns(), BSONObj(), CollectionOptions::parseForCommand, false)); ASSERT(collectionExists(&ctx, nss.ns())); Collection* coll = ctx.db()->getCollection(&opCtx, nss); IndexCatalog* catalog = coll->getIndexCatalog(); ASSERT_OK(catalog->createIndexOnEmptyCollection(&opCtx, specA)); ASSERT_OK(catalog->createIndexOnEmptyCollection(&opCtx, specB)); ASSERT_OK(catalog->createIndexOnEmptyCollection(&opCtx, specC)); if (!rollback) { uow.commit(); } } // uow if (rollback) { ASSERT(!collectionExists(&ctx, ns)); } else { ASSERT(collectionExists(&ctx, ns)); ASSERT(indexReady(&opCtx, nss, idxNameA)); ASSERT(indexReady(&opCtx, nss, idxNameB)); ASSERT(indexReady(&opCtx, nss, idxNameC)); } }
Collection* Database::createCollection(OperationContext* txn, StringData ns, const CollectionOptions& options, bool createIdIndex) { massert(17399, "collection already exists", getCollection(ns) == NULL); massertNamespaceNotIndex(ns, "createCollection"); invariant(txn->lockState()->isDbLockedForMode(name(), MODE_X)); if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer && !(ns.startsWith("config.") || ns.startsWith("local.") || ns.startsWith("admin."))) { uasserted(14037, "can't create user databases on a --configsvr instance"); } if (NamespaceString::normal(ns)) { // This check only applies for actual collections, not indexes or other types of ns. uassert(17381, str::stream() << "fully qualified namespace " << ns << " is too long " << "(max is " << NamespaceString::MaxNsCollectionLen << " bytes)", ns.size() <= NamespaceString::MaxNsCollectionLen); } NamespaceString nss(ns); uassert(17316, "cannot create a blank collection", nss.coll() > 0); uassert(28838, "cannot create a non-capped oplog collection", options.capped || !nss.isOplog()); audit::logCreateCollection(&cc(), ns); txn->recoveryUnit()->registerChange(new AddCollectionChange(txn, this, ns)); Status status = _dbEntry->createCollection(txn, ns, options, true /*allocateDefaultSpace*/); massertNoTraceStatusOK(status); Collection* collection = _getOrCreateCollectionInstance(txn, ns); invariant(collection); _collections[ns] = collection; if (createIdIndex) { if (collection->requiresIdIndex()) { if (options.autoIndexId == CollectionOptions::YES || options.autoIndexId == CollectionOptions::DEFAULT) { IndexCatalog* ic = collection->getIndexCatalog(); uassertStatusOK(ic->createIndexOnEmptyCollection(txn, ic->getDefaultIdIndexSpec())); } } if (nss.isSystem()) { authindex::createSystemIndexes(txn, collection); } } auto opObserver = getGlobalServiceContext()->getOpObserver(); if (opObserver) opObserver->onCreateCollection(txn, nss, options); return collection; }
void run() { string ns = "unittests.rollback_set_index_head"; const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; NamespaceString nss(ns); dropDatabase(&opCtx, nss); createCollection(&opCtx, nss); AutoGetDb autoDb(&opCtx, nss.db(), MODE_X); Collection* coll = autoDb.getDb()->getCollection(&opCtx, nss); IndexCatalog* catalog = coll->getIndexCatalog(); string idxName = "a"; BSONObj spec = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxName << "v" << static_cast<int>(kIndexVersion)); { WriteUnitOfWork uow(&opCtx); ASSERT_OK(catalog->createIndexOnEmptyCollection(&opCtx, spec)); uow.commit(); } IndexDescriptor* indexDesc = catalog->findIndexByName(&opCtx, idxName); invariant(indexDesc); const IndexCatalogEntry* ice = catalog->getEntry(indexDesc); invariant(ice); HeadManager* headManager = ice->headManager(); const RecordId oldHead = headManager->getHead(&opCtx); ASSERT_EQ(oldHead, ice->head(&opCtx)); const RecordId dummyHead(123, 456); ASSERT_NE(oldHead, dummyHead); // END SETUP / START TEST { WriteUnitOfWork uow(&opCtx); headManager->setHead(&opCtx, dummyHead); ASSERT_EQ(ice->head(&opCtx), dummyHead); ASSERT_EQ(headManager->getHead(&opCtx), dummyHead); if (!rollback) { uow.commit(); } } if (rollback) { ASSERT_EQ(ice->head(&opCtx), oldHead); ASSERT_EQ(headManager->getHead(&opCtx), oldHead); } else { ASSERT_EQ(ice->head(&opCtx), dummyHead); ASSERT_EQ(headManager->getHead(&opCtx), dummyHead); } }
Collection* Database::createCollection( OperationContext* txn, const StringData& ns, const CollectionOptions& options, bool allocateDefaultSpace, bool createIdIndex ) { massert( 17399, "collection already exists", getCollection( txn, ns ) == NULL ); massertNamespaceNotIndex( ns, "createCollection" ); if ( serverGlobalParams.configsvr && !( ns.startsWith( "config." ) || ns.startsWith( "local." ) || ns.startsWith( "admin." ) ) ) { uasserted(14037, "can't create user databases on a --configsvr instance"); } if (NamespaceString::normal(ns)) { // This check only applies for actual collections, not indexes or other types of ns. uassert(17381, str::stream() << "fully qualified namespace " << ns << " is too long " << "(max is " << NamespaceString::MaxNsCollectionLen << " bytes)", ns.size() <= NamespaceString::MaxNsCollectionLen); } NamespaceString nss( ns ); uassert( 17316, "cannot create a blank collection", nss.coll() > 0 ); audit::logCreateCollection( currentClient.get(), ns ); txn->recoveryUnit()->registerChange( new AddCollectionChange(this, ns) ); Status status = _dbEntry->createCollection(txn, ns, options, allocateDefaultSpace); massertStatusOK(status); Collection* collection = getCollection(txn, ns); invariant(collection); if ( createIdIndex ) { if ( collection->requiresIdIndex() ) { if ( options.autoIndexId == CollectionOptions::YES || options.autoIndexId == CollectionOptions::DEFAULT ) { IndexCatalog* ic = collection->getIndexCatalog(); uassertStatusOK( ic->createIndexOnEmptyCollection(txn, ic->getDefaultIdIndexSpec())); } } if ( nss.isSystem() ) { authindex::createSystemIndexes( txn, collection ); } } return collection; }
Collection* Database::createCollection(OperationContext* txn, StringData ns, const CollectionOptions& options, bool createIdIndex) { invariant(txn->lockState()->isDbLockedForMode(name(), MODE_X)); invariant(!options.isView()); NamespaceString nss(ns); _checkCanCreateCollection(nss, options); audit::logCreateCollection(&cc(), ns); txn->recoveryUnit()->registerChange(new AddCollectionChange(txn, this, ns)); Status status = _dbEntry->createCollection(txn, ns, options, true /*allocateDefaultSpace*/); massertNoTraceStatusOK(status); Collection* collection = _getOrCreateCollectionInstance(txn, ns); invariant(collection); _collections[ns] = collection; 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.featureCompatibilityVersion.load(); IndexCatalog* ic = collection->getIndexCatalog(); uassertStatusOK(ic->createIndexOnEmptyCollection( txn, ic->getDefaultIdIndexSpec(featureCompatibilityVersion))); } } if (nss.isSystem()) { authindex::createSystemIndexes(txn, collection); } } auto opObserver = getGlobalServiceContext()->getOpObserver(); if (opObserver) opObserver->onCreateCollection(txn, nss, options); return collection; }
void run() { string ns = "unittests.rollback_drop_index"; const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; NamespaceString nss(ns); dropDatabase(&opCtx, nss); createCollection(&opCtx, nss); AutoGetDb autoDb(&opCtx, nss.db(), MODE_X); Collection* coll = autoDb.getDb()->getCollection(&opCtx, nss); IndexCatalog* catalog = coll->getIndexCatalog(); string idxName = "a"; BSONObj spec = BSON("ns" << ns << "key" << BSON("a" << 1) << "name" << idxName << "v" << static_cast<int>(kIndexVersion)); { WriteUnitOfWork uow(&opCtx); ASSERT_OK(catalog->createIndexOnEmptyCollection(&opCtx, spec)); insertRecord(&opCtx, nss, BSON("a" << 1)); insertRecord(&opCtx, nss, BSON("a" << 2)); insertRecord(&opCtx, nss, BSON("a" << 3)); uow.commit(); } ASSERT(indexReady(&opCtx, nss, idxName)); ASSERT_EQ(3u, getNumIndexEntries(&opCtx, nss, idxName)); // END SETUP / START TEST { WriteUnitOfWork uow(&opCtx); dropIndex(&opCtx, nss, idxName); ASSERT(!indexExists(&opCtx, nss, idxName)); if (!rollback) { uow.commit(); } } if (rollback) { ASSERT(indexExists(&opCtx, nss, idxName)); ASSERT(indexReady(&opCtx, nss, idxName)); ASSERT_EQ(3u, getNumIndexEntries(&opCtx, nss, idxName)); } else { ASSERT(!indexExists(&opCtx, nss, idxName)); } }
Collection* Database::createCollection(OperationContext* txn, StringData ns, const CollectionOptions& options, bool createIdIndex, const BSONObj& idIndex) { invariant(txn->lockState()->isDbLockedForMode(name(), MODE_X)); invariant(!options.isView()); NamespaceString nss(ns); _checkCanCreateCollection(nss, options); audit::logCreateCollection(&cc(), ns); Status status = _dbEntry->createCollection(txn, ns, options, true /*allocateDefaultSpace*/); massertNoTraceStatusOK(status); txn->recoveryUnit()->registerChange(new AddCollectionChange(txn, this, ns)); Collection* collection = _getOrCreateCollectionInstance(txn, ns); invariant(collection); _collections[ns] = collection; BSONObj fullIdIndexSpec; if (createIdIndex) { if (collection->requiresIdIndex()) { if (options.autoIndexId == CollectionOptions::YES || options.autoIndexId == CollectionOptions::DEFAULT) { const auto featureCompatibilityVersion = serverGlobalParams.featureCompatibility.version.load(); IndexCatalog* ic = collection->getIndexCatalog(); fullIdIndexSpec = uassertStatusOK(ic->createIndexOnEmptyCollection( txn, !idIndex.isEmpty() ? idIndex : ic->getDefaultIdIndexSpec(featureCompatibilityVersion))); } } if (nss.isSystem()) { authindex::createSystemIndexes(txn, collection); } } auto opObserver = getGlobalServiceContext()->getOpObserver(); if (opObserver) opObserver->onCreateCollection(txn, nss, options, fullIdIndexSpec); return collection; }