bool run(OperationContext* txn, const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { // calls renamecollection which does a global lock, so we must too: // Lock::GlobalWrite globalWriteLock(txn->lockState()); WriteUnitOfWork wunit(txn->recoveryUnit()); Client::Context ctx(txn, dbname); Database* db = ctx.db(); stopIndexBuilds(txn, db, jsobj); BackgroundOperation::assertNoBgOpInProgForDb(dbname.c_str()); string shortSource = jsobj.getStringField( "convertToCapped" ); string longSource = dbname + "." + shortSource; double size = jsobj.getField( "size" ).number(); if ( shortSource.empty() || size == 0 ) { errmsg = "invalid command spec"; return false; } string shortTmpName = str::stream() << "tmp.convertToCapped." << shortSource; string longTmpName = str::stream() << dbname << "." << shortTmpName; if ( db->getCollection( txn, longTmpName ) ) { Status status = db->dropCollection( txn, longTmpName ); if ( !status.isOK() ) return appendCommandStatus( result, status ); } Status status = cloneCollectionAsCapped( txn, db, shortSource, shortTmpName, size, true, false ); if ( !status.isOK() ) return appendCommandStatus( result, status ); verify( db->getCollection( txn, longTmpName ) ); status = db->dropCollection( txn, longSource ); if ( !status.isOK() ) return appendCommandStatus( result, status ); status = db->renameCollection( txn, longTmpName, longSource, false ); if ( !status.isOK() ) return appendCommandStatus( result, status ); if (!fromRepl) repl::logOp(txn, "c",(dbname + ".$cmd").c_str(), jsobj); wunit.commit(); return true; }
mongo::Status mongo::convertToCapped(OperationContext* opCtx, const NamespaceString& collectionName, long long size) { StringData dbname = collectionName.db(); StringData shortSource = collectionName.coll(); AutoGetDb autoDb(opCtx, collectionName.db(), MODE_X); bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() && !repl::ReplicationCoordinator::get(opCtx)->canAcceptWritesFor(opCtx, collectionName); if (userInitiatedWritesAndNotPrimary) { return Status(ErrorCodes::NotMaster, str::stream() << "Not primary while converting " << collectionName.ns() << " to a capped collection"); } Database* const db = autoDb.getDb(); if (!db) { return Status(ErrorCodes::NamespaceNotFound, str::stream() << "database " << dbname << " not found"); } BackgroundOperation::assertNoBgOpInProgForDb(dbname); // Generate a temporary collection name that will not collide with any existing collections. auto tmpNameResult = db->makeUniqueCollectionNamespace(opCtx, "tmp%%%%%.convertToCapped." + shortSource); if (!tmpNameResult.isOK()) { return tmpNameResult.getStatus().withContext( str::stream() << "Cannot generate temporary collection namespace to convert " << collectionName.ns() << " to a capped collection"); } const auto& longTmpName = tmpNameResult.getValue(); const auto shortTmpName = longTmpName.coll().toString(); { Status status = cloneCollectionAsCapped(opCtx, db, shortSource.toString(), shortTmpName, size, true); if (!status.isOK()) return status; } RenameCollectionOptions options; options.dropTarget = true; options.stayTemp = false; return renameCollection(opCtx, longTmpName, collectionName, options); }
bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { string from = jsobj.getStringField( "cloneCollectionAsCapped" ); string to = jsobj.getStringField( "toCollection" ); double size = jsobj.getField( "size" ).number(); bool temp = jsobj.getField( "temp" ).trueValue(); if ( from.empty() || to.empty() || size == 0 ) { errmsg = "invalid command spec"; return false; } Status status = cloneCollectionAsCapped( cc().database(), from, to, size, temp, true ); return appendCommandStatus( result, status ); }
bool run(OperationContext* txn, const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { string from = jsobj.getStringField( "cloneCollectionAsCapped" ); string to = jsobj.getStringField( "toCollection" ); double size = jsobj.getField( "size" ).number(); bool temp = jsobj.getField( "temp" ).trueValue(); if ( from.empty() || to.empty() || size == 0 ) { errmsg = "invalid command spec"; return false; } Lock::DBWrite dbXLock(txn->lockState(), dbname); Client::Context ctx(dbname); Status status = cloneCollectionAsCapped( txn, ctx.db(), from, to, size, temp, true ); return appendCommandStatus( result, status ); }
bool run(const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { Database* db = cc().database(); stopIndexBuilds(db, jsobj); BackgroundOperation::assertNoBgOpInProgForDb(dbname.c_str()); string shortSource = jsobj.getStringField( "convertToCapped" ); string longSource = dbname + "." + shortSource; double size = jsobj.getField( "size" ).number(); if ( shortSource.empty() || size == 0 ) { errmsg = "invalid command spec"; return false; } string shortTmpName = str::stream() << "tmp.convertToCapped." << shortSource; string longTmpName = str::stream() << dbname << "." << shortTmpName; if ( db->getCollection( longTmpName ) ) { Status status = db->dropCollection( longTmpName ); if ( !status.isOK() ) return appendCommandStatus( result, status ); } Status status = cloneCollectionAsCapped( db, shortSource, shortTmpName, size, true, false ); if ( !status.isOK() ) return appendCommandStatus( result, status ); verify( db->getCollection( longTmpName ) ); status = db->dropCollection( longSource ); if ( !status.isOK() ) return appendCommandStatus( result, status ); status = db->renameCollection( longTmpName, longSource, false ); return appendCommandStatus( result, status ); }
Status convertToCapped(OperationContext* txn, const NamespaceString& collectionName, double size) { StringData dbname = collectionName.db(); StringData shortSource = collectionName.coll(); ScopedTransaction transaction(txn, MODE_IX); AutoGetDb autoDb(txn, collectionName.db(), MODE_X); bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() && !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(dbname); if (userInitiatedWritesAndNotPrimary) { return Status(ErrorCodes::NotMaster, str::stream() << "Not primary while converting " << collectionName.ns() << " to a capped collection"); } Database* const db = autoDb.getDb(); if (!db) { return Status(ErrorCodes::DatabaseNotFound, str::stream() << "database " << dbname << " not found"); } stopIndexBuildsConvertToCapped(txn, db, collectionName); BackgroundOperation::assertNoBgOpInProgForDb(dbname); std::string shortTmpName = str::stream() << "tmp.convertToCapped." << shortSource; std::string longTmpName = str::stream() << dbname << "." << shortTmpName; WriteUnitOfWork wunit(txn); if (db->getCollection(longTmpName)) { Status status = db->dropCollection(txn, longTmpName); if (!status.isOK()) return status; } const bool shouldReplicateWrites = txn->writesAreReplicated(); txn->setReplicatedWrites(false); ON_BLOCK_EXIT(&OperationContext::setReplicatedWrites, txn, shouldReplicateWrites); Status status = cloneCollectionAsCapped(txn, db, shortSource.toString(), shortTmpName, size, true); if (!status.isOK()) { return status; } verify(db->getCollection(longTmpName)); status = db->dropCollection(txn, collectionName.ns()); txn->setReplicatedWrites(shouldReplicateWrites); if (!status.isOK()) return status; status = db->renameCollection(txn, longTmpName, collectionName.ns(), false); if (!status.isOK()) return status; getGlobalServiceContext()->getOpObserver()->onConvertToCapped( txn, NamespaceString(collectionName), size); wunit.commit(); return Status::OK(); }