summaryrefslogtreecommitdiff
path: root/db/client.h
diff options
context:
space:
mode:
Diffstat (limited to 'db/client.h')
-rw-r--r--db/client.h193
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();
+ }
+ }
+
+};
+