00001
00017 #pragma once
00018
00019 #include "../pch.h"
00020 #include "../util/message.h"
00021 #include "concurrency.h"
00022 #include "pdfile.h"
00023 #include "client.h"
00024
00025 namespace mongo {
00026
00027
00028
00033 class DatabaseHolder {
00034 public:
00035 typedef map<string,Database*> DBs;
00036 typedef map<string,DBs> Paths;
00037
00038 DatabaseHolder() : _size(0) { }
00039
00040 bool isLoaded( const string& ns , const string& path ) const {
00041 dbMutex.assertAtLeastReadLocked();
00042 Paths::const_iterator x = _paths.find( path );
00043 if ( x == _paths.end() )
00044 return false;
00045 const DBs& m = x->second;
00046
00047 string db = _todb( ns );
00048
00049 DBs::const_iterator it = m.find(db);
00050 return it != m.end();
00051 }
00052
00053 Database * get( const string& ns , const string& path ) const {
00054 dbMutex.assertAtLeastReadLocked();
00055 Paths::const_iterator x = _paths.find( path );
00056 if ( x == _paths.end() )
00057 return 0;
00058 const DBs& m = x->second;
00059
00060 string db = _todb( ns );
00061
00062 DBs::const_iterator it = m.find(db);
00063 if ( it != m.end() )
00064 return it->second;
00065 return 0;
00066 }
00067
00068 void put( const string& ns , const string& path , Database * db ) {
00069 dbMutex.assertWriteLocked();
00070 DBs& m = _paths[path];
00071 Database*& d = m[_todb(ns)];
00072 if ( ! d )
00073 _size++;
00074 d = db;
00075 }
00076
00077 Database* getOrCreate( const string& ns , const string& path , bool& justCreated );
00078
00079 void erase( const string& ns , const string& path ) {
00080 dbMutex.assertWriteLocked();
00081 DBs& m = _paths[path];
00082 _size -= (int)m.erase( _todb( ns ) );
00083 }
00084
00085
00086 bool closeAll( const string& path , BSONObjBuilder& result, bool force );
00087
00088 int size() {
00089 return _size;
00090 }
00091
00092 void forEach(boost::function<void(Database *)> f) const {
00093 dbMutex.assertAtLeastReadLocked();
00094 for ( Paths::const_iterator i=_paths.begin(); i!=_paths.end(); i++ ) {
00095 DBs m = i->second;
00096 for( DBs::const_iterator j=m.begin(); j!=m.end(); j++ ) {
00097 f(j->second);
00098 }
00099 }
00100 }
00101
00105 void getAllShortNames( set<string>& all ) const {
00106 dbMutex.assertAtLeastReadLocked();
00107 for ( Paths::const_iterator i=_paths.begin(); i!=_paths.end(); i++ ) {
00108 DBs m = i->second;
00109 for( DBs::const_iterator j=m.begin(); j!=m.end(); j++ ) {
00110 all.insert( j->first );
00111 }
00112 }
00113 }
00114
00115 private:
00116
00117 string _todb( const string& ns ) const {
00118 string d = __todb( ns );
00119 uassert( 13280 , (string)"invalid db name: " + ns , Database::validDBName( d ) );
00120 return d;
00121 }
00122
00123 string __todb( const string& ns ) const {
00124 size_t i = ns.find( '.' );
00125 if ( i == string::npos ) {
00126 uassert( 13074 , "db name can't be empty" , ns.size() );
00127 return ns;
00128 }
00129 uassert( 13075 , "db name can't be empty" , i > 0 );
00130 return ns.substr( 0 , i );
00131 }
00132
00133 Paths _paths;
00134 int _size;
00135
00136 };
00137
00138 extern DatabaseHolder dbHolder;
00139
00140 struct dbtemprelease {
00141 Client::Context * _context;
00142 int _locktype;
00143
00144 dbtemprelease() {
00145 _context = cc().getContext();
00146 _locktype = dbMutex.getState();
00147 assert( _locktype );
00148
00149 if ( _locktype > 0 ) {
00150 massert( 10298 , "can't temprelease nested write lock", _locktype == 1);
00151 if ( _context ) _context->unlocked();
00152 dbMutex.unlock();
00153 }
00154 else {
00155 massert( 10299 , "can't temprelease nested read lock", _locktype == -1);
00156 if ( _context ) _context->unlocked();
00157 dbMutex.unlock_shared();
00158 }
00159
00160 }
00161 ~dbtemprelease() {
00162 if ( _locktype > 0 )
00163 dbMutex.lock();
00164 else
00165 dbMutex.lock_shared();
00166
00167 if ( _context ) _context->relocked();
00168 }
00169 };
00170
00171
00175 struct dbtempreleasecond {
00176 dbtemprelease * real;
00177 int locktype;
00178
00179 dbtempreleasecond() {
00180 real = 0;
00181 locktype = dbMutex.getState();
00182 if ( locktype == 1 || locktype == -1 )
00183 real = new dbtemprelease();
00184 }
00185
00186 ~dbtempreleasecond() {
00187 if ( real ) {
00188 delete real;
00189 real = 0;
00190 }
00191 }
00192
00193 bool unlocked() {
00194 return real > 0;
00195 }
00196 };
00197
00198 }
00199
00200
00201 #include "concurrency.h"