00001
00002
00019 #pragma once
00020
00021 #include "../pch.h"
00022 #include "jsobj.h"
00023 #include "queryutil.h"
00024 #include "diskloc.h"
00025 #include "../util/hashtab.h"
00026 #include "mongommf.h"
00027
00028 namespace mongo {
00029
00030
00031
00032 const int MaxDatabaseNameLen = 256;
00033
00034
00035
00036
00037
00038 class NamespaceString {
00039 public:
00040 string db;
00041 string coll;
00042
00043 NamespaceString( const char * ns ) { init(ns); }
00044 NamespaceString( const string& ns ) { init(ns.c_str()); }
00045 string ns() const { return db + '.' + coll; }
00046 bool isSystem() const { return strncmp(coll.c_str(), "system.", 7) == 0; }
00047 private:
00048 void init(const char *ns) {
00049 const char *p = strchr(ns, '.');
00050 if( p == 0 ) return;
00051 db = string(ns, p - ns);
00052 coll = p + 1;
00053 }
00054 };
00055
00056 #pragma pack(1)
00057
00058
00059
00060 class Namespace {
00061 public:
00062 explicit Namespace(const char *ns) { *this = ns; }
00063 Namespace& operator=(const char *ns);
00064
00065 bool hasDollarSign() const { return strchr( buf , '$' ) > 0; }
00066 void kill() { buf[0] = 0x7f; }
00067 bool operator==(const char *r) const { return strcmp(buf, r) == 0; }
00068 bool operator==(const Namespace& r) const { return strcmp(buf, r.buf) == 0; }
00069 int hash() const;
00070 string toString() const { return (string) buf; }
00071 operator string() const { return (string) buf; }
00072
00073
00074
00075
00076 string extraName(int i) const;
00077 bool isExtra() const;
00078
00082 string getSisterNS( const char * local ) const;
00083
00084 enum MaxNsLenValue { MaxNsLen = 128 };
00085 private:
00086 char buf[MaxNsLen];
00087 };
00088 #pragma pack()
00089
00090 }
00091
00092 #include "index.h"
00093
00094 namespace mongo {
00095
00100 bool legalClientSystemNS( const string& ns , bool write );
00101
00102
00103
00104
00105 const int Buckets = 19;
00106 const int MaxBucket = 18;
00107
00108 extern int bucketSizes[];
00109
00110 #pragma pack(1)
00111
00112
00113
00114 class NamespaceDetails {
00115 public:
00116 enum { NIndexesMax = 64, NIndexesExtra = 30, NIndexesBase = 10 };
00117
00118
00119 DiskLoc firstExtent;
00120 DiskLoc lastExtent;
00121
00122
00123
00124
00125
00126
00127
00128 DiskLoc deletedList[Buckets];
00129
00130 struct Stats {
00131
00132 long long datasize;
00133 long long nrecords;
00134 } stats;
00135 int lastExtentSize;
00136 int nIndexes;
00137 private:
00138
00139 IndexDetails _indexes[NIndexesBase];
00140 public:
00141
00142 int capped;
00143 int max;
00144 double paddingFactor;
00145
00146 int flags;
00147 DiskLoc capExtent;
00148 DiskLoc capFirstNewRecord;
00149 unsigned short dataFileVersion;
00150 unsigned short indexFileVersion;
00151 unsigned long long multiKeyIndexBits;
00152 private:
00153
00154 unsigned long long reservedA;
00155 long long extraOffset;
00156 public:
00157 int indexBuildInProgress;
00158 unsigned reservedB;
00159
00160 struct Capped2 {
00161 unsigned long long cc2_ptr;
00162 unsigned fileNumber;
00163 } capped2;
00164 char reserved[60];
00165
00166
00167 explicit NamespaceDetails( const DiskLoc &loc, bool _capped );
00168
00169 class Extra {
00170 long long _next;
00171 public:
00172 IndexDetails details[NIndexesExtra];
00173 private:
00174 unsigned reserved2;
00175 unsigned reserved3;
00176 Extra(const Extra&) { assert(false); }
00177 Extra& operator=(const Extra& r) { assert(false); return *this; }
00178 public:
00179 Extra() { }
00180 long ofsFrom(NamespaceDetails *d) {
00181 return ((char *) this) - ((char *) d);
00182 }
00183 void init() { memset(this, 0, sizeof(Extra)); }
00184 Extra* next(NamespaceDetails *d) {
00185 if( _next == 0 ) return 0;
00186 return (Extra*) (((char *) d) + _next);
00187 }
00188 void setNext(long ofs) { *getDur().writing(&_next) = ofs; }
00189 void copy(NamespaceDetails *d, const Extra& e) {
00190 memcpy(this, &e, sizeof(Extra));
00191 _next = 0;
00192 }
00193 };
00194 Extra* extra() {
00195 if( extraOffset == 0 ) return 0;
00196 return (Extra *) (((char *) this) + extraOffset);
00197 }
00198
00199 Extra* allocExtra(const char *ns, int nindexessofar);
00200 void copyingFrom(const char *thisns, NamespaceDetails *src);
00201
00202
00203 void onLoad(const Namespace& k);
00204
00205
00206 void dump(const Namespace& k);
00207
00208
00209 void dumpExtents();
00210
00211 private:
00212 Extent *theCapExtent() const { return capExtent.ext(); }
00213 void advanceCapExtent( const char *ns );
00214 DiskLoc __capAlloc(int len);
00215 DiskLoc cappedAlloc(const char *ns, int len);
00216 DiskLoc &cappedFirstDeletedInCurExtent();
00217 bool nextIsInCapExtent( const DiskLoc &dl ) const;
00218
00219 public:
00220 DiskLoc& cappedListOfAllDeletedRecords() { return deletedList[0]; }
00221 DiskLoc& cappedLastDelRecLastExtent() { return deletedList[1]; }
00222 void cappedDumpDelInfo();
00223 bool capLooped() const { return capped && capFirstNewRecord.isValid(); }
00224 bool inCapExtent( const DiskLoc &dl ) const;
00225 void cappedCheckMigrate();
00232 void cappedTruncateAfter(const char *ns, DiskLoc end, bool inclusive);
00234 void emptyCappedCollection(const char *ns);
00235
00236
00237
00238
00239 int nIndexesBeingBuilt() const { return nIndexes + indexBuildInProgress; }
00240
00241
00242
00243
00244 enum NamespaceFlags {
00245 Flag_HaveIdIndex = 1 << 0
00246 };
00247
00248 IndexDetails& idx(int idxNo, bool missingExpected = false );
00249
00251 IndexDetails& inProgIdx() {
00252 DEV assert(indexBuildInProgress);
00253 return idx(nIndexes);
00254 }
00255
00256 class IndexIterator {
00257 public:
00258 int pos() { return i; }
00259 bool more() { return i < n; }
00260 IndexDetails& next() { return d->idx(i++); }
00261 private:
00262 friend class NamespaceDetails;
00263 int i, n;
00264 NamespaceDetails *d;
00265 IndexIterator(NamespaceDetails *_d);
00266 };
00267
00268 IndexIterator ii() { return IndexIterator(this); }
00269
00270
00271 int idxNo(IndexDetails& idx);
00272
00273
00274
00275
00276
00277 bool isMultikey(int i) const { return (multiKeyIndexBits & (((unsigned long long) 1) << i)) != 0; }
00278 void setIndexIsMultikey(int i) {
00279 dassert( i < NIndexesMax );
00280 unsigned long long x = ((unsigned long long) 1) << i;
00281 if( multiKeyIndexBits & x ) return;
00282 *getDur().writing(&multiKeyIndexBits) |= x;
00283 }
00284 void clearIndexIsMultikey(int i) {
00285 dassert( i < NIndexesMax );
00286 unsigned long long x = ((unsigned long long) 1) << i;
00287 if( (multiKeyIndexBits & x) == 0 ) return;
00288 *getDur().writing(&multiKeyIndexBits) &= ~x;
00289 }
00290
00291
00292
00293
00294 IndexDetails& addIndex(const char *thisns, bool resetTransient=true);
00295
00296 void aboutToDeleteAnIndex() {
00297 *getDur().writing(&flags) = flags & ~Flag_HaveIdIndex;
00298 }
00299
00300
00301 int fieldIsIndexed(const char *fieldName);
00302
00303 void paddingFits() {
00304 double x = paddingFactor - 0.01;
00305 if ( x >= 1.0 )
00306 getDur().setNoJournal(&paddingFactor, &x, sizeof(x));
00307 }
00308 void paddingTooSmall() {
00309 double x = paddingFactor + 0.6;
00310 if ( x <= 2.0 )
00311 getDur().setNoJournal(&paddingFactor, &x, sizeof(x));
00312 }
00313
00314
00315 int findIndexByName(const char *name);
00316
00317
00318 int findIndexByKeyPattern(const BSONObj& keyPattern);
00319
00320 void findIndexByType( const string& name , vector<int>& matches ) {
00321 IndexIterator i = ii();
00322 while ( i.more() ) {
00323 if ( i.next().getSpec().getTypeName() == name )
00324 matches.push_back( i.pos() - 1 );
00325 }
00326 }
00327
00328
00329
00330
00331 int findIdIndex() {
00332 IndexIterator i = ii();
00333 while( i.more() ) {
00334 if( i.next().isIdIndex() )
00335 return i.pos()-1;
00336 }
00337 return -1;
00338 }
00339
00340
00341 static int bucket(int n) {
00342 for ( int i = 0; i < Buckets; i++ )
00343 if ( bucketSizes[i] > n )
00344 return i;
00345 return Buckets-1;
00346 }
00347
00348
00349 DiskLoc alloc(const char *ns, int lenToAlloc, DiskLoc& extentLoc);
00350
00351 void addDeletedRec(DeletedRecord *d, DiskLoc dloc);
00352 void dumpDeleted(set<DiskLoc> *extents = 0);
00353
00354 DiskLoc firstRecord( const DiskLoc &startExtent = DiskLoc() ) const;
00355
00356 DiskLoc lastRecord( const DiskLoc &startExtent = DiskLoc() ) const;
00357 long long storageSize( int * numExtents = 0 , BSONArrayBuilder * extentInfo = 0 ) const;
00358
00359 int averageObjectSize() {
00360 if ( stats.nrecords == 0 )
00361 return 5;
00362 return (int) (stats.datasize / stats.nrecords);
00363 }
00364
00365 NamespaceDetails *writingWithoutExtra() {
00366 return ( NamespaceDetails* ) getDur().writingPtr( this, sizeof( NamespaceDetails ) );
00367 }
00369 NamespaceDetails *writingWithExtra();
00370
00371 private:
00372 DiskLoc _alloc(const char *ns, int len);
00373 void maybeComplain( const char *ns, int len ) const;
00374 DiskLoc __stdAlloc(int len);
00375 void compact();
00376 friend class NamespaceIndex;
00377 struct ExtraOld {
00378
00379 unsigned long long reserved1;
00380 IndexDetails details[NIndexesExtra];
00381 unsigned reserved2;
00382 unsigned reserved3;
00383 };
00385 void cappedTruncateLastDelUpdate();
00386 BOOST_STATIC_ASSERT( NIndexesMax <= NIndexesBase + NIndexesExtra*2 );
00387 BOOST_STATIC_ASSERT( NIndexesMax <= 64 );
00388 BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::ExtraOld) == 496 );
00389 BOOST_STATIC_ASSERT( sizeof(NamespaceDetails::Extra) == 496 );
00390 };
00391 #pragma pack()
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 class NamespaceDetailsTransient : boost::noncopyable {
00406 BOOST_STATIC_ASSERT( sizeof(NamespaceDetails) == 496 );
00407
00408
00409 private:
00410 string _ns;
00411 void reset();
00412 static std::map< string, shared_ptr< NamespaceDetailsTransient > > _map;
00413 public:
00414 NamespaceDetailsTransient(const char *ns) : _ns(ns), _keysComputed(false), _qcWriteCount() { }
00415
00416 static NamespaceDetailsTransient& _get(const char *ns);
00417
00418 static NamespaceDetailsTransient& get_w(const char *ns) {
00419 DEV assertInWriteLock();
00420 return _get(ns);
00421 }
00422 void addedIndex() { reset(); }
00423 void deletedIndex() { reset(); }
00424
00425
00426
00427 static void clearForPrefix(const char *prefix);
00428
00429
00430
00431 private:
00432 bool _keysComputed;
00433 set<string> _indexKeys;
00434 void computeIndexKeys();
00435 public:
00436
00437
00438
00439 set<string>& indexKeys() {
00440 DEV assertInWriteLock();
00441 if ( !_keysComputed )
00442 computeIndexKeys();
00443 return _indexKeys;
00444 }
00445
00446
00447 private:
00448 map<const IndexDetails*,IndexSpec> _indexSpecs;
00449 static mongo::mutex _isMutex;
00450 public:
00451 const IndexSpec& getIndexSpec( const IndexDetails * details ) {
00452 IndexSpec& spec = _indexSpecs[details];
00453 if ( ! spec._finishedInit ) {
00454 scoped_lock lk(_isMutex);
00455 if ( ! spec._finishedInit ) {
00456 spec.reset( details );
00457 assert( spec._finishedInit );
00458 }
00459 }
00460 return spec;
00461 }
00462
00463
00464 private:
00465 int _qcWriteCount;
00466 map< QueryPattern, pair< BSONObj, long long > > _qcCache;
00467 public:
00468 static mongo::mutex _qcMutex;
00469
00470 static NamespaceDetailsTransient& get_inlock(const char *ns) {
00471 return _get(ns);
00472 }
00473 void clearQueryCache() {
00474 _qcCache.clear();
00475 _qcWriteCount = 0;
00476 }
00477
00478 void notifyOfWriteOp() {
00479 if ( _qcCache.empty() )
00480 return;
00481 if ( ++_qcWriteCount >= 100 )
00482 clearQueryCache();
00483 }
00484 BSONObj indexForPattern( const QueryPattern &pattern ) {
00485 return _qcCache[ pattern ].first;
00486 }
00487 long long nScannedForPattern( const QueryPattern &pattern ) {
00488 return _qcCache[ pattern ].second;
00489 }
00490 void registerIndexForPattern( const QueryPattern &pattern, const BSONObj &indexKey, long long nScanned ) {
00491 _qcCache[ pattern ] = make_pair( indexKey, nScanned );
00492 }
00493
00494 };
00495
00496 inline NamespaceDetailsTransient& NamespaceDetailsTransient::_get(const char *ns) {
00497 shared_ptr< NamespaceDetailsTransient > &t = _map[ ns ];
00498 if ( t.get() == 0 )
00499 t.reset( new NamespaceDetailsTransient(ns) );
00500 return *t;
00501 }
00502
00503
00504
00505
00506 class NamespaceIndex {
00507 friend class NamespaceCursor;
00508
00509 public:
00510 NamespaceIndex(const string &dir, const string &database) :
00511 ht( 0 ), dir_( dir ), database_( database ) {}
00512
00513
00514 bool exists() const;
00515
00516 void init();
00517
00518 void add_ns(const char *ns, DiskLoc& loc, bool capped) {
00519 NamespaceDetails details( loc, capped );
00520 add_ns( ns, details );
00521 }
00522 void add_ns( const char *ns, const NamespaceDetails &details ) {
00523 init();
00524 Namespace n(ns);
00525 uassert( 10081 , "too many namespaces/collections", ht->put(n, details));
00526 }
00527
00528
00529
00530
00531
00532
00533
00534
00535 NamespaceDetails* details(const char *ns) {
00536 if ( !ht )
00537 return 0;
00538 Namespace n(ns);
00539 NamespaceDetails *d = ht->get(n);
00540 if ( d && d->capped )
00541 d->cappedCheckMigrate();
00542 return d;
00543 }
00544
00545 void kill_ns(const char *ns);
00546
00547 bool find(const char *ns, DiskLoc& loc) {
00548 NamespaceDetails *l = details(ns);
00549 if ( l ) {
00550 loc = l->firstExtent;
00551 return true;
00552 }
00553 return false;
00554 }
00555
00556 bool allocated() const {
00557 return ht != 0;
00558 }
00559
00560 void getNamespaces( list<string>& tofill , bool onlyCollections = true ) const;
00561
00562 NamespaceDetails::Extra* newExtra(const char *ns, int n, NamespaceDetails *d);
00563
00564 boost::filesystem::path path() const;
00565
00566 private:
00567 void maybeMkdir() const;
00568
00569 MongoMMF f;
00570 HashTable<Namespace,NamespaceDetails> *ht;
00571 string dir_;
00572 string database_;
00573 };
00574
00575 extern string dbpath;
00576 extern bool directoryperdb;
00577
00578
00579
00580 void renameNamespace( const char *from, const char *to );
00581
00582
00583 inline void nsToDatabase(const char *ns, char *database) {
00584 const char *p = ns;
00585 char *q = database;
00586 while ( *p != '.' ) {
00587 if ( *p == 0 )
00588 break;
00589 *q++ = *p++;
00590 }
00591 *q = 0;
00592 if (q-database>=MaxDatabaseNameLen) {
00593 log() << "nsToDatabase: ns too long. terminating, buf overrun condition" << endl;
00594 dbexit( EXIT_POSSIBLE_CORRUPTION );
00595 }
00596 }
00597 inline string nsToDatabase(const char *ns) {
00598 char buf[MaxDatabaseNameLen];
00599 nsToDatabase(ns, buf);
00600 return buf;
00601 }
00602 inline string nsToDatabase(const string& ns) {
00603 size_t i = ns.find( '.' );
00604 if ( i == string::npos )
00605 return ns;
00606 return ns.substr( 0 , i );
00607 }
00608
00609 }