00001
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #pragma once
00027
00028 #include "../pch.h"
00029 #include "../util/mmap.h"
00030 #include "diskloc.h"
00031 #include "jsobjmanipulator.h"
00032 #include "namespace-inl.h"
00033 #include "client.h"
00034 #include "mongommf.h"
00035
00036 namespace mongo {
00037
00038 class DataFileHeader;
00039 class Extent;
00040 class Record;
00041 class Cursor;
00042 class OpDebug;
00043
00044 void dropDatabase(string db);
00045 bool repairDatabase(string db, string &errmsg, bool preserveClonedFilesOnFailure = false, bool backupOriginalFiles = false);
00046
00047
00048 void dropNS(const string& dropNs);
00049
00050
00051 void dropCollection( const string &name, string &errmsg, BSONObjBuilder &result );
00052 bool userCreateNS(const char *ns, BSONObj j, string& err, bool logForReplication, bool *deferIdIndex = 0);
00053 shared_ptr<Cursor> findTableScan(const char *ns, const BSONObj& order, const DiskLoc &startLoc=DiskLoc());
00054
00055
00056 boost::intmax_t freeSpace( const string &path = dbpath );
00057
00058 bool isValidNS( const StringData& ns );
00059
00060
00061
00062 class MongoDataFile {
00063 friend class DataFileMgr;
00064 friend class BasicCursor;
00065 public:
00066 MongoDataFile(int fn) : _mb(0), fileNo(fn) { }
00067 void open(const char *filename, int requestedDataSize = 0, bool preallocateOnly = false);
00068
00069
00070
00071
00072
00073 Extent* createExtent(const char *ns, int approxSize, bool capped = false, int loops = 0);
00074
00075 DataFileHeader *getHeader() { return header(); }
00076
00077 unsigned long long length() const { return mmf.length(); }
00078
00079
00080 static int maxSize();
00081
00083 void flush( bool sync );
00084
00086 Extent* debug_getExtent(DiskLoc loc) { return _getExtent( loc ); }
00087 private:
00088 void badOfs(int) const;
00089 void badOfs2(int) const;
00090 int defaultSize( const char *filename ) const;
00091
00092 Extent* getExtent(DiskLoc loc) const;
00093 Extent* _getExtent(DiskLoc loc) const;
00094 Record* recordAt(DiskLoc dl);
00095 Record* makeRecord(DiskLoc dl, int size);
00096 void grow(DiskLoc dl, int size);
00097
00098 char* p() const { return (char *) _mb; }
00099 DataFileHeader* header() { return (DataFileHeader*) _mb; }
00100
00101 MongoMMF mmf;
00102 void *_mb;
00103 int fileNo;
00104 };
00105
00106 class DataFileMgr {
00107 friend class BasicCursor;
00108 public:
00109 void init(const string& path );
00110
00111
00112 static Extent* allocFromFreeList(const char *ns, int approxSize, bool capped = false);
00113
00115
00116 const DiskLoc updateRecord(
00117 const char *ns,
00118 NamespaceDetails *d,
00119 NamespaceDetailsTransient *nsdt,
00120 Record *toupdate, const DiskLoc& dl,
00121 const char *buf, int len, OpDebug& debug, bool god=false);
00122
00123
00124 void insertAndLog( const char *ns, const BSONObj &o, bool god = false );
00125
00127 DiskLoc insertWithObjMod(const char *ns, BSONObj &o, bool god = false);
00128
00130 void insertNoReturnVal(const char *ns, BSONObj o, bool god = false);
00131
00132 DiskLoc insert(const char *ns, const void *buf, int len, bool god = false, const BSONElement &writeId = BSONElement(), bool mayAddIndex = true);
00133 static shared_ptr<Cursor> findAll(const char *ns, const DiskLoc &startLoc = DiskLoc());
00134
00135
00136
00137
00138
00139 Record* fast_oplog_insert(NamespaceDetails *d, const char *ns, int len);
00140
00141 static Extent* getExtent(const DiskLoc& dl);
00142 static Record* getRecord(const DiskLoc& dl);
00143 static DeletedRecord* makeDeletedRecord(const DiskLoc& dl, int len);
00144
00145 void deleteRecord(const char *ns, Record *todelete, const DiskLoc& dl, bool cappedOK = false, bool noWarn = false);
00146
00147
00148 void _deleteRecord(NamespaceDetails *d, const char *ns, Record *todelete, const DiskLoc& dl);
00149
00150 private:
00151 vector<MongoDataFile *> files;
00152 };
00153
00154 extern DataFileMgr theDataFileMgr;
00155
00156 #pragma pack(1)
00157
00158 class DeletedRecord {
00159 public:
00160 int lengthWithHeaders;
00161 int extentOfs;
00162 DiskLoc nextDeleted;
00163 Extent* myExtent(const DiskLoc& myLoc) {
00164 return DataFileMgr::getExtent(DiskLoc(myLoc.a(), extentOfs));
00165 }
00166 };
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 class Record {
00180 public:
00181 enum HeaderSizeValue { HeaderSize = 16 };
00182 int lengthWithHeaders;
00183 int extentOfs;
00184 int nextOfs;
00185 int prevOfs;
00186
00188 char data[4];
00189
00190 int netLength() {
00191 return lengthWithHeaders - HeaderSize;
00192 }
00193
00194
00195
00196 DeletedRecord& asDeleted() {
00197 return *((DeletedRecord*) this);
00198 }
00199
00200 Extent* myExtent(const DiskLoc& myLoc) {
00201 return DataFileMgr::getExtent(DiskLoc(myLoc.a(), extentOfs));
00202 }
00203
00204 DiskLoc getNext(const DiskLoc& myLoc);
00205 DiskLoc getPrev(const DiskLoc& myLoc);
00206
00207 struct NP {
00208 int nextOfs;
00209 int prevOfs;
00210 };
00211 NP* np() { return (NP*) &nextOfs; }
00212 };
00213
00214
00215
00216
00217
00218
00219
00220 class Extent {
00221 public:
00222 unsigned magic;
00223 DiskLoc myLoc;
00224 DiskLoc xnext, xprev;
00225
00226
00227
00228
00229 Namespace nsDiagnostic;
00230
00231 int length;
00232 DiskLoc firstRecord;
00233 DiskLoc lastRecord;
00234 char _extentData[4];
00235
00236 static int HeaderSize() { return sizeof(Extent)-4; }
00237
00238 bool validates() {
00239 return !(firstRecord.isNull() ^ lastRecord.isNull()) &&
00240 length >= 0 && !myLoc.isNull();
00241 }
00242
00243 void dump(iostream& s) {
00244 s << " loc:" << myLoc.toString() << " xnext:" << xnext.toString() << " xprev:" << xprev.toString() << '\n';
00245 s << " nsdiag:" << nsDiagnostic.toString() << '\n';
00246 s << " size:" << length << " firstRecord:" << firstRecord.toString() << " lastRecord:" << lastRecord.toString() << '\n';
00247 }
00248
00249
00250
00251
00252
00253 DiskLoc init(const char *nsname, int _length, int _fileNo, int _offset);
00254
00255
00256 DiskLoc reuse(const char *nsname);
00257
00258 bool isOk() const { return magic == 0x41424344; }
00259 void assertOk() const { assert(isOk()); }
00260
00261 Record* newRecord(int len);
00262
00263 Record* getRecord(DiskLoc dl) {
00264 assert( !dl.isNull() );
00265 assert( dl.sameFile(myLoc) );
00266 int x = dl.getOfs() - myLoc.getOfs();
00267 assert( x > 0 );
00268 return (Record *) (((char *) this) + x);
00269 }
00270
00271 Extent* getNextExtent() { return xnext.isNull() ? 0 : DataFileMgr::getExtent(xnext); }
00272 Extent* getPrevExtent() { return xprev.isNull() ? 0 : DataFileMgr::getExtent(xprev); }
00273
00274 static int maxSize();
00275 static int minSize() { return 0x100; }
00280 static int followupSize(int len, int lastExtentLen);
00281
00285 static int initialSize(int len);
00286
00287 struct FL {
00288 DiskLoc firstRecord;
00289 DiskLoc lastRecord;
00290 };
00294 FL* fl() { return (FL*) &firstRecord; }
00295 private:
00296 DiskLoc _reuse(const char *nsname);
00297 };
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312 class DataFileHeader {
00313 public:
00314 int version;
00315 int versionMinor;
00316 int fileLength;
00317 DiskLoc unused;
00318 int unusedLength;
00319 char reserved[8192 - 4*4 - 8];
00320
00321 char data[4];
00322
00323 enum { HeaderSize = 8192 };
00324
00325 bool isCurrentVersion() const { return ( version == VERSION ) && ( versionMinor == VERSION_MINOR ); }
00326
00327 bool uninitialized() const { return version == 0; }
00328
00329 void init(int fileno, int filelength, const char* filename) {
00330 if ( uninitialized() ) {
00331 if( !(filelength > 32768 ) ) {
00332 massert(13640, str::stream() << "DataFileHeader looks corrupt at file open filelength:" << filelength << " fileno:" << fileno, false);
00333 }
00334 getDur().createdFile(filename, filelength);
00335 assert( HeaderSize == 8192 );
00336 DataFileHeader *h = getDur().writing(this);
00337 h->fileLength = filelength;
00338 h->version = VERSION;
00339 h->versionMinor = VERSION_MINOR;
00340 h->unused.set( fileno, HeaderSize );
00341 assert( (data-(char*)this) == HeaderSize );
00342 h->unusedLength = fileLength - HeaderSize - 16;
00343 }
00344 }
00345
00346 bool isEmpty() const {
00347 return uninitialized() || ( unusedLength == fileLength - HeaderSize - 16 );
00348 }
00349 };
00350
00351 #pragma pack()
00352
00353 inline Extent* MongoDataFile::_getExtent(DiskLoc loc) const {
00354 loc.assertOk();
00355 Extent *e = (Extent *) (p()+loc.getOfs());
00356 return e;
00357 }
00358
00359 inline Extent* MongoDataFile::getExtent(DiskLoc loc) const {
00360 Extent *e = _getExtent(loc);
00361 e->assertOk();
00362 return e;
00363 }
00364
00365 }
00366
00367 #include "cursor.h"
00368
00369 namespace mongo {
00370
00371 inline Record* MongoDataFile::recordAt(DiskLoc dl) {
00372 int ofs = dl.getOfs();
00373 if( ofs < DataFileHeader::HeaderSize ) badOfs(ofs);
00374 return (Record*) (p()+ofs);
00375 }
00376
00377 inline Record* MongoDataFile::makeRecord(DiskLoc dl, int size) {
00378 int ofs = dl.getOfs();
00379 if( ofs < DataFileHeader::HeaderSize ) badOfs(ofs);
00380 return (Record*) (p()+ofs);
00381 }
00382
00383 inline DiskLoc Record::getNext(const DiskLoc& myLoc) {
00384 if ( nextOfs != DiskLoc::NullOfs ) {
00385
00386 if ( nextOfs >= 0 && nextOfs < 10 ) {
00387 sayDbContext("Assertion failure - Record::getNext() referencing a deleted record?");
00388 return DiskLoc();
00389 }
00390
00391 return DiskLoc(myLoc.a(), nextOfs);
00392 }
00393 Extent *e = myExtent(myLoc);
00394 while ( 1 ) {
00395 if ( e->xnext.isNull() )
00396 return DiskLoc();
00397 e = e->xnext.ext();
00398 if ( !e->firstRecord.isNull() )
00399 break;
00400
00401 }
00402 return e->firstRecord;
00403 }
00404 inline DiskLoc Record::getPrev(const DiskLoc& myLoc) {
00405 if ( prevOfs != DiskLoc::NullOfs )
00406 return DiskLoc(myLoc.a(), prevOfs);
00407 Extent *e = myExtent(myLoc);
00408 if ( e->xprev.isNull() )
00409 return DiskLoc();
00410 return e->xprev.ext()->lastRecord;
00411 }
00412
00413 inline Record* DiskLoc::rec() const {
00414 return DataFileMgr::getRecord(*this);
00415 }
00416 inline BSONObj DiskLoc::obj() const {
00417 return BSONObj(rec());
00418 }
00419 inline DeletedRecord* DiskLoc::drec() const {
00420 assert( _a != -1 );
00421 return (DeletedRecord*) rec();
00422 }
00423 inline Extent* DiskLoc::ext() const {
00424 return DataFileMgr::getExtent(*this);
00425 }
00426 inline const BtreeBucket* DiskLoc::btree() const {
00427 assert( _a != -1 );
00428 return (const BtreeBucket *) rec()->data;
00429 }
00430
00431 }
00432
00433 #include "database.h"
00434
00435 namespace mongo {
00436
00437 boost::intmax_t dbSize( const char *database );
00438
00439 inline NamespaceIndex* nsindex(const char *ns) {
00440 Database *database = cc().database();
00441 assert( database );
00442 DEV {
00443 char buf[256];
00444 nsToDatabase(ns, buf);
00445 if ( database->name != buf ) {
00446 out() << "ERROR: attempt to write to wrong database database\n";
00447 out() << " ns:" << ns << '\n';
00448 out() << " database->name:" << database->name << endl;
00449 assert( database->name == buf );
00450 }
00451 }
00452 return &database->namespaceIndex;
00453 }
00454
00455 inline NamespaceDetails* nsdetails(const char *ns) {
00456
00457 return nsindex(ns)->details(ns);
00458 }
00459
00460 inline Extent* DataFileMgr::getExtent(const DiskLoc& dl) {
00461 assert( dl.a() != -1 );
00462 return cc().database()->getFile(dl.a())->getExtent(dl);
00463 }
00464
00465 inline Record* DataFileMgr::getRecord(const DiskLoc& dl) {
00466 assert( dl.a() != -1 );
00467 return cc().database()->getFile(dl.a())->recordAt(dl);
00468 }
00469
00470 BOOST_STATIC_ASSERT( 16 == sizeof(DeletedRecord) );
00471
00472 inline DeletedRecord* DataFileMgr::makeDeletedRecord(const DiskLoc& dl, int len) {
00473 assert( dl.a() != -1 );
00474 return (DeletedRecord*) cc().database()->getFile(dl.a())->makeRecord(dl, sizeof(DeletedRecord));
00475 }
00476
00477 void ensureHaveIdIndex(const char *ns);
00478
00479 bool dropIndexes( NamespaceDetails *d, const char *ns, const char *name, string &errmsg, BSONObjBuilder &anObjBuilder, bool maydeleteIdIndex );
00480
00481
00486 inline bool isANormalNSName( const char* ns ) {
00487 if ( strchr( ns , '$' ) == 0 )
00488 return true;
00489 return strcmp( ns, "local.oplog.$main" ) == 0;
00490 }
00491
00492 inline BSONObj::BSONObj(const Record *r) {
00493 init(r->data, false);
00494 }
00495
00496 }