2010-05-19 23:01:09 +02:00
|
|
|
// shardconnection.cpp
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#include "shard.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "request.h"
|
|
|
|
#include <set>
|
|
|
|
|
|
|
|
namespace mongo {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* holds all the actual db connections for a client to various servers
|
|
|
|
*/
|
|
|
|
class ClientConnections : boost::noncopyable {
|
|
|
|
public:
|
|
|
|
struct Status : boost::noncopyable {
|
|
|
|
Status() : created(0){}
|
|
|
|
|
|
|
|
std::stack<DBClientBase*> avail;
|
|
|
|
long long created;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Nullstream& debug( Status * s = 0 , const string& addr = "" ){
|
2010-05-19 23:07:46 +02:00
|
|
|
static int ll = 9;
|
2010-05-19 23:01:09 +02:00
|
|
|
|
|
|
|
if ( logLevel < ll )
|
|
|
|
return nullstream;
|
|
|
|
Nullstream& l = log(ll);
|
|
|
|
|
|
|
|
l << "ClientConnections DEBUG " << this << " ";
|
|
|
|
if ( s ){
|
|
|
|
l << "s: " << s << " addr: " << addr << " ";
|
|
|
|
}
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
2010-05-26 06:46:49 +02:00
|
|
|
ClientConnections() : _mutex("ClientConnections") {
|
2010-05-19 23:01:09 +02:00
|
|
|
debug() << " NEW " << endl;
|
|
|
|
}
|
2010-05-20 19:36:29 +02:00
|
|
|
|
2010-05-19 23:01:09 +02:00
|
|
|
~ClientConnections(){
|
|
|
|
debug() << " KILLING " << endl;
|
|
|
|
for ( map<string,Status*>::iterator i=_hosts.begin(); i!=_hosts.end(); ++i ){
|
|
|
|
string addr = i->first;
|
|
|
|
Status* ss = i->second;
|
|
|
|
assert( ss );
|
|
|
|
std::stack<DBClientBase*>& s = ss->avail;
|
|
|
|
while ( ! s.empty() ){
|
|
|
|
pool.release( addr , s.top() );
|
|
|
|
s.pop();
|
|
|
|
}
|
|
|
|
delete ss;
|
|
|
|
}
|
|
|
|
_hosts.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
DBClientBase * get( const string& addr ){
|
|
|
|
scoped_lock lk( _mutex );
|
|
|
|
Status* &s = _hosts[addr];
|
|
|
|
if ( ! s )
|
|
|
|
s = new Status();
|
|
|
|
|
|
|
|
debug() << "WANT ONE pool empty: " << s->avail.empty() << endl;
|
|
|
|
|
|
|
|
if ( ! s->avail.empty() ){
|
|
|
|
DBClientBase* c = s->avail.top();
|
|
|
|
s->avail.pop();
|
|
|
|
debug( s , addr ) << "GOT " << c << endl;
|
|
|
|
pool.onHandedOut( c );
|
|
|
|
return c;
|
|
|
|
}
|
2010-05-24 23:24:41 +02:00
|
|
|
|
|
|
|
debug() << "CREATING NEW CONNECTION" << endl;
|
2010-05-19 23:01:09 +02:00
|
|
|
s->created++;
|
|
|
|
return pool.get( addr );
|
|
|
|
}
|
|
|
|
|
|
|
|
void done( const string& addr , DBClientBase* conn ){
|
|
|
|
scoped_lock lk( _mutex );
|
|
|
|
Status* s = _hosts[addr];
|
|
|
|
assert( s );
|
|
|
|
if ( s->avail.size() > 0 ){
|
|
|
|
delete conn;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
s->avail.push( conn );
|
|
|
|
debug( s , addr ) << "PUSHING: " << conn << endl;
|
|
|
|
}
|
2010-05-20 19:36:29 +02:00
|
|
|
|
|
|
|
void sync(){
|
|
|
|
scoped_lock lk( _mutex );
|
|
|
|
for ( map<string,Status*>::iterator i=_hosts.begin(); i!=_hosts.end(); ++i ){
|
|
|
|
string addr = i->first;
|
|
|
|
Status* ss = i->second;
|
|
|
|
assert( ss );
|
|
|
|
std::stack<DBClientBase*>& s = ss->avail;
|
|
|
|
while ( ! s.empty() ){
|
|
|
|
DBClientBase* conn = s.top();
|
|
|
|
conn->getLastError();
|
|
|
|
pool.release( addr , conn );
|
|
|
|
s.pop();
|
|
|
|
}
|
2010-05-27 03:47:02 +02:00
|
|
|
delete ss;
|
2010-05-20 19:36:29 +02:00
|
|
|
}
|
|
|
|
_hosts.clear();
|
|
|
|
}
|
|
|
|
|
2010-05-19 23:01:09 +02:00
|
|
|
map<string,Status*> _hosts;
|
|
|
|
mongo::mutex _mutex;
|
|
|
|
|
|
|
|
// -----
|
|
|
|
|
|
|
|
static thread_specific_ptr<ClientConnections> _perThread;
|
|
|
|
|
|
|
|
static ClientConnections* get(){
|
|
|
|
ClientConnections* cc = _perThread.get();
|
|
|
|
if ( ! cc ){
|
|
|
|
cc = new ClientConnections();
|
|
|
|
_perThread.reset( cc );
|
|
|
|
}
|
|
|
|
return cc;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
thread_specific_ptr<ClientConnections> ClientConnections::_perThread;
|
|
|
|
|
2010-05-20 19:36:29 +02:00
|
|
|
ShardConnection::ShardConnection( const Shard * s , const string& ns )
|
|
|
|
: _addr( s->getConnString() ) , _ns( ns ) {
|
2010-05-19 23:01:09 +02:00
|
|
|
_init();
|
|
|
|
}
|
|
|
|
|
2010-05-20 19:36:29 +02:00
|
|
|
ShardConnection::ShardConnection( const Shard& s , const string& ns )
|
|
|
|
: _addr( s.getConnString() ) , _ns( ns ) {
|
2010-05-19 23:01:09 +02:00
|
|
|
_init();
|
|
|
|
}
|
|
|
|
|
2010-05-20 19:36:29 +02:00
|
|
|
ShardConnection::ShardConnection( const string& addr , const string& ns )
|
|
|
|
: _addr( addr ) , _ns( ns ) {
|
2010-05-19 23:01:09 +02:00
|
|
|
_init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShardConnection::_init(){
|
|
|
|
assert( _addr.size() );
|
|
|
|
_conn = ClientConnections::get()->get( _addr );
|
2010-05-20 19:36:29 +02:00
|
|
|
|
|
|
|
if ( _ns.size() ){
|
2010-07-01 23:44:13 +02:00
|
|
|
_setVersion = checkShardVersion( *_conn , _ns );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
_setVersion = false;
|
2010-05-20 19:36:29 +02:00
|
|
|
}
|
|
|
|
|
2010-05-19 23:01:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void ShardConnection::done(){
|
|
|
|
if ( _conn ){
|
|
|
|
ClientConnections::get()->done( _addr , _conn );
|
|
|
|
_conn = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShardConnection::kill(){
|
|
|
|
if ( _conn ){
|
|
|
|
delete _conn;
|
|
|
|
_conn = 0;
|
|
|
|
}
|
|
|
|
}
|
2010-05-20 19:36:29 +02:00
|
|
|
|
|
|
|
void ShardConnection::sync(){
|
|
|
|
ClientConnections::get()->sync();
|
|
|
|
}
|
2010-05-27 22:33:20 +02:00
|
|
|
|
|
|
|
ShardConnection::~ShardConnection() {
|
|
|
|
if ( _conn ){
|
|
|
|
if ( ! _conn->isFailed() ) {
|
|
|
|
/* see done() comments above for why we log this line */
|
|
|
|
log() << "~ScopedDBConnection: _conn != null" << endl;
|
|
|
|
}
|
|
|
|
kill();
|
|
|
|
}
|
|
|
|
}
|
2010-05-19 23:01:09 +02:00
|
|
|
}
|