void FeatureCompatibilityVersion::setIfCleanStartup(OperationContext* txn, repl::StorageInterface* storageInterface) { if (serverGlobalParams.clusterRole != ClusterRole::ShardServer) { std::vector<std::string> dbNames; StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); storageEngine->listDatabases(&dbNames); for (auto&& dbName : dbNames) { if (dbName != "local") { return; } } // Insert featureCompatibilityDocument into admin.system.version. txn->setReplicatedWrites(false); NamespaceString nss(FeatureCompatibilityVersion::kCollection); CollectionOptions options; uassertStatusOK(storageInterface->createCollection(txn, nss, options)); uassertStatusOK(storageInterface->insertDocument( txn, nss, BSON("_id" << FeatureCompatibilityVersion::kParameterName << FeatureCompatibilityVersion::kVersionField << FeatureCompatibilityVersion::kVersion34))); // Update server parameter. serverGlobalParams.featureCompatibilityVersion.store( ServerGlobalParams::FeatureCompatibilityVersion_34); } }
bool WriteCmd::run(const string& dbName, BSONObj& cmdObj, int options, string& errMsg, BSONObjBuilder& result, bool fromRepl) { // Can't be run on secondaries (logTheOp() == false, slaveOk() == false). dassert( !fromRepl ); BatchedCommandRequest request( _writeType ); BatchedCommandResponse response; if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) { // Batch parse failure response.setOk( false ); response.setErrCode( 99999 ); response.setErrMessage( errMsg ); result.appendElements( response.toBSON() ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); return true; } // Note that this is a runCommmand, and therefore, the database and the collection name // are in different parts of the grammar for the command. But it's more convenient to // work with a NamespaceString. We built it here and replace it in the parsed command. // Internally, everything work with the namespace string as opposed to just the // collection name. NamespaceString nss(dbName, request.getNS()); request.setNS(nss.ns()); { // Commands with locktype == NONE need to acquire a Context in order to set // CurOp::_ns. Setting a CurOp's namespace is necessary for higher-level // functionality (e.g. profiling) to operate on the correct database (note that // WriteBatchExecutor doesn't do this for us, since its job is to create child CurOp // objects and operate on them). // // Acquire ReadContext momentarily, for satisfying this purpose. Client::ReadContext ctx( dbName + ".$cmd" ); } WriteBatchExecutor writeBatchExecutor(&cc(), &globalOpCounters, lastError.get()); writeBatchExecutor.executeBatch( request, &response ); result.appendElements( response.toBSON() ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); return true; }
void MMAPV1DatabaseCatalogEntry::_fillInEntry_inlock( OperationContext* txn, const StringData& ns, Entry* entry ) { NamespaceDetails* details = _namespaceIndex.details( ns ); invariant( details ); entry->catalogEntry.reset( new NamespaceDetailsCollectionCatalogEntry( ns, details, _getIndexRecordStore_inlock(), this ) ); NamespaceString nss( ns ); auto_ptr<NamespaceDetailsRSV1MetaData> md( new NamespaceDetailsRSV1MetaData( ns, details, _getNamespaceRecordStore_inlock() ) ); if ( details->isCapped ) { entry->recordStore.reset( new CappedRecordStoreV1( txn, NULL, //TOD(ERH) this will blow up :) ns, md.release(), &_extentManager, nss.coll() == "system.indexes" ) ); } else { entry->recordStore.reset( new SimpleRecordStoreV1( txn, ns, md.release(), &_extentManager, nss.coll() == "system.indexes" ) ); } }
void FeatureCompatibilityVersion::_runUpdateCommand(OperationContext* opCtx, UpdateBuilder builder) { DBDirectClient client(opCtx); NamespaceString nss(NamespaceString::kServerConfigurationNamespace); BSONObjBuilder updateCmd; updateCmd.append("update", nss.coll()); { BSONArrayBuilder updates(updateCmd.subarrayStart("updates")); { BSONObjBuilder updateSpec(updates.subobjStart()); { BSONObjBuilder queryFilter(updateSpec.subobjStart("q")); queryFilter.append("_id", FeatureCompatibilityVersionParser::kParameterName); } { BSONObjBuilder updateMods(updateSpec.subobjStart("u")); builder(std::move(updateMods)); } updateSpec.appendBool("upsert", true); } } updateCmd.append(WriteConcernOptions::kWriteConcernField, WriteConcernOptions::Majority); // Update the featureCompatibilityVersion document stored in the server configuration // collection. BSONObj updateResult; client.runCommand(nss.db().toString(), updateCmd.obj(), updateResult); uassertStatusOK(getStatusFromWriteCommandReply(updateResult)); }
virtual bool run(OperationContext* txn, const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { string coll = cmdObj[ "captrunc" ].valuestrsafe(); uassert( 13416, "captrunc must specify a collection", !coll.empty() ); NamespaceString nss( dbname, coll ); int n = cmdObj.getIntField( "n" ); bool inc = cmdObj.getBoolField( "inc" ); // inclusive range? Client::WriteContext ctx(txn, nss.ns() ); Collection* collection = ctx.ctx().db()->getCollection( txn, nss.ns() ); massert( 13417, "captrunc collection not found or empty", collection); boost::scoped_ptr<PlanExecutor> exec( InternalPlanner::collectionScan(txn, nss.ns(), collection, InternalPlanner::BACKWARD)); DiskLoc end; // We remove 'n' elements so the start is one past that for( int i = 0; i < n + 1; ++i ) { PlanExecutor::ExecState state = exec->getNext(NULL, &end); massert( 13418, "captrunc invalid n", PlanExecutor::ADVANCED == state); } collection->temp_cappedTruncateAfter( txn, end, inc ); ctx.commit(); return true; }
void FeatureCompatibilityVersion::setIfCleanStartup(OperationContext* txn) { std::vector<std::string> dbNames; StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); storageEngine->listDatabases(&dbNames); for (auto&& dbName : dbNames) { if (dbName != "local") { return; } } if (serverGlobalParams.clusterRole != ClusterRole::ShardServer) { // Insert featureCompatibilityDocument into admin.system.version. // Do not use writeConcern majority, because we may be holding locks. NamespaceString nss(FeatureCompatibilityVersion::kCollection); DBDirectClient client(txn); BSONObj result; client.runCommand( nss.db().toString(), BSON("insert" << nss.coll() << "documents" << BSON_ARRAY(BSON("_id" << FeatureCompatibilityVersion::kParameterName << FeatureCompatibilityVersion::kVersionField << FeatureCompatibilityVersion::kVersion34))), result); auto status = getStatusFromCommandResult(result); if (!status.isOK() && status != ErrorCodes::InterruptedAtShutdown) { uassertStatusOK(status); } // Update server parameter. serverGlobalParams.featureCompatibilityVersion.store( ServerGlobalParams::FeatureCompatibilityVersion_34); } }
void FeatureCompatibilityVersion::setIfCleanStartup(OperationContext* opCtx, repl::StorageInterface* storageInterface) { if (!isCleanStartUp()) return; // If the server was not started with --shardsvr, the default featureCompatibilityVersion on // clean startup is the upgrade version. If it was started with --shardsvr, the default // featureCompatibilityVersion is the downgrade version, so that it can be safely added to a // downgrade version cluster. The config server will run setFeatureCompatibilityVersion as part // of addShard. const bool storeUpgradeVersion = serverGlobalParams.clusterRole != ClusterRole::ShardServer; UnreplicatedWritesBlock unreplicatedWritesBlock(opCtx); NamespaceString nss(NamespaceString::kServerConfigurationNamespace); { CollectionOptions options; options.uuid = CollectionUUID::gen(); uassertStatusOK(storageInterface->createCollection(opCtx, nss, options)); } // We then insert the featureCompatibilityVersion document into the server configuration // collection. The server parameter will be updated on commit by the op observer. uassertStatusOK(storageInterface->insertDocument( opCtx, nss, repl::TimestampedBSONObj{ BSON("_id" << FeatureCompatibilityVersionParser::kParameterName << FeatureCompatibilityVersionParser::kVersionField << (storeUpgradeVersion ? FeatureCompatibilityVersionParser::kVersion40 : FeatureCompatibilityVersionParser::kVersion36)), Timestamp()}, repl::OpTime::kUninitializedTerm)); // No timestamp or term because this write is not // replicated. }
void FeatureCompatibilityVersion::set(OperationContext* txn, StringData version) { uassert(40284, "featureCompatibilityVersion must be '3.4' or '3.2'", version == FeatureCompatibilityVersion::kVersion34 || version == FeatureCompatibilityVersion::kVersion32); // Update admin.system.version. NamespaceString nss(FeatureCompatibilityVersion::kCollection); BSONObjBuilder updateCmd; updateCmd.append("update", nss.coll()); updateCmd.append( "updates", BSON_ARRAY(BSON("q" << BSON("_id" << FeatureCompatibilityVersion::kParameterName) << "u" << BSON(FeatureCompatibilityVersion::kVersionField << version) << "upsert" << true))); updateCmd.append("writeConcern", BSON("w" << "majority")); DBDirectClient client(txn); BSONObj result; client.runCommand(nss.db().toString(), updateCmd.obj(), result); uassertStatusOK(getStatusFromCommandResult(result)); uassertStatusOK(getWriteConcernStatusFromCommandResult(result)); // Update server parameter. if (version == FeatureCompatibilityVersion::kVersion34) { serverGlobalParams.featureCompatibilityVersion.store( ServerGlobalParams::FeatureCompatibilityVersion_34); } else if (version == FeatureCompatibilityVersion::kVersion32) { serverGlobalParams.featureCompatibilityVersion.store( ServerGlobalParams::FeatureCompatibilityVersion_32); } }
RecordStoreV1Base* MMAPV1DatabaseCatalogEntry::_getRecordStore( OperationContext* txn, const StringData& ns ) { // XXX TODO - CACHE NamespaceString nss( ns ); NamespaceDetails* details = _namespaceIndex.details( ns ); if ( !details ) { return NULL; } auto_ptr<NamespaceDetailsRSV1MetaData> md( new NamespaceDetailsRSV1MetaData( ns, details, _getNamespaceRecordStore( txn, ns ) ) ); if ( details->isCapped ) { return new CappedRecordStoreV1( txn, NULL, //TOD(ERH) this will blow up :) ns, md.release(), &_extentManager, nss.coll() == "system.indexes" ); } return new SimpleRecordStoreV1( txn, ns, md.release(), &_extentManager, nss.coll() == "system.indexes" ); }
void run() { string ns = "unittests.rollback_create_collection"; 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, ns); { WriteUnitOfWork uow(&opCtx); ASSERT(!collectionExists(&ctx, ns)); auto options = capped ? BSON("capped" << true << "size" << 1000) : BSONObj(); ASSERT_OK(userCreateNS( &opCtx, ctx.db(), ns, options, CollectionOptions::parseForCommand, defaultIndexes)); ASSERT(collectionExists(&ctx, ns)); if (!rollback) { uow.commit(); } } if (rollback) { ASSERT(!collectionExists(&ctx, ns)); } else { ASSERT(collectionExists(&ctx, ns)); } }
Status checkAuthForCommand(ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) override { NamespaceString nss(parseNs(dbname, cmdObj)); auto hasTerm = cmdObj.hasField(kTermField); return AuthorizationSession::get(client)->checkAuthForFind(nss, hasTerm); }
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; }
string Command::parseNsFullyQualified(const string& dbname, const BSONObj& cmdObj) const { string s = cmdObj.firstElement().valuestr(); NamespaceString nss(s); // these are for security, do not remove: massert(15962, "need to specify namespace" , !nss.db.empty() ); massert(15966, str::stream() << "dbname not ok in Command::parseNsFullyQualified: " << dbname , dbname == nss.db || dbname == "admin" ); return s; }
bool ClusterWriteCmd::run( const string& dbName, BSONObj& cmdObj, int options, string& errMsg, BSONObjBuilder& result, bool ) { BatchedCommandRequest request( _writeType ); BatchedCommandResponse response; // TODO: if we do namespace parsing, push this to the type if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) { // Batch parse failure response.setOk( false ); response.setN( 0 ); response.setErrCode( ErrorCodes::FailedToParse ); response.setErrMessage( errMsg ); dassert( response.isValid( &errMsg ) ); result.appendElements( response.toBSON() ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); return true; } NamespaceString nss( dbName, request.getNS() ); request.setNS( nss.ns() ); // App-level validation of a create index insert if ( request.isInsertIndexRequest() ) { if ( request.sizeWriteOps() != 1 || request.isWriteConcernSet() ) { // Invalid request to create index response.setOk( false ); response.setN( 0 ); response.setErrCode( ErrorCodes::CannotCreateIndex ); response.setErrMessage( "invalid batch request for index creation" ); dassert( response.isValid( &errMsg ) ); result.appendElements( response.toBSON() ); return false; } } clusterWrite( request, &response, true /* autosplit */ ); result.appendElements( response.toBSON() ); // TODO // There's a pending issue about how to report response here. If we use // the command infra-structure, we should reuse the 'errmsg' field. But // we have already filed that message inside the BatchCommandResponse. // return response.getOk(); return true; }
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); } }
void FeatureCompatibilityVersion::set(OperationContext* txn, StringData version) { uassert(40284, "featureCompatibilityVersion must be '3.4' or '3.2'. See " "http://dochub.mongodb.org/core/3.4-feature-compatibility.", version == FeatureCompatibilityVersionCommandParser::kVersion34 || version == FeatureCompatibilityVersionCommandParser::kVersion32); DBDirectClient client(txn); NamespaceString nss(FeatureCompatibilityVersion::kCollection); if (version == FeatureCompatibilityVersionCommandParser::kVersion34) { // We build a v=2 index on the "admin.system.version" collection as part of setting the // featureCompatibilityVersion to 3.4. This is a new index version that isn't supported by // versions of MongoDB earlier than 3.4 that will cause 3.2 secondaries to crash when it is // replicated. std::vector<BSONObj> indexSpecs{k32IncompatibleIndexSpec}; { ScopedTransaction transaction(txn, MODE_IX); AutoGetOrCreateDb autoDB(txn, nss.db(), MODE_X); uassert(ErrorCodes::NotMaster, str::stream() << "Cannot set featureCompatibilityVersion to '" << version << "'. Not primary while attempting to create index on: " << nss.ns(), repl::ReplicationCoordinator::get(txn->getServiceContext()) ->canAcceptWritesFor(nss)); IndexBuilder builder(k32IncompatibleIndexSpec, false); auto status = builder.buildInForeground(txn, autoDB.getDb()); uassertStatusOK(status); MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { WriteUnitOfWork wuow(txn); getGlobalServiceContext()->getOpObserver()->onCreateIndex( txn, autoDB.getDb()->getSystemIndexesName(), k32IncompatibleIndexSpec, false); wuow.commit(); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "FeatureCompatibilityVersion::set", nss.ns()); } // We then update the featureCompatibilityVersion document stored in the // "admin.system.version" collection. We do this after creating the v=2 index in order to // maintain the invariant that if the featureCompatibilityVersion is 3.4, then // 'k32IncompatibleIndexSpec' index exists on the "admin.system.version" collection. BSONObj updateResult; client.runCommand(nss.db().toString(), makeUpdateCommand(version, WriteConcernOptions::Majority), updateResult); uassertStatusOK(getStatusFromCommandResult(updateResult)); uassertStatusOK(getWriteConcernStatusFromCommandResult(updateResult)); // We then update the value of the featureCompatibilityVersion server parameter. serverGlobalParams.featureCompatibility.version.store( ServerGlobalParams::FeatureCompatibility::Version::k34); } else if (version == FeatureCompatibilityVersionCommandParser::kVersion32) {
TEST_F(SyncTailTest, MultiInitialSyncApplyPassesThroughSyncApplyErrorAfterFailingToRetryBadOp) { SyncTailWithLocalDocumentFetcher syncTail(BSON("_id" << 0 << "x" << 1)); NamespaceString nss("local." + _agent.getSuiteName() + "_" + _agent.getTestName()); OplogEntry op(BSON("op" << "x" << "ns" << nss.ns())); MultiApplier::OperationPtrs ops = {&op}; ASSERT_EQUALS(ErrorCodes::BadValue, multiInitialSyncApply_noAbort(_txn.get(), &ops, &syncTail)); }
void Request::process( int attempt ) { init(); int op = _m.operation(); verify( op > dbMsg ); int msgId = (int)(_m.header()->id); Timer t; LOG(3) << "Request::process begin ns: " << getns() << " msg id: " << msgId << " op: " << op << " attempt: " << attempt << endl; _d.markSet(); bool iscmd = false; if ( op == dbKillCursors ) { cursorCache.gotKillCursors( _m ); globalOpCounters.gotOp( op , iscmd ); } else if ( op == dbQuery ) { NamespaceString nss(getns()); iscmd = nss.isCommand() || nss.isSpecialCommand(); if (iscmd) { int n = _d.getQueryNToReturn(); uassert( 16978, str::stream() << "bad numberToReturn (" << n << ") for $cmd type ns - can only be 1 or -1", n == 1 || n == -1 ); STRATEGY->clientCommandOp(*this); } else { STRATEGY->queryOp( *this ); } globalOpCounters.gotOp( op , iscmd ); } else if ( op == dbGetMore ) { STRATEGY->getMore( *this ); globalOpCounters.gotOp( op , iscmd ); } else { STRATEGY->writeOp( op, *this ); // globalOpCounters are handled by write commands. } LOG(3) << "Request::process end ns: " << getns() << " msg id: " << msgId << " op: " << op << " attempt: " << attempt << " " << t.millis() << "ms" << endl; }
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; }
void ChunkManager::calcInitSplitsAndShards(OperationContext* txn, const ShardId& primaryShardId, const vector<BSONObj>* initPoints, const set<ShardId>* initShardIds, vector<BSONObj>* splitPoints, vector<ShardId>* shardIds) const { verify(_chunkMap.size() == 0); Chunk c(this, _keyPattern.getKeyPattern().globalMin(), _keyPattern.getKeyPattern().globalMax(), primaryShardId); if (!initPoints || !initPoints->size()) { // discover split points const auto primaryShard = grid.shardRegistry()->getShard(txn, primaryShardId); auto targetStatus = primaryShard->getTargeter()->findHost({ReadPreference::PrimaryPreferred, TagSet{}}); uassertStatusOK(targetStatus); NamespaceString nss(getns()); auto result = grid.shardRegistry()->runCommand( txn, targetStatus.getValue(), nss.db().toString(), BSON("count" << nss.coll())); long long numObjects = 0; uassertStatusOK(result.getStatus()); uassertStatusOK(Command::getStatusFromCommandResult(result.getValue())); uassertStatusOK(bsonExtractIntegerField(result.getValue(), "n", &numObjects)); if (numObjects > 0) c.pickSplitVector(txn, *splitPoints, Chunk::MaxChunkSize); // since docs already exists, must use primary shard shardIds->push_back(primaryShardId); } else { // make sure points are unique and ordered set<BSONObj> orderedPts; for (unsigned i = 0; i < initPoints->size(); ++i) { BSONObj pt = (*initPoints)[i]; orderedPts.insert(pt); } for (set<BSONObj>::iterator it = orderedPts.begin(); it != orderedPts.end(); ++it) { splitPoints->push_back(*it); } if (!initShardIds || !initShardIds->size()) { // If not specified, only use the primary shard (note that it's not safe for mongos // to put initial chunks on other shards without the primary mongod knowing). shardIds->push_back(primaryShardId); } else { std::copy(initShardIds->begin(), initShardIds->end(), std::back_inserter(*shardIds)); } } }
TEST_F(SyncTailTest, MultiSyncApplyFallsBackOnApplyingInsertsIndividuallyWhenGroupedInsertFails) { int seconds = 0; auto makeOp = [&seconds](const NamespaceString& nss) { return makeInsertDocumentOplogEntry( {Timestamp(Seconds(seconds), 0), 1LL}, nss, BSON("_id" << seconds++)); }; NamespaceString nss("test." + _agent.getSuiteName() + "_" + _agent.getTestName() + "_1"); auto createOp = makeCreateCollectionOplogEntry({Timestamp(Seconds(seconds++), 0), 1LL}, nss); // Generate operations to apply: // {create}, {insert_1}, {insert_2}, .. {insert_(limit)}, {insert_(limit+1)} std::size_t limit = 64; MultiApplier::Operations insertOps; for (std::size_t i = 0; i < limit + 1; ++i) { insertOps.push_back(makeOp(nss)); } MultiApplier::Operations operationsToApply; operationsToApply.push_back(createOp); std::copy(insertOps.begin(), insertOps.end(), std::back_inserter(operationsToApply)); std::size_t numFailedGroupedInserts = 0; MultiApplier::Operations operationsApplied; auto syncApply = [&numFailedGroupedInserts, &operationsApplied](OperationContext*, const BSONObj& op, bool) -> Status { // Reject grouped insert operations. if (op["o"].type() == BSONType::Array) { numFailedGroupedInserts++; return {ErrorCodes::OperationFailed, "grouped inserts not supported"}; } operationsApplied.push_back(OplogEntry(op)); return Status::OK(); }; MultiApplier::OperationPtrs ops; for (auto&& op : operationsToApply) { ops.push_back(&op); } ASSERT_OK(multiSyncApply_noAbort(_txn.get(), &ops, syncApply)); // On failing to apply the grouped insert operation, multiSyncApply should apply the operations // as given in "operationsToApply": // {create}, {insert_1}, {insert_2}, .. {insert_(limit)}, {insert_(limit+1)} ASSERT_EQUALS(limit + 2, operationsApplied.size()); ASSERT_EQUALS(createOp, operationsApplied[0]); for (std::size_t i = 0; i < limit + 1; ++i) { const auto& insertOp = insertOps[i]; ASSERT_EQUALS(insertOp, operationsApplied[i + 1]); } // Ensure that multiSyncApply does not attempt to group remaining operations in first failed // grouped insert operation. ASSERT_EQUALS(1U, numFailedGroupedInserts); }
TEST_F(SyncTailTest, MultiInitialSyncApplyDisablesDocumentValidationWhileApplyingOperations) { SyncTailWithOperationContextChecker syncTail; NamespaceString nss("local." + _agent.getSuiteName() + "_" + _agent.getTestName()); ASSERT_TRUE(_txn->writesAreReplicated()); ASSERT_FALSE(documentValidationDisabled(_txn.get())); ASSERT_FALSE(_txn->lockState()->isBatchWriter()); auto op = makeUpdateDocumentOplogEntry( {Timestamp(Seconds(1), 0), 1LL}, nss, BSON("_id" << 0), BSON("_id" << 0 << "x" << 2)); MultiApplier::OperationPtrs ops = {&op}; ASSERT_OK(multiInitialSyncApply_noAbort(_txn.get(), &ops, &syncTail)); }
TEST_F(SyncTailTest, MultiInitialSyncApplyPassesThroughShouldSyncTailRetryError) { SyncTail syncTail(nullptr, SyncTail::MultiSyncApplyFunc(), nullptr); NamespaceString nss("local." + _agent.getSuiteName() + "_" + _agent.getTestName()); auto op = makeUpdateDocumentOplogEntry( {Timestamp(Seconds(1), 0), 1LL}, nss, BSON("_id" << 0), BSON("_id" << 0 << "x" << 2)); ASSERT_THROWS_CODE( syncTail.shouldRetry(_txn.get(), op.raw), mongo::UserException, ErrorCodes::FailedToParse); MultiApplier::OperationPtrs ops = {&op}; ASSERT_EQUALS(ErrorCodes::FailedToParse, multiInitialSyncApply_noAbort(_txn.get(), &ops, &syncTail)); }
RecordStoreV1Base* MMAPV1DatabaseCatalogEntry::_getIndexRecordStore( OperationContext* txn ) { NamespaceString nss( name(), "system.indexes" ); RecordStoreV1Base* rs = _getRecordStore( txn, nss.ns() ); if ( rs != NULL ) return rs; CollectionOptions options; Status status = createCollection( txn, nss.ns(), options, true ); massertStatusOK( status ); rs = _getRecordStore( txn, nss.ns() ); invariant( rs ); return rs; }
TEST_F(SyncTailTest, MultiSyncApplyPassesThroughSyncApplyErrorAfterFailingToApplyOperation) { NamespaceString nss("local." + _agent.getSuiteName() + "_" + _agent.getTestName()); OplogEntry op(BSON("op" << "x" << "ns" << nss.ns())); auto syncApply = [](OperationContext*, const BSONObj&, bool) -> Status { return {ErrorCodes::OperationFailed, ""}; }; MultiApplier::OperationPtrs ops = {&op}; ASSERT_EQUALS(ErrorCodes::OperationFailed, multiSyncApply_noAbort(_txn.get(), &ops, syncApply)); }
NamespaceString Command::parseNsCollectionRequired(const string& dbname, const BSONObj& cmdObj) const { // Accepts both BSON String and Symbol for collection name per SERVER-16260 // TODO(kangas) remove Symbol support in MongoDB 3.0 after Ruby driver audit BSONElement first = cmdObj.firstElement(); uassert(40072, str::stream() << "collection name has invalid type " << typeName(first.type()), first.canonicalType() == canonicalizeBSONType(mongo::String)); NamespaceString nss(dbname, first.valuestr()); uassert(ErrorCodes::InvalidNamespace, "Not a valid namespace", nss.isValid()); return nss; }
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; }
TEST_F(KVDropPendingIdentReaperTest, AddDropPendingIdentAcceptsNullDropTimestamp) { Timestamp nullDropTimestamp; NamespaceString nss("test.foo"); constexpr auto ident = "myident"_sd; auto engine = getEngine(); KVDropPendingIdentReaper reaper(engine); reaper.addDropPendingIdent(nullDropTimestamp, nss, ident); ASSERT_EQUALS(nullDropTimestamp, *reaper.getEarliestDropTimestamp()); auto opCtx = makeOpCtx(); reaper.dropIdentsOlderThan(opCtx.get(), {Seconds(100), 0}); ASSERT_EQUALS(1U, engine->droppedIdents.size()); ASSERT_EQUALS(ident, engine->droppedIdents.front()); }
TEST_F(SyncTailTest, MultiSyncApplyUsesLimitWhenGroupingInsertOperation) { int seconds = 0; auto makeOp = [&seconds](const NamespaceString& nss) { return makeInsertDocumentOplogEntry( {Timestamp(Seconds(seconds), 0), 1LL}, nss, BSON("_id" << seconds++)); }; NamespaceString nss("test." + _agent.getSuiteName() + "_" + _agent.getTestName() + "_1"); auto createOp = makeCreateCollectionOplogEntry({Timestamp(Seconds(seconds++), 0), 1LL}, nss); // Generate operations to apply: // {create}, {insert_1}, {insert_2}, .. {insert_(limit)}, {insert_(limit+1)} std::size_t limit = 64; MultiApplier::Operations insertOps; for (std::size_t i = 0; i < limit + 1; ++i) { insertOps.push_back(makeOp(nss)); } MultiApplier::Operations operationsToApply; operationsToApply.push_back(createOp); std::copy(insertOps.begin(), insertOps.end(), std::back_inserter(operationsToApply)); MultiApplier::Operations operationsApplied; auto syncApply = [&operationsApplied](OperationContext*, const BSONObj& op, bool) { operationsApplied.push_back(OplogEntry(op)); return Status::OK(); }; MultiApplier::OperationPtrs ops; for (auto&& op : operationsToApply) { ops.push_back(&op); } ASSERT_OK(multiSyncApply_noAbort(_txn.get(), &ops, syncApply)); // multiSyncApply should combine operations as follows: // {create}, {grouped_insert}, {insert_(limit+1)} ASSERT_EQUALS(3U, operationsApplied.size()); ASSERT_EQUALS(createOp, operationsApplied[0]); const auto& groupedInsertOp = operationsApplied[1]; ASSERT_EQUALS(insertOps.front().getOpTime(), groupedInsertOp.getOpTime()); ASSERT_EQUALS(insertOps.front().ns, groupedInsertOp.ns); ASSERT_EQUALS(BSONType::Array, groupedInsertOp.o.type()); auto groupedInsertDocuments = groupedInsertOp.o.Array(); ASSERT_EQUALS(limit, groupedInsertDocuments.size()); for (std::size_t i = 0; i < limit; ++i) { const auto& insertOp = insertOps[i]; ASSERT_EQUALS(insertOp.o.Obj(), groupedInsertDocuments[i].Obj()); } // (limit + 1)-th insert operations should not be included in group of first (limit) inserts. ASSERT_EQUALS(insertOps.back(), operationsApplied[2]); }
TEST_F(SyncTailTest, MultiInitialSyncApplyDoesNotRetryFailedUpdateIfDocumentIsMissingFromSyncSource) { BSONObj emptyDoc; SyncTailWithLocalDocumentFetcher syncTail(emptyDoc); NamespaceString nss("local." + _agent.getSuiteName() + "_" + _agent.getTestName()); auto op = makeUpdateDocumentOplogEntry( {Timestamp(Seconds(1), 0), 1LL}, nss, BSON("_id" << 0), BSON("_id" << 0 << "x" << 2)); MultiApplier::OperationPtrs ops = {&op}; ASSERT_OK(multiInitialSyncApply_noAbort(_txn.get(), &ops, &syncTail)); // Since the missing document is not found on the sync source, the collection referenced by // the failed operation should not be automatically created. ASSERT_FALSE(AutoGetCollectionForRead(_txn.get(), nss).getCollection()); }