summaryrefslogtreecommitdiff
path: root/db/pdfile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'db/pdfile.cpp')
-rw-r--r--db/pdfile.cpp265
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();