Files
mongo/db/client.h

276 lines
9.2 KiB
C
Raw Normal View History

// 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/>.
*/
2011-01-04 00:40:41 -05:00
/* 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
2010-04-27 15:27:52 -04:00
#include "../pch.h"
#include "security.h"
2010-11-04 09:07:28 -04:00
#include "namespace-inl.h"
#include "lasterror.h"
2010-02-01 10:47:28 -05:00
#include "stats/top.h"
2011-08-26 21:01:01 -04:00
#include "../util/concurrency/threadlocal.h"
#include "../db/client_common.h"
#include "../util/net/message_port.h"
2011-01-04 00:40:41 -05:00
namespace mongo {
2010-06-26 13:06:03 -04:00
extern class ReplSet *theReplSet;
2009-10-13 16:01:02 -04:00
class AuthenticationInfo;
class Database;
2009-12-21 13:19:20 -05:00
class CurOp;
2009-12-31 16:22:28 -05:00
class Command;
2010-01-17 16:57:35 -05:00
class Client;
2011-04-05 02:24:16 -04:00
class AbstractMessagingPort;
2010-01-17 16:57:35 -05:00
2011-09-14 11:39:20 -04:00
TSP_DECLARE(Client, currentClient)
2010-01-17 16:57:35 -05:00
typedef long long ConnectionId;
2011-03-22 11:02:42 -04:00
/** the database's concept of an outside "client" */
class Client : public ClientBasic {
public:
2011-01-03 12:07:04 -05:00
class Context;
static mongo::mutex clientsMutex;
static set<Client*> clients; // always be in clientsMutex when manipulating this
static int recommendedYieldMicros( int * writers = 0 , int * readers = 0 );
static int getActiveClientCount( int& writers , int& readers );
static Client *syncThread;
2011-01-03 12:07:04 -05:00
2011-01-04 00:40:41 -05:00
/* each thread which does db operations has a Client object in TLS.
call this when your thread starts.
2011-01-03 12:07:04 -05:00
*/
2011-04-05 02:24:16 -04:00
static Client& initThread(const char *desc, AbstractMessagingPort *mp = 0);
2011-01-03 12:07:04 -05:00
2011-08-16 18:40:40 -04:00
static void initThreadIfNotAlready(const char *desc) {
if( currentClient.get() )
return;
initThread(desc);
}
2011-03-22 11:02:42 -04:00
~Client();
2011-01-04 00:40:41 -05:00
/*
2011-01-03 12:07:04 -05:00
this has to be called as the client goes away, but before thread termination
@return true if anything was done
*/
bool shutdown();
2011-05-21 10:07:22 -04:00
/** set so isSyncThread() works */
2011-01-04 00:40:41 -05:00
void iAmSyncThread() {
wassert( syncThread == 0 );
2011-01-04 00:40:41 -05:00
syncThread = this;
}
2011-05-21 10:07:22 -04:00
/** @return true if this client is the replication secondary pull thread. not used much, is used in create index sync code. */
bool isSyncThread() const { return this == syncThread; }
2011-01-03 12:07:04 -05:00
string clientAddress(bool includePort=false) const;
const AuthenticationInfo * getAuthenticationInfo() const { return &_ai; }
2011-01-03 12:07:04 -05:00
AuthenticationInfo * getAuthenticationInfo() { return &_ai; }
bool isAdmin() { return _ai.isAuthorized( "admin" ); }
2011-01-04 00:40:41 -05:00
CurOp* curop() const { return _curOp; }
2011-01-03 12:07:04 -05:00
Context* getContext() const { return _context; }
Database* database() const { return _context ? _context->db() : 0; }
const char *ns() const { return _context->ns(); }
const char *desc() const { return _desc; }
void setLastOp( OpTime op ) { _lastOp = op; }
OpTime getLastOp() const { return _lastOp; }
2011-01-03 12:07:04 -05:00
2011-08-16 18:40:40 -04:00
/** caution -- use Context class instead */
void setContext(Context *c) { _context = c; }
2011-01-03 12:07:04 -05:00
/* report what the last operation was. used by getlasterror */
void appendLastOp( BSONObjBuilder& b ) const;
bool isGod() const { return _god; } /* this is for map/reduce writes */
string toString() const;
void gotHandshake( const BSONObj& o );
2011-09-30 00:43:36 -04:00
bool hasRemote() const { return _mp; }
HostAndPort getRemote() const { assert( _mp ); return _mp->remote(); }
2011-01-03 12:07:04 -05:00
BSONObj getRemoteID() const { return _remoteId; }
BSONObj getHandshake() const { return _handshake; }
2011-04-05 02:24:16 -04:00
AbstractMessagingPort * port() const { return _mp; }
ConnectionId getConnectionId() const { return _connectionId; }
2011-01-03 12:07:04 -05:00
private:
ConnectionId _connectionId; // > 0 for things "conn", 0 otherwise
2011-05-29 04:05:49 -04:00
string _threadId; // "" on non support systems
2011-01-03 12:07:04 -05:00
CurOp * _curOp;
Context * _context;
bool _shutdown;
const char *_desc;
bool _god;
AuthenticationInfo _ai;
OpTime _lastOp;
2011-01-03 12:07:04 -05:00
BSONObj _handshake;
BSONObj _remoteId;
2011-04-05 02:24:16 -04:00
AbstractMessagingPort * const _mp;
2011-01-03 12:07:04 -05:00
2011-04-05 02:24:16 -04:00
Client(const char *desc, AbstractMessagingPort *p = 0);
2011-01-03 12:07:04 -05:00
friend class CurOp;
unsigned _sometimes;
public:
/** the concept here is the same as MONGO_SOMETIMES. however that
macro uses a static that will be shared by all threads, and each
time incremented it might eject that line from the other cpu caches (?),
so idea is that this is better.
*/
bool sometimes(unsigned howOften) { return ++_sometimes % howOften == 0; }
2010-08-25 13:01:36 -04:00
/* set _god=true temporarily, safely */
2009-10-23 11:13:08 -04:00
class GodScope {
bool _prev;
public:
GodScope();
~GodScope();
};
2010-01-17 16:57:35 -05:00
/* 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.
*/
2011-01-04 00:40:41 -05:00
class Context : boost::noncopyable {
2010-01-17 16:57:35 -05:00
public:
2011-01-04 00:40:41 -05:00
/**
2011-01-03 12:00:41 -05:00
* this is the main constructor
* use this unless there is a good reason not to
*/
Context(const string& ns, string path=dbpath, mongolock * lock = 0 , bool doauth=true );
2011-01-04 00:40:41 -05:00
2010-01-17 16:57:35 -05:00
/* this version saves the context but doesn't yet set the new one: */
2011-01-03 12:00:41 -05:00
Context();
2011-01-04 00:40:41 -05:00
/**
* 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, bool doauth=true );
2011-01-04 00:40:41 -05:00
~Context();
2010-01-17 16:57:35 -05:00
2011-01-04 00:40:41 -05:00
Client* getClient() const { return _client; }
2010-05-29 16:17:33 -04:00
Database* db() const { return _db; }
2011-01-04 00:40:41 -05:00
const char * ns() const { return _ns.c_str(); }
2011-01-03 12:00:41 -05:00
/** @return if the db was created by this Context */
2010-05-29 16:17:33 -04:00
bool justCreated() const { return _justCreated; }
2011-01-03 12:00:41 -05:00
bool equals( const string& ns , const string& path=dbpath ) const { return _ns == ns && _path == path; }
2011-01-04 00:40:41 -05:00
2011-01-03 12:00:41 -05:00
/**
* @return true iff the current Context is using db/path
*/
bool inDB( const string& db , const string& path=dbpath ) const;
2011-01-04 00:40:41 -05:00
void clear() { _ns = ""; _db = 0; }
/**
* call before unlocking, so clear any non-thread safe state
*/
2011-01-04 00:40:41 -05:00
void unlocked() { _db = 0; }
2010-01-17 16:57:35 -05:00
/**
* call after going back into the lock, will re-establish non-thread safe stuff
*/
2011-01-04 00:40:41 -05:00
void relocked() { _finishInit(); }
friend class CurOp;
2011-01-03 12:00:41 -05:00
private:
/**
* at this point _client, _oldContext and _ns have to be set
* _db should not have been touched
* this will set _db and create if needed
* will also set _client->_context to this
*/
void _finishInit( bool doauth=true);
2011-01-04 00:40:41 -05:00
2011-01-03 12:00:41 -05:00
void _auth( int lockState = dbMutex.getState() );
Client * _client;
Context * _oldContext;
2011-01-04 00:40:41 -05:00
2011-01-03 12:00:41 -05:00
string _path;
mongolock * _lock;
bool _justCreated;
string _ns;
Database * _db;
2010-08-27 16:38:56 -04:00
}; // class Client::Context
2011-01-04 00:40:41 -05:00
2011-11-17 08:09:07 -05:00
struct LockStatus {
LockStatus() : db(), coll() { }
int db;
int coll;
2011-11-17 08:04:44 -05:00
} lockStatus;
}; // class Client
2011-01-04 00:40:41 -05:00
2010-08-25 13:01:36 -04:00
/** get the Client object for this thread. */
2011-01-04 00:40:41 -05:00
inline Client& cc() {
2010-07-20 17:00:40 -04:00
Client * c = currentClient.get();
assert( c );
return *c;
2009-10-13 16:01:02 -04:00
}
2011-01-04 00:40:41 -05:00
inline Client::GodScope::GodScope() {
2009-10-23 11:13:08 -04:00
_prev = cc()._god;
cc()._god = true;
}
2010-10-11 21:51:30 -04:00
inline Client::GodScope::~GodScope() { cc()._god = _prev; }
2009-12-03 11:50:09 -05:00
2011-10-24 17:56:19 -04:00
/* this unreadlocks and then writelocks; i.e. it does NOT upgrade inside the
lock (and is thus wrong to use if you need that, which is usually).
that said we use it today for a specific case where the usage is correct.
*/
2011-01-04 00:40:41 -05:00
inline void mongolock::releaseAndWriteLock() {
2009-12-06 10:06:02 -05:00
if( !_writelock ) {
#if BOOST_VERSION >= 103500
2009-12-06 10:06:02 -05:00
int s = dbMutex.getState();
if( s != -1 ) {
log() << "error: releaseAndWriteLock() s == " << s << endl;
msgasserted( 12600, "releaseAndWriteLock: unlock_shared failed, probably recursive" );
2009-12-06 10:06:02 -05:00
}
#endif
2009-12-03 11:50:09 -05:00
_writelock = true;
dbMutex.unlock_shared();
dbMutex.lock();
2011-10-24 17:56:19 -04:00
// todo: unlocked() method says to call it before unlocking, not after. so fix this here,
// or fix the doc there.
2010-01-29 22:00:50 -05:00
if ( cc().getContext() )
cc().getContext()->unlocked();
2009-12-03 11:50:09 -05:00
}
}
2010-02-04 22:51:57 -05:00
string sayClientState();
2011-01-04 00:40:41 -05:00
2010-08-25 13:01:36 -04:00
inline bool haveClient() { return currentClient.get() > 0; }
};