diff options
Diffstat (limited to 'db/pdfile.cpp')
-rw-r--r-- | db/pdfile.cpp | 265 |
1 files changed, 169 insertions, 96 deletions
diff --git a/db/pdfile.cpp b/db/pdfile.cpp index 95bdb17..787e070 100644 --- a/db/pdfile.cpp +++ b/db/pdfile.cpp @@ -24,7 +24,7 @@ _ coalesce deleted _ disallow system* manipulations from the database. */ -#include "stdafx.h" +#include "pch.h" #include "pdfile.h" #include "db.h" #include "../util/mmap.h" @@ -45,6 +45,17 @@ _ disallow system* manipulations from the database. namespace mongo { + bool inDBRepair = false; + struct doingRepair { + doingRepair(){ + assert( ! inDBRepair ); + inDBRepair = true; + } + ~doingRepair(){ + inDBRepair = false; + } + }; + const int MaxExtentSize = 0x7ff00000; map<string, unsigned> BackgroundOperation::dbsInProg; @@ -100,6 +111,7 @@ namespace mongo { string dbpath = "/data/db/"; bool directoryperdb = false; string repairpath; + string pidfilepath; DataFileMgr theDataFileMgr; DatabaseHolder dbHolder; @@ -111,7 +123,7 @@ namespace mongo { void ensureIdIndexForNewNs(const char *ns) { if ( ( strstr( ns, ".system." ) == 0 || legalClientSystemNS( ns , false ) ) && strstr( ns, ".$freelist" ) == 0 ){ - log( 1 ) << "adding _id index for new collection" << endl; + log( 1 ) << "adding _id index for collection " << ns << endl; ensureHaveIdIndex( ns ); } } @@ -145,29 +157,29 @@ namespace mongo { sz = 1000000000; int z = ((int)sz) & 0xffffff00; assert( z > len ); - DEV log() << "initialExtentSize(" << len << ") returns " << z << endl; + DEV tlog() << "initialExtentSize(" << len << ") returns " << z << endl; return z; } - bool _userCreateNS(const char *ns, const BSONObj& j, string& err) { + bool _userCreateNS(const char *ns, const BSONObj& options, string& err, bool *deferIdIndex) { if ( nsdetails(ns) ) { err = "collection already exists"; return false; } - log(1) << "create collection " << ns << ' ' << j << '\n'; + log(1) << "create collection " << ns << ' ' << options << '\n'; /* todo: do this only when we have allocated space successfully? or we could insert with a { ok: 0 } field and then go back and set to ok : 1 after we are done. */ bool isFreeList = strstr(ns, ".$freelist") != 0; if( !isFreeList ) - addNewNamespaceToCatalog(ns, j.isEmpty() ? 0 : &j); + addNewNamespaceToCatalog(ns, options.isEmpty() ? 0 : &options); long long size = initialExtentSize(128); - BSONElement e = j.getField("size"); + BSONElement e = options.getField("size"); if ( e.isNumber() ) { - size = (long long) e.number(); + size = e.numberLong(); size += 256; size &= 0xffffffffffffff00LL; } @@ -176,18 +188,18 @@ namespace mongo { bool newCapped = false; int mx = 0; - e = j.getField("capped"); + e = options.getField("capped"); if ( e.type() == Bool && e.boolean() ) { newCapped = true; - e = j.getField("max"); + e = options.getField("max"); if ( e.isNumber() ) { - mx = (int) e.number(); + mx = e.numberInt(); } } // $nExtents just for debug/testing. We create '$nExtents' extents, // each of size 'size'. - e = j.getField( "$nExtents" ); + e = options.getField( "$nExtents" ); int nExtents = int( e.number() ); Database *database = cc().database(); if ( nExtents > 0 ) { @@ -201,7 +213,7 @@ namespace mongo { } } else { while ( size > 0 ) { - int max = MongoDataFile::maxSize() - MDFHeader::headerSize(); + int max = MongoDataFile::maxSize() - DataFileHeader::HeaderSize; int desiredExtentSize = (int) (size > max ? max : size); Extent *e = database->allocExtent( ns, desiredExtentSize, newCapped ); size -= e->length; @@ -211,15 +223,22 @@ namespace mongo { NamespaceDetails *d = nsdetails(ns); assert(d); - if ( j.getField( "autoIndexId" ).type() ) { - if ( j["autoIndexId"].trueValue() ){ - ensureIdIndexForNewNs( ns ); + bool ensure = false; + if ( options.getField( "autoIndexId" ).type() ) { + if ( options["autoIndexId"].trueValue() ){ + ensure = true; } } else { if ( !newCapped ) { - ensureIdIndexForNewNs( ns ); + ensure=true; } } + if( ensure ) { + if( deferIdIndex ) + *deferIdIndex = true; + else + ensureIdIndexForNewNs( ns ); + } if ( mx > 0 ) d->max = mx; @@ -227,23 +246,25 @@ namespace mongo { return true; } - // { ..., capped: true, size: ..., max: ... } - // returns true if successful - bool userCreateNS(const char *ns, BSONObj j, string& err, bool logForReplication) { + /** { ..., capped: true, size: ..., max: ... } + @param deferIdIndex - if not not, defers id index creation. sets the bool value to true if we wanted to create the id index. + @return true if successful + */ + bool userCreateNS(const char *ns, BSONObj options, string& err, bool logForReplication, bool *deferIdIndex) { const char *coll = strchr( ns, '.' ) + 1; massert( 10356 , "invalid ns", coll && *coll ); char cl[ 256 ]; nsToDatabase( ns, cl ); - bool ok = _userCreateNS(ns, j, err); + bool ok = _userCreateNS(ns, options, err, deferIdIndex); if ( logForReplication && ok ) { - if ( j.getField( "create" ).eoo() ) { + if ( options.getField( "create" ).eoo() ) { BSONObjBuilder b; b << "create" << coll; - b.appendElements( j ); - j = b.obj(); + b.appendElements( options ); + options = b.obj(); } string logNs = string( cl ) + ".$cmd"; - logOp("c", logNs.c_str(), j); + logOp("c", logNs.c_str(), options); } return ok; } @@ -286,7 +307,7 @@ namespace mongo { very simple temporary implementation - we will in future look up the quota from the grid database */ - if ( cmdLine.quota && fileNo > cmdLine.quotaFiles && !boost::filesystem::exists(filename) ) { + if ( cmdLine.quota && fileNo > cmdLine.quotaFiles && !MMF::exists(filename) ) { /* todo: if we were adding / changing keys in an index did we do some work previously that needs cleaning up? Possible. We should check code like that and have it catch the exception and do @@ -322,7 +343,8 @@ namespace mongo { return; } - header = (MDFHeader *) mmf.map(filename, size); + _p = mmf.map(filename, size); + header = (DataFileHeader *) _p.at(0, DataFileHeader::HeaderSize); if( sizeof(char *) == 4 ) uassert( 10084 , "can't map file memory - mongo requires 64 bit build for larger datasets", header); else @@ -330,6 +352,10 @@ namespace mongo { header->init(fileNo, size); } + void MongoDataFile::flush( bool sync ){ + mmf.flush( sync ); + } + void addNewExtentToNamespace(const char *ns, Extent *e, DiskLoc eloc, DiskLoc emptyLoc, bool capped) { DiskLoc oldExtentLoc; NamespaceIndex *ni = nsindex(ns); @@ -377,8 +403,8 @@ namespace mongo { addNewExtentToNamespace(ns, e, loc, emptyLoc, newCapped); - DEV log() << "new extent " << ns << " size: 0x" << hex << ExtentSize << " loc: 0x" << hex << offset - << " emptyLoc:" << hex << emptyLoc.getOfs() << dec << endl; + DEV tlog() << "new extent " << ns << " size: 0x" << hex << ExtentSize << " loc: 0x" << hex << offset + << " emptyLoc:" << hex << emptyLoc.getOfs() << dec << endl; return e; } @@ -447,6 +473,7 @@ namespace mongo { /*---------------------------------------------------------------------*/ DiskLoc Extent::reuse(const char *nsname) { + /*TODOMMF - work to do when extent is freed. */ log(3) << "reset extent was:" << nsDiagnostic.buf << " now:" << nsname << '\n'; massert( 10360 , "Extent::reset bad magic value", magic == 0x41424344 ); xnext.Null(); @@ -456,13 +483,14 @@ namespace mongo { lastRecord.Null(); DiskLoc emptyLoc = myLoc; - emptyLoc.inc( (extentData-(char*)this) ); + emptyLoc.inc( (int) (_extentData-(char*)this) ); - int delRecLength = length - (extentData - (char *) this); - DeletedRecord *empty1 = (DeletedRecord *) extentData; - DeletedRecord *empty = (DeletedRecord *) getRecord(emptyLoc); - assert( empty == empty1 ); - memset(empty, delRecLength, 1); + int delRecLength = length - (_extentData - (char *) this); + //DeletedRecord *empty1 = (DeletedRecord *) extentData; + DeletedRecord *empty = DataFileMgr::makeDeletedRecord(emptyLoc, delRecLength);//(DeletedRecord *) getRecord(emptyLoc); + //assert( empty == empty1 ); + + // do we want to zero the record? memset(empty, ...) empty->lengthWithHeaders = delRecLength; empty->extentOfs = myLoc.getOfs(); @@ -483,19 +511,20 @@ namespace mongo { lastRecord.Null(); DiskLoc emptyLoc = myLoc; - emptyLoc.inc( (extentData-(char*)this) ); + emptyLoc.inc( (int) (_extentData-(char*)this) ); - DeletedRecord *empty1 = (DeletedRecord *) extentData; - DeletedRecord *empty = (DeletedRecord *) getRecord(emptyLoc); - assert( empty == empty1 ); - empty->lengthWithHeaders = _length - (extentData - (char *) this); + int l = _length - (_extentData - (char *) this); + //DeletedRecord *empty1 = (DeletedRecord *) extentData; + DeletedRecord *empty = DataFileMgr::makeDeletedRecord(emptyLoc, l); + //assert( empty == empty1 ); + empty->lengthWithHeaders = l; empty->extentOfs = myLoc.getOfs(); return emptyLoc; } /* Record* Extent::newRecord(int len) { - if( firstEmptyRegion.isNull() ) + if( firstEmptyRegion.isNull() )8 return 0; assert(len > 0); @@ -541,10 +570,10 @@ namespace mongo { /*---------------------------------------------------------------------*/ - auto_ptr<Cursor> DataFileMgr::findAll(const char *ns, const DiskLoc &startLoc) { + shared_ptr<Cursor> DataFileMgr::findAll(const char *ns, const DiskLoc &startLoc) { NamespaceDetails * d = nsdetails( ns ); if ( ! d ) - return auto_ptr<Cursor>(new BasicCursor(DiskLoc())); + return shared_ptr<Cursor>(new BasicCursor(DiskLoc())); DiskLoc loc = d->firstExtent; Extent *e = getExtent(loc); @@ -569,10 +598,10 @@ namespace mongo { } if ( d->capped ) - return auto_ptr< Cursor >( new ForwardCappedCursor( d , startLoc ) ); + return shared_ptr<Cursor>( new ForwardCappedCursor( d , startLoc ) ); if ( !startLoc.isNull() ) - return auto_ptr<Cursor>(new BasicCursor( startLoc )); + return shared_ptr<Cursor>(new BasicCursor( startLoc )); while ( e->firstRecord.isNull() && !e->xnext.isNull() ) { /* todo: if extent is empty, free it for reuse elsewhere. @@ -583,13 +612,13 @@ namespace mongo { // it might be nice to free the whole extent here! but have to clean up free recs then. e = e->getNextExtent(); } - return auto_ptr<Cursor>(new BasicCursor( e->firstRecord )); + return shared_ptr<Cursor>(new BasicCursor( e->firstRecord )); } /* get a table scan cursor, but can be forward or reverse direction. order.$natural - if set, > 0 means forward (asc), < 0 backward (desc). */ - auto_ptr<Cursor> findTableScan(const char *ns, const BSONObj& order, const DiskLoc &startLoc) { + shared_ptr<Cursor> findTableScan(const char *ns, const BSONObj& order, const DiskLoc &startLoc) { BSONElement el = order.getField("$natural"); // e.g., { $natural : -1 } if ( el.number() >= 0 ) @@ -599,19 +628,19 @@ namespace mongo { NamespaceDetails *d = nsdetails(ns); if ( !d ) - return auto_ptr<Cursor>(new BasicCursor(DiskLoc())); + return shared_ptr<Cursor>(new BasicCursor(DiskLoc())); if ( !d->capped ) { if ( !startLoc.isNull() ) - return auto_ptr<Cursor>(new ReverseCursor( startLoc )); + return shared_ptr<Cursor>(new ReverseCursor( startLoc )); Extent *e = d->lastExtent.ext(); while ( e->lastRecord.isNull() && !e->xprev.isNull() ) { OCCASIONALLY out() << " findTableScan: extent empty, skipping ahead" << endl; e = e->getPrevExtent(); } - return auto_ptr<Cursor>(new ReverseCursor( e->lastRecord )); + return shared_ptr<Cursor>(new ReverseCursor( e->lastRecord )); } else { - return auto_ptr< Cursor >( new ReverseCappedCursor( d, startLoc ) ); + return shared_ptr<Cursor>( new ReverseCappedCursor( d, startLoc ) ); } } @@ -663,7 +692,7 @@ namespace mongo { NamespaceDetails *freeExtents = nsdetails(s.c_str()); if( freeExtents == 0 ) { string err; - _userCreateNS(s.c_str(), BSONObj(), err); + _userCreateNS(s.c_str(), BSONObj(), err, 0); freeExtents = nsdetails(s.c_str()); massert( 10361 , "can't create .$freelist", freeExtents); } @@ -690,7 +719,8 @@ namespace mongo { void dropCollection( const string &name, string &errmsg, BSONObjBuilder &result ) { log(1) << "dropCollection: " << name << endl; NamespaceDetails *d = nsdetails(name.c_str()); - assert( d ); + if( d == 0 ) + return; BackgroundOperation::assertNoBgOpInProgForNs(name.c_str()); @@ -706,6 +736,7 @@ namespace mongo { log(1) << "\t dropIndexes done" << endl; result.append("ns", name.c_str()); ClientCursor::invalidate(name.c_str()); + Client::invalidateNS( name ); Top::global.collectionDropped( name ); dropNS(name); } @@ -831,7 +862,7 @@ namespace mongo { NamespaceDetails *d, NamespaceDetailsTransient *nsdt, Record *toupdate, const DiskLoc& dl, - const char *_buf, int _len, OpDebug& debug) + const char *_buf, int _len, OpDebug& debug, bool &changedId, bool god) { StringBuilder& ss = debug.str; dassert( toupdate == dl.rec() ); @@ -858,7 +889,7 @@ namespace mongo { below. that is suboptimal, but it's pretty complicated to do it the other way without rollbacks... */ vector<IndexChanges> changes; - getIndexChanges(changes, *d, objNew, objOld); + getIndexChanges(changes, *d, objNew, objOld, changedId); dupCheck(changes, *d, dl); if ( toupdate->netLength() < objNew.objsize() ) { @@ -868,7 +899,7 @@ namespace mongo { if ( cc().database()->profile ) ss << " moved "; deleteRecord(ns, toupdate, dl); - return insert(ns, objNew.objdata(), objNew.objsize(), false); + return insert(ns, objNew.objdata(), objNew.objsize(), god); } nsdt->notifyOfWriteOp(); @@ -891,13 +922,14 @@ namespace mongo { } assert( !dl.isNull() ); BSONObj idxKey = idx.info.obj().getObjectField("key"); + Ordering ordering = Ordering::make(idxKey); keyUpdates += changes[x].added.size(); for ( unsigned i = 0; i < changes[x].added.size(); i++ ) { try { /* we did the dupCheck() above. so we don't have to worry about it here. */ idx.head.btree()->bt_insert( idx.head, - dl, *changes[x].added[i], idxKey, /*dupsAllowed*/true, idx); + dl, *changes[x].added[i], ordering, /*dupsAllowed*/true, idx); } catch (AssertionException& e) { ss << " exception update index "; @@ -937,6 +969,7 @@ namespace mongo { BSONObjSetDefaultOrder keys; idx.getKeysFromObject(obj, keys); BSONObj order = idx.keyPattern(); + Ordering ordering = Ordering::make(order); int n = 0; for ( BSONObjSetDefaultOrder::iterator i=keys.begin(); i != keys.end(); i++ ) { if( ++n == 2 ) { @@ -945,10 +978,10 @@ namespace mongo { assert( !recordLoc.isNull() ); try { idx.head.btree()->bt_insert(idx.head, recordLoc, - *i, order, dupsAllowed, idx); + *i, ordering, dupsAllowed, idx); } catch (AssertionException& e) { - if( e.code == 10287 && idxNo == d->nIndexes ) { + if( e.getCode() == 10287 && idxNo == d->nIndexes ) { DEV log() << "info: caught key already in index on bg indexing (ok)" << endl; continue; } @@ -980,9 +1013,9 @@ namespace mongo { auto_ptr<BSONObjExternalSorter::Iterator> i = sorter.iterator(); while( i->more() ) { BSONObjExternalSorter::Data d = i->next(); - cout << d.second.toString() << endl; + /*cout << d.second.toString() << endl; cout << d.first.objsize() << endl; - cout<<"SORTER next:" << d.first.toString() << endl; + cout<<"SORTER next:" << d.first.toString() << endl;*/ } } @@ -993,10 +1026,10 @@ namespace mongo { Timer t; - log() << "Buildindex " << ns << " idxNo:" << idxNo << ' ' << idx.info.obj().toString() << endl; + tlog() << "Buildindex " << ns << " idxNo:" << idxNo << ' ' << idx.info.obj().toString() << endl; bool dupsAllowed = !idx.unique(); - bool dropDups = idx.dropDups(); + bool dropDups = idx.dropDups() || inDBRepair; BSONObj order = idx.keyPattern(); idx.head.Null(); @@ -1005,11 +1038,11 @@ namespace mongo { /* get and sort all the keys ----- */ unsigned long long n = 0; - auto_ptr<Cursor> c = theDataFileMgr.findAll(ns); + shared_ptr<Cursor> c = theDataFileMgr.findAll(ns); BSONObjExternalSorter sorter(order); sorter.hintNumObjects( d->nrecords ); unsigned long long nkeys = 0; - ProgressMeter & pm = op->setMessage( "index: (1/3) external sort" , d->nrecords , 10 ); + ProgressMeterHolder pm( op->setMessage( "index: (1/3) external sort" , d->nrecords , 10 ) ); while ( c->ok() ) { BSONObj o = c->current(); DiskLoc loc = c->currLoc(); @@ -1048,7 +1081,7 @@ namespace mongo { BtreeBuilder btBuilder(dupsAllowed, idx); BSONObj keyLast; auto_ptr<BSONObjExternalSorter::Iterator> i = sorter.iterator(); - pm = op->setMessage( "index: (2/3) btree bottom up" , nkeys , 10 ); + assert( pm == op->setMessage( "index: (2/3) btree bottom up" , nkeys , 10 ) ); while( i->more() ) { RARELY killCurrentOp.checkForInterrupt(); BSONObjExternalSorter::Data d = i->next(); @@ -1102,8 +1135,8 @@ namespace mongo { unsigned long long n = 0; auto_ptr<ClientCursor> cc; { - auto_ptr<Cursor> c = theDataFileMgr.findAll(ns); - cc.reset( new ClientCursor(c, ns, false) ); + shared_ptr<Cursor> c = theDataFileMgr.findAll(ns); + cc.reset( new ClientCursor(QueryOption_NoCursorTimeout, c, ns) ); } CursorId id = cc->cursorid; @@ -1155,6 +1188,7 @@ namespace mongo { void prep(const char *ns, NamespaceDetails *d) { assertInWriteLock(); + uassert( 13130 , "can't start bg index b/c in recursive lock (db.eval?)" , dbMutex.getState() == 1 ); bgJobsInProgress.insert(d); d->backgroundIndexBuildInProgress = 1; d->nIndexes--; @@ -1196,7 +1230,7 @@ namespace mongo { // throws DBException static void buildAnIndex(string ns, NamespaceDetails *d, IndexDetails& idx, int idxNo, bool background) { - log() << "building new index on " << idx.keyPattern() << " for " << ns << ( background ? " background" : "" ) << endl; + tlog() << "building new index on " << idx.keyPattern() << " for " << ns << ( background ? " background" : "" ) << endl; Timer t; unsigned long long n; @@ -1205,7 +1239,7 @@ namespace mongo { } assert( !BackgroundOperation::inProgForNs(ns.c_str()) ); // should have been checked earlier, better not be... - if( !background ) { + if( inDBRepair || !background ) { n = fastBuildIndex(ns.c_str(), d, idx, idxNo); assert( !idx.head.isNull() ); } @@ -1213,7 +1247,7 @@ namespace mongo { BackgroundIndexBuildJob j(ns.c_str()); n = j.go(ns, d, idx, idxNo); } - log() << "done for " << n << " records " << t.millis() / 1000.0 << "secs" << endl; + tlog() << "done for " << n << " records " << t.millis() / 1000.0 << "secs" << endl; } /* add keys to indexes for a new record */ @@ -1289,17 +1323,21 @@ namespace mongo { void DataFileMgr::insertAndLog( const char *ns, const BSONObj &o, bool god ) { BSONObj tmp = o; - insert( ns, tmp, god ); + insertWithObjMod( ns, tmp, god ); logOp( "i", ns, tmp ); } - DiskLoc DataFileMgr::insert(const char *ns, BSONObj &o, bool god) { + DiskLoc DataFileMgr::insertWithObjMod(const char *ns, BSONObj &o, bool god) { DiskLoc loc = insert( ns, o.objdata(), o.objsize(), god ); if ( !loc.isNull() ) o = BSONObj( loc.rec() ); return loc; } + void DataFileMgr::insertNoReturnVal(const char *ns, BSONObj o, bool god) { + insert( ns, o.objdata(), o.objsize(), god ); + } + bool prepareToBuildIndex(const BSONObj& io, bool god, string& sourceNS, NamespaceDetails *&sourceCollection); // We are now doing two btree scans for all unique indexes (one here, and one when we've @@ -1320,13 +1358,13 @@ namespace mongo { } } } - + /* note: if god==true, you may pass in obuf of NULL and then populate the returned DiskLoc after the call -- that will prevent a double buffer copy in some cases (btree.cpp). */ DiskLoc DataFileMgr::insert(const char *ns, const void *obuf, int len, bool god, const BSONElement &writeId, bool mayAddIndex) { bool wouldAddIndex = false; - massert( 10093 , "cannot insert into reserved $ collection", god || strchr(ns, '$') == 0 ); + massert( 10093 , "cannot insert into reserved $ collection", god || nsDollarCheck( ns ) ); uassert( 10094 , "invalid ns", strchr( ns , '.' ) > 0 ); const char *sys = strstr(ns, "system."); if ( sys ) { @@ -1366,6 +1404,7 @@ namespace mongo { string tabletoidxns; if ( addIndex ) { + assert( obuf ); BSONObj io((const char *) obuf); if( !prepareToBuildIndex(io, god, tabletoidxns, tableToIndex) ) return DiskLoc(); @@ -1428,7 +1467,7 @@ namespace mongo { } } if ( loc.isNull() ) { - log() << "out of space in datafile " << ns << " capped:" << d->capped << endl; + log() << "insert: couldn't alloc space for object ns:" << ns << " capped:" << d->capped << endl; assert(d->capped); return DiskLoc(); } @@ -1468,6 +1507,8 @@ namespace mongo { NamespaceDetailsTransient::get_w( ns ).notifyOfWriteOp(); if ( tableToIndex ) { + uassert( 13143 , "can't create index on system.indexes" , tabletoidxns.find( ".system.indexes" ) == string::npos ); + BSONObj info = loc.obj(); bool background = info["background"].trueValue(); @@ -1476,7 +1517,7 @@ namespace mongo { idx.info = loc; try { buildAnIndex(tabletoidxns, tableToIndex, idx, idxNo, background); - } catch( DBException& ) { + } catch( DBException& e ) { // save our error msg string as an exception or dropIndexes will overwrite our message LastError *le = lastError.get(); int savecode = 0; @@ -1485,6 +1526,10 @@ namespace mongo { savecode = le->code; saveerrmsg = le->msg; } + else { + savecode = e.getCode(); + saveerrmsg = e.what(); + } // roll back this index string name = idx.indexName(); @@ -1494,7 +1539,7 @@ namespace mongo { if( !ok ) { log() << "failed to drop index after a unique key error building it: " << errmsg << ' ' << tabletoidxns << ' ' << name << endl; } - + assert( le && !saveerrmsg.empty() ); raiseError(savecode,saveerrmsg.c_str()); throw; @@ -1571,21 +1616,46 @@ namespace mongo { namespace mongo { - void dropDatabase(const char *ns) { - // ns is of the form "<dbname>.$cmd" - char db[256]; - nsToDatabase(ns, db); + void dropAllDatabasesExceptLocal() { + writelock lk(""); + + vector<string> n; + getDatabaseNames(n); + if( n.size() == 0 ) return; + log() << "dropAllDatabasesExceptLocal " << n.size() << endl; + for( vector<string>::iterator i = n.begin(); i != n.end(); i++ ) { + if( *i != "local" ) { + Client::Context ctx(*i); + dropDatabase(*i); + } + } + } + + void dropDatabase(string db) { log(1) << "dropDatabase " << db << endl; + assert( cc().database() ); assert( cc().database()->name == db ); - BackgroundOperation::assertNoBgOpInProgForDb(db); + BackgroundOperation::assertNoBgOpInProgForDb(db.c_str()); + + Client::invalidateDB( db ); - closeDatabase( db ); - _deleteDataFiles(db); + closeDatabase( db.c_str() ); + _deleteDataFiles( db.c_str() ); } typedef boost::filesystem::path Path; + void boostRenameWrapper( const Path &from, const Path &to ) { + try { + boost::filesystem::rename( from, to ); + } catch ( const boost::filesystem::filesystem_error & ) { + // boost rename doesn't work across partitions + boost::filesystem::copy_file( from, to); + boost::filesystem::remove( from ); + } + } + // back up original database files to 'temp' dir void _renameForBackup( const char *database, const Path &reservedPath ) { Path newPath( reservedPath ); @@ -1599,7 +1669,7 @@ namespace mongo { virtual bool apply( const Path &p ) { if ( !boost::filesystem::exists( p ) ) return false; - boost::filesystem::rename( p, newPath_ / ( p.leaf() + ".bak" ) ); + boostRenameWrapper( p, newPath_ / ( p.leaf() + ".bak" ) ); return true; } virtual const char * op() const { @@ -1622,7 +1692,7 @@ namespace mongo { virtual bool apply( const Path &p ) { if ( !boost::filesystem::exists( p ) ) return false; - boost::filesystem::rename( p, newPath_ / p.leaf() ); + boostRenameWrapper( p, newPath_ / p.leaf() ); return true; } virtual const char * op() const { @@ -1676,32 +1746,33 @@ namespace mongo { #include <sys/statvfs.h> namespace mongo { #endif - boost::intmax_t freeSpace() { + boost::intmax_t freeSpace ( const string &path ) { #if !defined(_WIN32) struct statvfs info; - assert( !statvfs( dbpath.c_str() , &info ) ); + assert( !statvfs( path.c_str() , &info ) ); return boost::intmax_t( info.f_bavail ) * info.f_frsize; #else return -1; #endif } - bool repairDatabase( const char *ns, string &errmsg, + bool repairDatabase( string dbNameS , string &errmsg, bool preserveClonedFilesOnFailure, bool backupOriginalFiles ) { + doingRepair dr; + dbNameS = nsToDatabase( dbNameS ); + const char * dbName = dbNameS.c_str(); + stringstream ss; ss << "localhost:" << cmdLine.port; string localhost = ss.str(); - - // ns is of the form "<dbname>.$cmd" - char dbName[256]; - nsToDatabase(ns, dbName); + problem() << "repairDatabase " << dbName << endl; assert( cc().database()->name == dbName ); BackgroundOperation::assertNoBgOpInProgForDb(dbName); boost::intmax_t totalSize = dbSize( dbName ); - boost::intmax_t freeSize = freeSpace(); + boost::intmax_t freeSize = freeSpace( repairpath ); if ( freeSize > -1 && freeSize < totalSize ) { stringstream ss; ss << "Cannot repair database " << dbName << " having size: " << totalSize @@ -1800,6 +1871,8 @@ namespace mongo { dbs.insert( i->first ); } + currentClient.get()->getContext()->clear(); + BSONObjBuilder bb( result.subarrayStart( "dbs" ) ); int n = 0; int nNotClosed = 0; @@ -1813,7 +1886,7 @@ namespace mongo { } else { closeDatabase( name.c_str() , path ); - bb.append( bb.numStr( n++ ).c_str() , name ); + bb.append( bb.numStr( n++ ) , name ); } } bb.done(); |