/** * Copyright (C) 2008 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #pragma once #include "../pch.h" #include "../util/net/message.h" #include "concurrency.h" #include "pdfile.h" #include "curop.h" #include "client.h" namespace mongo { // void jniCallback(Message& m, Message& out); /** * class to hold path + dbname -> Database * might be able to optimizer further */ class DatabaseHolder { public: typedef map DBs; typedef map Paths; DatabaseHolder() : _size(0) { } bool isLoaded( const string& ns , const string& path ) const { dbMutex.assertAtLeastReadLocked(); Paths::const_iterator x = _paths.find( path ); if ( x == _paths.end() ) return false; const DBs& m = x->second; string db = _todb( ns ); DBs::const_iterator it = m.find(db); return it != m.end(); } Database * get( const string& ns , const string& path ) const { dbMutex.assertAtLeastReadLocked(); Paths::const_iterator x = _paths.find( path ); if ( x == _paths.end() ) return 0; const DBs& m = x->second; string db = _todb( ns ); DBs::const_iterator it = m.find(db); if ( it != m.end() ) return it->second; return 0; } void put( const string& ns , const string& path , Database * db ) { dbMutex.assertWriteLocked(); DBs& m = _paths[path]; Database*& d = m[_todb(ns)]; if ( ! d ) _size++; d = db; } Database* getOrCreate( const string& ns , const string& path , bool& justCreated ); void erase( const string& ns , const string& path ) { dbMutex.assertWriteLocked(); DBs& m = _paths[path]; _size -= (int)m.erase( _todb( ns ) ); } /* force - force close even if something underway - use at shutdown */ bool closeAll( const string& path , BSONObjBuilder& result, bool force ); int size() { return _size; } void forEach(boost::function f) const { dbMutex.assertAtLeastReadLocked(); for ( Paths::const_iterator i=_paths.begin(); i!=_paths.end(); i++ ) { DBs m = i->second; for( DBs::const_iterator j=m.begin(); j!=m.end(); j++ ) { f(j->second); } } } /** * gets all unique db names, ignoring paths */ void getAllShortNames( set& all ) const { dbMutex.assertAtLeastReadLocked(); for ( Paths::const_iterator i=_paths.begin(); i!=_paths.end(); i++ ) { DBs m = i->second; for( DBs::const_iterator j=m.begin(); j!=m.end(); j++ ) { all.insert( j->first ); } } } private: string _todb( const string& ns ) const { string d = __todb( ns ); uassert( 13280 , (string)"invalid db name: " + ns , Database::validDBName( d ) ); return d; } string __todb( const string& ns ) const { size_t i = ns.find( '.' ); if ( i == string::npos ) { uassert( 13074 , "db name can't be empty" , ns.size() ); return ns; } uassert( 13075 , "db name can't be empty" , i > 0 ); return ns.substr( 0 , i ); } Paths _paths; int _size; }; extern DatabaseHolder dbHolder; struct dbtemprelease { Client::Context * _context; int _locktype; dbtemprelease() { const Client& c = cc(); _context = c.getContext(); _locktype = dbMutex.getState(); assert( _locktype ); if ( _locktype > 0 ) { massert( 10298 , "can't temprelease nested write lock", _locktype == 1); if ( _context ) _context->unlocked(); dbMutex.unlock(); } else { massert( 10299 , "can't temprelease nested read lock", _locktype == -1); if ( _context ) _context->unlocked(); dbMutex.unlock_shared(); } verify( 14814 , c.curop() ); c.curop()->yielded(); } ~dbtemprelease() { if ( _locktype > 0 ) dbMutex.lock(); else dbMutex.lock_shared(); if ( _context ) _context->relocked(); } }; /** must be write locked no assert (and no release) if nested write lock a lot like dbtempreleasecond but no malloc so should be a tiny bit faster */ struct dbtempreleasewritelock { Client::Context * _context; int _locktype; dbtempreleasewritelock() { const Client& c = cc(); _context = c.getContext(); _locktype = dbMutex.getState(); assert( _locktype >= 1 ); if( _locktype > 1 ) return; // nested if ( _context ) _context->unlocked(); dbMutex.unlock(); verify( 14845 , c.curop() ); c.curop()->yielded(); } ~dbtempreleasewritelock() { if ( _locktype == 1 ) dbMutex.lock(); if ( _context ) _context->relocked(); } }; /** only does a temp release if we're not nested and have a lock */ struct dbtempreleasecond { dbtemprelease * real; int locktype; dbtempreleasecond() { real = 0; locktype = dbMutex.getState(); if ( locktype == 1 || locktype == -1 ) real = new dbtemprelease(); } ~dbtempreleasecond() { if ( real ) { delete real; real = 0; } } bool unlocked() { return real > 0; } }; } // namespace mongo //#include "dbinfo.h" #include "concurrency.h"