void NamespaceIndex::drop() { Lock::assertWriteLocked(_database); init(); if (!allocated()) { return; } string errmsg; BSONObjBuilder result; // This implementation is inefficient and slightly messy, but it was easy. // Feel free to improve it as necessary: // - The getCursor call will grab a table lock on .system.namespaces. // - We'll look at the entire system.namespaces collection just for one database. // - Code is duplicated to handle dropping system system collections in stages. vector<string> sysIndexesEntries; const string systemNamespacesNs = getSisterNS(_database, "system.namespaces"); NamespaceDetails *sysNsd = nsdetails(systemNamespacesNs); for (shared_ptr<Cursor> c(BasicCursor::make(sysNsd)); c->ok(); c->advance()) { const BSONObj nsObj = c->current(); const StringData ns = nsObj["name"].Stringdata(); if (nsToDatabaseSubstring(ns) != _database) { // Not part of this database, skip. continue; } if (nsToCollectionSubstring(ns) == "system.indexes") { // Save .system.indexes collection for last, because dropCollection deletes from it. sysIndexesEntries.push_back(ns.toString()); } else { dropCollection(ns, errmsg, result, true); } } if (sysNsd != NULL) { // The .system.namespaces collection does not include itself. dropCollection(systemNamespacesNs, errmsg, result, true); } // Now drop the system.indexes entries. for (vector<string>::const_iterator it = sysIndexesEntries.begin(); it != sysIndexesEntries.end(); it++) { // Need to close any existing handle before drop. const string &ns = *it; dropCollection(ns, errmsg, result, true); } // Everything that was open should have been closed due to drop. verify(_namespaces.empty()); shared_ptr<storage::Dictionary> nsdb = _nsdb; _nsdb.reset(); const int r = nsdb->close(); if (r != 0) { storage::handle_ydb_error(r); } storage::db_remove(_nsdbFilename); }
void deleteOplogFiles() { rsOplogDetails = NULL; rsOplogRefsDetails = NULL; replInfoDetails = NULL; Client::Context ctx(rsoplog, dbpath); // TODO: code review this for possible error cases // although, I don't think we care about error cases, // just that after we exit, oplog files don't exist BSONObjBuilder out; string errmsg; dropCollection(rsoplog, errmsg, out); dropCollection(rsOplogRefs, errmsg, out); dropCollection(rsReplInfo, errmsg, out); }
void Database::clearTmpCollections(OperationContext* txn) { txn->lockState()->assertWriteLocked( _name ); list<string> collections; _dbEntry->getCollectionNamespaces( &collections ); for ( list<string>::iterator i = collections.begin(); i != collections.end(); ++i ) { string ns = *i; invariant( NamespaceString::normal( ns ) ); CollectionCatalogEntry* coll = _dbEntry->getCollectionCatalogEntry( txn, ns ); CollectionOptions options = coll->getCollectionOptions( txn ); if ( !options.temp ) continue; WriteUnitOfWork wunit(txn); Status status = dropCollection( txn, ns ); if ( !status.isOK() ) { warning() << "could not drop temp collection '" << ns << "': " << status; continue; } string cmdNs = _name + ".$cmd"; repl::logOp( txn, "c", cmdNs.c_str(), BSON( "drop" << nsToCollectionSubstring( ns ) ) ); wunit.commit(); } }
void Database::clearTmpCollections(OperationContext* txn) { invariant(txn->lockState()->isDbLockedForMode(name(), MODE_X)); list<string> collections; _dbEntry->getCollectionNamespaces(&collections); for (list<string>::iterator i = collections.begin(); i != collections.end(); ++i) { string ns = *i; invariant(NamespaceString::normal(ns)); CollectionCatalogEntry* coll = _dbEntry->getCollectionCatalogEntry(ns); CollectionOptions options = coll->getCollectionOptions(txn); if (!options.temp) continue; try { WriteUnitOfWork wunit(txn); Status status = dropCollection(txn, ns); if (!status.isOK()) { warning() << "could not drop temp collection '" << ns << "': " << redact(status); continue; } wunit.commit(); } catch (const WriteConflictException& exp) { warning() << "could not drop temp collection '" << ns << "' due to " "WriteConflictException"; txn->recoveryUnit()->abandonSnapshot(); } } }
bool ClientCursor::prepareToYield( YieldData &data ) { if ( ! _c->supportYields() ) return false; // need to store in case 'this' gets deleted data._id = _cursorid; data._doingDeletes = _doingDeletes; _doingDeletes = false; updateLocation(); { /* a quick test that our temprelease is safe. todo: make a YieldingCursor class and then make the following code part of a unit test. */ const int test = 0; static bool inEmpty = false; if( test && !inEmpty ) { inEmpty = true; log() << "TEST: manipulate collection during cc:yield" << endl; if( test == 1 ) Helpers::emptyCollection(_ns.c_str()); else if( test == 2 ) { BSONObjBuilder b; string m; dropCollection(_ns.c_str(), m, b); } else { dropDatabase(_ns.c_str()); } } } return true; }
bool Client::shutdown(){ _shutdown = true; if ( inShutdown() ) return false; { scoped_lock bl(clientsMutex); clients.erase(this); } bool didAnything = false; if ( _tempCollections.size() ){ didAnything = true; for ( list<string>::iterator i = _tempCollections.begin(); i!=_tempCollections.end(); i++ ){ string ns = *i; Top::global.collectionDropped( ns ); dblock l; Client::Context ctx( ns ); if ( ! nsdetails( ns.c_str() ) ) continue; try { string err; BSONObjBuilder b; dropCollection( ns , err , b ); } catch ( ... ){ log() << "error dropping temp collection: " << ns << endl; } } _tempCollections.clear(); } return didAnything; }
virtual ~Base() { if ( !nsd() ) return; string s( ns() ); string errmsg; BSONObjBuilder result; dropCollection( s, errmsg, result ); }
void drop() { Client::Context c(_ns); if (nsdetails(_ns.c_str()) != NULL) { string errmsg; BSONObjBuilder result; dropCollection( string(_ns), errmsg, result ); } }
Status AuthzManagerExternalStateMock::renameCollection(const NamespaceString& oldName, const NamespaceString& newName, const BSONObj& writeConcern) { if (_documents.count(oldName) == 0) { return Status(ErrorCodes::NamespaceNotFound, "No collection to rename named " + oldName.ns()); } std::swap(_documents[newName], _documents[oldName]); return dropCollection(oldName, writeConcern); }
void drop() { Client::WriteContext c(ns()); string errmsg; BSONObjBuilder result; if (nsdetails(ns()) == NULL) { return; } dropCollection( string(ns()), errmsg, result ); }
bool ClientCursor::yield( int micros ) { // need to store on the stack in case this gets deleted CursorId id = cursorid; bool doingDeletes = _doingDeletes; _doingDeletes = false; updateLocation(); { /* a quick test that our temprelease is safe. todo: make a YieldingCursor class and then make the following code part of a unit test. */ const int test = 0; static bool inEmpty = false; if( test && !inEmpty ) { inEmpty = true; log() << "TEST: manipulate collection during cc:yield" << endl; if( test == 1 ) Helpers::emptyCollection(ns.c_str()); else if( test == 2 ) { BSONObjBuilder b; string m; dropCollection(ns.c_str(), m, b); } else { dropDatabase(ns.c_str()); } } } { dbtempreleasecond unlock; if ( unlock.unlocked() ){ if ( micros == -1 ) micros = Client::recommendedYieldMicros(); if ( micros > 0 ) sleepmicros( micros ); } else { log( LL_WARNING ) << "ClientCursor::yield can't unlock b/c of recursive lock" << endl; } } if ( ClientCursor::find( id , false ) == 0 ){ // i was deleted return false; } _doingDeletes = doingDeletes; return true; }
TEST_F(KVCatalogTest, Coll1) { unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); KVEngine* engine = helper->getEngine(); unique_ptr<RecordStore> rs; unique_ptr<KVCatalog> catalog; { MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); ASSERT_OK(engine->createRecordStore(&opCtx, "catalog", "catalog", CollectionOptions())); rs = engine->getRecordStore(&opCtx, "catalog", "catalog", CollectionOptions()); catalog.reset(new KVCatalog(rs.get(), false, false, nullptr)); uow.commit(); } { MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); ASSERT_OK(newCollection(&opCtx, NamespaceString("a.b"), CollectionOptions(), KVPrefix::kNotPrefixed, catalog.get())); ASSERT_NOT_EQUALS("a.b", catalog->getCollectionIdent("a.b")); uow.commit(); } string ident = catalog->getCollectionIdent("a.b"); { MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); catalog.reset(new KVCatalog(rs.get(), false, false, nullptr)); catalog->init(&opCtx); uow.commit(); } ASSERT_EQUALS(ident, catalog->getCollectionIdent("a.b")); { MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); dropCollection(&opCtx, "a.b", catalog.get()).transitional_ignore(); newCollection(&opCtx, NamespaceString("a.b"), CollectionOptions(), KVPrefix::kNotPrefixed, catalog.get()) .transitional_ignore(); uow.commit(); } ASSERT_NOT_EQUALS(ident, catalog->getCollectionIdent("a.b")); }
DbSet::~DbSet() { if ( name_.empty() ) return; try { Client::Context c( name_.c_str() ); if ( nsdetails( name_.c_str() ) ) { string errmsg; BSONObjBuilder result; dropCollection( name_, errmsg, result ); } } catch ( ... ) { problem() << "exception cleaning up DbSet" << endl; } }
Collection* RollbackTest::_createCollection(OperationContext* opCtx, const NamespaceString& nss, const CollectionOptions& options) { Lock::DBLock dbLock(opCtx, nss.db(), MODE_X); mongo::WriteUnitOfWork wuow(opCtx); auto databaseHolder = DatabaseHolder::get(opCtx); auto db = databaseHolder->openDb(opCtx, nss.db()); ASSERT_TRUE(db); db->dropCollection(opCtx, nss.ns()).transitional_ignore(); auto coll = db->createCollection(opCtx, nss.ns(), options); ASSERT_TRUE(coll); wuow.commit(); return coll; }
QueryStageCachedPlanBase() { // If collection exists already, we need to drop it. dropCollection(); // Add indices. addIndex(BSON("a" << 1)); addIndex(BSON("b" << 1)); OldClientWriteContext ctx(&_txn, nss.ns()); Collection* collection = ctx.getCollection(); ASSERT(collection); // Add data. for (int i = 0; i < 10; i++) { insertDocument(collection, BSON("_id" << i << "a" << i << "b" << 1)); } }
void setUp() { // If collection exists already, we need to drop it. dropCollection(); // Add indices. addIndex(BSON("a" << 1)); addIndex(BSON("b" << 1)); dbtests::WriteContextForTests ctx(&_opCtx, nss.ns()); Collection* collection = ctx.getCollection(); ASSERT(collection); // Add data. for (int i = 0; i < 10; i++) { insertDocument(collection, BSON("_id" << i << "a" << i << "b" << 1)); } }
void run() { Client::WriteContext ctx(&_txn, ns()); insert(BSON("_id" << 1)); insert(BSON("_id" << 2)); BSONObj filterObj = fromjson("{_id: {$gt: 0}}"); scoped_ptr<SingleSolutionRunner> ssr(makeCollScanRunner(ctx.ctx(),filterObj)); registerRunner(ssr.get()); BSONObj objOut; ASSERT_EQUALS(Runner::RUNNER_ADVANCED, ssr->getNext(&objOut, NULL)); ASSERT_EQUALS(1, objOut["_id"].numberInt()); // After dropping the collection, the runner // should be dead. dropCollection(); ASSERT_EQUALS(Runner::RUNNER_DEAD, ssr->getNext(&objOut, NULL)); deregisterRunner(ssr.get()); }
void run() { NamespaceString nss("unittests.rollback_create_drop_collection"); const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; dropDatabase(&opCtx, nss); Lock::DBLock dbXLock(&opCtx, nss.db(), MODE_X); OldClientContext ctx(&opCtx, nss.ns()); BSONObj doc = BSON("_id" << "example string"); ASSERT(!collectionExists(&ctx, nss.ns())); { WriteUnitOfWork uow(&opCtx); ASSERT_OK(userCreateNS(&opCtx, ctx.db(), nss.ns(), BSONObj(), CollectionOptions::parseForCommand, defaultIndexes)); ASSERT(collectionExists(&ctx, nss.ns())); insertRecord(&opCtx, nss, doc); assertOnlyRecord(&opCtx, nss, doc); BSONObjBuilder result; ASSERT_OK( dropCollection(&opCtx, nss, result, {}, DropCollectionSystemCollectionMode::kDisallowSystemCollectionDrops)); ASSERT(!collectionExists(&ctx, nss.ns())); if (!rollback) { uow.commit(); } } ASSERT(!collectionExists(&ctx, nss.ns())); }
void Database::clearTmpCollections() { Lock::assertWriteLocked( _name ); Client::Context ctx( _name ); string systemNamespaces = _name + ".system.namespaces"; // Note: we build up a toDelete vector rather than dropping the collection inside the loop // to avoid modifying the system.namespaces collection while iterating over it since that // would corrupt the cursor. vector<string> toDelete; auto_ptr<Runner> runner(InternalPlanner::collectionScan(systemNamespaces)); BSONObj nsObj; Runner::RunnerState state; while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&nsObj, NULL))) { BSONElement e = nsObj.getFieldDotted( "options.temp" ); if ( !e.trueValue() ) continue; string ns = nsObj["name"].String(); // Do not attempt to drop indexes if ( !NamespaceString::normal(ns.c_str()) ) continue; toDelete.push_back(ns); } if (Runner::RUNNER_EOF != state) { warning() << "Internal error while reading collection " << systemNamespaces << endl; } for (size_t i=0; i < toDelete.size(); i++) { Status s = dropCollection( toDelete[i] ); if ( !s.isOK() ) warning() << "could not drop temp collection: " << toDelete[i] << " because of " << s << endl; } }
void run() { Client::WriteContext ctx(&_txn, ns()); insert(BSON("_id" << 1 << "a" << 6)); insert(BSON("_id" << 2 << "a" << 7)); insert(BSON("_id" << 3 << "a" << 8)); BSONObj indexSpec = BSON("a" << 1); addIndex(indexSpec); scoped_ptr<SingleSolutionRunner> ssr(makeIndexScanRunner(ctx.ctx(), indexSpec, 7, 10)); registerRunner(ssr.get()); BSONObj objOut; ASSERT_EQUALS(Runner::RUNNER_ADVANCED, ssr->getNext(&objOut, NULL)); ASSERT_EQUALS(7, objOut["a"].numberInt()); // After dropping the collection, the runner // should be dead. dropCollection(); ASSERT_EQUALS(Runner::RUNNER_DEAD, ssr->getNext(&objOut, NULL)); deregisterRunner(ssr.get()); }
void Client::dropTempCollectionsInDB( const string db ) { list<string>::iterator i = _tempCollections.begin(); while ( i!=_tempCollections.end() ) { string ns = *i; dblock l; Client::Context ctx( ns ); if ( nsdetails( ns.c_str() ) && ns.compare( 0, db.length(), db ) == 0 ) { try { string err; BSONObjBuilder b; dropCollection( ns, err, b ); i = _tempCollections.erase(i); ++i; } catch ( ... ){ log() << "error dropping temp collection: " << ns << endl; } } else { ++i; } } }
void Database::clearTmpCollections(OperationContext* txn) { invariant(txn->lockState()->isDbLockedForMode(name(), MODE_X)); list<string> collections; _dbEntry->getCollectionNamespaces( &collections ); for ( list<string>::iterator i = collections.begin(); i != collections.end(); ++i ) { string ns = *i; invariant( NamespaceString::normal( ns ) ); CollectionCatalogEntry* coll = _dbEntry->getCollectionCatalogEntry( ns ); CollectionOptions options = coll->getCollectionOptions( txn ); if ( !options.temp ) continue; try { WriteUnitOfWork wunit(txn); Status status = dropCollection( txn, ns ); if ( !status.isOK() ) { warning() << "could not drop temp collection '" << ns << "': " << status; continue; } string cmdNs = _name + ".$cmd"; repl::logOp( txn, "c", cmdNs.c_str(), BSON( "drop" << nsToCollectionSubstring( ns ) ) ); wunit.commit(); } catch (const WriteConflictException& exp) { warning() << "could not drop temp collection '" << ns << "' due to " "WriteConflictException"; txn->recoveryUnit()->commitAndRestart(); } } }
virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) { string source = cmdObj.getStringField( name.c_str() ); string target = cmdObj.getStringField( "to" ); if ( source.empty() || target.empty() ) { errmsg = "invalid command syntax"; return false; } setClient( source.c_str() ); NamespaceDetails *nsd = nsdetails( source.c_str() ); uassert( "source namespace does not exist", nsd ); bool capped = nsd->capped; long long size = 0; if ( capped ) for( DiskLoc i = nsd->firstExtent; !i.isNull(); i = i.ext()->xnext ) size += i.ext()->length; setClient( target.c_str() ); uassert( "target namespace exists", !nsdetails( target.c_str() ) ); { char from[256]; nsToClient( source.c_str(), from ); char to[256]; nsToClient( target.c_str(), to ); if ( strcmp( from, to ) == 0 ) { renameNamespace( source.c_str(), target.c_str() ); return true; } } BSONObjBuilder spec; if ( capped ) { spec.appendBool( "capped", true ); spec.append( "size", double( size ) ); } if ( !userCreateNS( target.c_str(), spec.done(), errmsg, false ) ) return false; auto_ptr< DBClientCursor > c; DBDirectClient bridge; { c = bridge.query( source, BSONObj() ); } while( 1 ) { { if ( !c->more() ) break; } BSONObj o = c->next(); theDataFileMgr.insert( target.c_str(), o ); } char cl[256]; nsToClient( source.c_str(), cl ); string sourceIndexes = string( cl ) + ".system.indexes"; nsToClient( target.c_str(), cl ); string targetIndexes = string( cl ) + ".system.indexes"; { c = bridge.query( sourceIndexes, QUERY( "ns" << source ) ); } while( 1 ) { { if ( !c->more() ) break; } BSONObj o = c->next(); BSONObjBuilder b; BSONObjIterator i( o ); while( i.moreWithEOO() ) { BSONElement e = i.next(); if ( e.eoo() ) break; if ( strcmp( e.fieldName(), "ns" ) == 0 ) { b.append( "ns", target ); } else { b.append( e ); } } BSONObj n = b.done(); theDataFileMgr.insert( targetIndexes.c_str(), n ); } setClient( source.c_str() ); dropCollection( source, errmsg, result ); return true; }
Status renameCollectionForApplyOps(OperationContext* opCtx, const std::string& dbName, const BSONElement& ui, const BSONObj& cmd) { const auto sourceNsElt = cmd.firstElement(); const auto targetNsElt = cmd["to"]; const auto dropSourceElt = cmd["dropSource"]; uassert(ErrorCodes::TypeMismatch, "'renameCollection' must be of type String", sourceNsElt.type() == BSONType::String); uassert(ErrorCodes::TypeMismatch, "'to' must be of type String", targetNsElt.type() == BSONType::String); NamespaceString sourceNss(sourceNsElt.valueStringData()); NamespaceString targetNss(targetNsElt.valueStringData()); NamespaceString uiNss(getNamespaceFromUUID(opCtx, ui)); NamespaceString dropSourceNss(getNamespaceFromUUID(opCtx, dropSourceElt)); // If the UUID we're targeting already exists, rename from there no matter what. // When dropSource is specified, the rename is accross databases. In that case, ui indicates // the UUID of the new target collection and the dropSourceNss specifies the sourceNss. if (!uiNss.isEmpty()) { sourceNss = uiNss; // The cross-database rename was already done and just needs a local rename, but we may // still need to actually remove the source collection. auto dropSourceNss = getNamespaceFromUUID(opCtx, dropSourceElt); if (!dropSourceNss.isEmpty()) { BSONObjBuilder unusedBuilder; dropCollection(opCtx, dropSourceNss, unusedBuilder, repl::OpTime(), DropCollectionSystemCollectionMode::kAllowSystemCollectionDrops) .ignore(); } } else if (!dropSourceNss.isEmpty()) { sourceNss = dropSourceNss; } else { // When replaying cross-database renames, both source and target collections may no longer // exist. Attempting a rename anyway could result in removing a newer collection of the // same name. uassert(ErrorCodes::NamespaceNotFound, str::stream() << "source collection (UUID " << uassertStatusOK(UUID::parse(dropSourceElt)) << ") for rename to " << targetNss.ns() << " no longer exists", !dropSourceElt); } OptionalCollectionUUID targetUUID; if (!ui.eoo()) targetUUID = uassertStatusOK(UUID::parse(ui)); return renameCollectionCommon(opCtx, sourceNss, targetNss, targetUUID, cmd["dropTarget"].trueValue(), cmd["stayTemp"].trueValue()); }
void run() { NamespaceString source("unittests.rollback_rename_droptarget_collection_src"); NamespaceString target("unittests.rollback_rename_droptarget_collection_dest"); const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; dropDatabase(&opCtx, source); dropDatabase(&opCtx, target); Lock::GlobalWrite globalWriteLock(&opCtx); OldClientContext ctx(&opCtx, source.ns()); BSONObj sourceDoc = BSON("_id" << "source"); BSONObj targetDoc = BSON("_id" << "target"); { WriteUnitOfWork uow(&opCtx); ASSERT(!collectionExists(&ctx, source.ns())); ASSERT(!collectionExists(&ctx, target.ns())); auto options = capped ? BSON("capped" << true << "size" << 1000) : BSONObj(); ASSERT_OK(userCreateNS(&opCtx, ctx.db(), source.ns(), options, CollectionOptions::parseForCommand, defaultIndexes)); ASSERT_OK(userCreateNS(&opCtx, ctx.db(), target.ns(), options, CollectionOptions::parseForCommand, defaultIndexes)); insertRecord(&opCtx, source, sourceDoc); insertRecord(&opCtx, target, targetDoc); uow.commit(); } ASSERT(collectionExists(&ctx, source.ns())); ASSERT(collectionExists(&ctx, target.ns())); assertOnlyRecord(&opCtx, source, sourceDoc); assertOnlyRecord(&opCtx, target, targetDoc); // END OF SETUP / START OF TEST { WriteUnitOfWork uow(&opCtx); BSONObjBuilder result; ASSERT_OK( dropCollection(&opCtx, target, result, {}, DropCollectionSystemCollectionMode::kDisallowSystemCollectionDrops)); ASSERT_OK(renameCollection(&opCtx, source, target)); ASSERT(!collectionExists(&ctx, source.ns())); ASSERT(collectionExists(&ctx, target.ns())); assertOnlyRecord(&opCtx, target, sourceDoc); if (!rollback) { uow.commit(); } } if (rollback) { ASSERT(collectionExists(&ctx, source.ns())); ASSERT(collectionExists(&ctx, target.ns())); assertOnlyRecord(&opCtx, source, sourceDoc); assertOnlyRecord(&opCtx, target, targetDoc); } else { ASSERT(!collectionExists(&ctx, source.ns())); ASSERT(collectionExists(&ctx, target.ns())); assertOnlyRecord(&opCtx, target, sourceDoc); } }
void drop() { string s( _ns ); string errmsg; BSONObjBuilder result; dropCollection( s, errmsg, result ); }