diff options
Diffstat (limited to 'db/client.h')
-rw-r--r-- | db/client.h | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/db/client.h b/db/client.h new file mode 100644 index 0000000..99092ca --- /dev/null +++ b/db/client.h @@ -0,0 +1,193 @@ +// client.h
+
+/** +* 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 <http://www.gnu.org/licenses/>. +*/ + +/* Client represents a connection to the database (the server-side) and corresponds + to an open socket (or logical connection if pooling on sockets) from a client. + + todo: switch to asio...this will fit nicely with that. +*/ + +#pragma once + +#include "../stdafx.h" +#include "namespace.h" +#include "lasterror.h" +#include "../util/top.h" + +namespace mongo { + + class AuthenticationInfo; + class Database; + class CurOp; + class Command; + class Client; + + extern boost::thread_specific_ptr<Client> currentClient; + + bool setClient(const char *ns, const string& path=dbpath, mongolock *lock = 0); + + + class Client : boost::noncopyable { + public: + static boost::mutex clientsMutex; + static set<Client*> clients; // always be in clientsMutex when manipulating this + + class GodScope { + bool _prev; + public: + GodScope(); + ~GodScope(); + }; + + /* Set database we want to use, then, restores when we finish (are out of scope) + Note this is also helpful if an exception happens as the state if fixed up. + */ + class Context { + Client * _client; + Database * _olddb; + string _oldns; + public: + Context(const char *ns) + : _client( currentClient.get() ) { + _olddb = _client->_database; + _oldns = _client->_ns; + setClient(ns); + } + Context(string ns) + : _client( currentClient.get() ){ + _olddb = _client->_database; + _oldns = _client->_ns; + setClient(ns.c_str()); + } + + /* this version saves the context but doesn't yet set the new one: */ + Context() + : _client( currentClient.get() ) { + _olddb = _client->database(); + _oldns = _client->ns(); + + } + + /** + * if you are doing this after allowing a write there could be a race condition + * if someone closes that db. this checks that the DB is still valid + */ + Context( string ns , Database * db ); + + ~Context() { + DEV assert( _client == currentClient.get() ); + _client->setns( _oldns.c_str(), _olddb ); + } + + }; + + private: + CurOp * const _curOp; + Database *_database; + Namespace _ns; + //NamespaceString _nsstr; + bool _shutdown; + list<string> _tempCollections; + const char *_desc; + bool _god; + public: + AuthenticationInfo *ai; + Top top; + + CurOp* curop() { return _curOp; } + Database* database() { + return _database; + } + const char *ns() { return _ns.buf; } + + void setns(const char *ns, Database *db) { + _database = db; + _ns = ns; + //_nsstr = ns; + } + void clearns() { setns("", 0); } + + Client(const char *desc); + ~Client(); + + const char *desc() const { return _desc; } + + void addTempCollection( const string& ns ){ + _tempCollections.push_back( ns ); + } + + /* each thread which does db operations has a Client object in TLS. + call this when your thread starts. + */ + static void initThread(const char *desc); + + /* + this has to be called as the client goes away, but before thread termination + @return true if anything was done + */ + bool shutdown(); + + bool isGod() const { return _god; } + }; + + inline Client& cc() { + return *currentClient.get(); + } + + /* each thread which does db operations has a Client object in TLS. + call this when your thread starts. + */ + inline void Client::initThread(const char *desc) { + assert( currentClient.get() == 0 ); + currentClient.reset( new Client(desc) ); + } + + inline Client::GodScope::GodScope(){ + _prev = cc()._god; + cc()._god = true; + } + + inline Client::GodScope::~GodScope(){ + cc()._god = _prev; + } + + /* this unlocks, does NOT upgrade. that works for our current usage */ + inline void mongolock::releaseAndWriteLock() { + if( !_writelock ) { + +#if BOOST_VERSION >= 103500 + int s = dbMutex.getState(); + if( s != -1 ) { + log() << "error: releaseAndWriteLock() s == " << s << endl; + msgasserted( 12600, "releaseAndWriteLock: unlock_shared failed, probably recursive" ); + } +#endif + + _writelock = true; + dbMutex.unlock_shared(); + dbMutex.lock(); + + /* this is defensive; as we were unlocked for a moment above, + the Database object we reference could have been deleted: + */ + cc().clearns(); + } + } + +}; + |