2010-12-17 20:08:07 +01:00
|
|
|
// dbclient.cpp - connect to a Mongo database as a database, from C++
|
|
|
|
|
|
|
|
/* Copyright 2009 10gen Inc.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "pch.h"
|
|
|
|
#include "dbclient.h"
|
|
|
|
#include "../bson/util/builder.h"
|
|
|
|
#include "../db/jsobj.h"
|
|
|
|
#include "../db/json.h"
|
2010-12-20 08:21:41 +01:00
|
|
|
#include "../db/dbmessage.h"
|
2010-12-17 20:08:07 +01:00
|
|
|
#include "connpool.h"
|
2010-12-19 03:38:19 +01:00
|
|
|
#include "dbclient_rs.h"
|
2010-12-20 07:28:10 +01:00
|
|
|
#include "../util/background.h"
|
2010-12-17 20:08:07 +01:00
|
|
|
|
|
|
|
namespace mongo {
|
2010-12-19 03:38:19 +01:00
|
|
|
|
|
|
|
// --------------------------------
|
|
|
|
// ----- ReplicaSetMonitor ---------
|
|
|
|
// --------------------------------
|
2010-12-17 20:08:07 +01:00
|
|
|
|
2010-12-20 07:28:10 +01:00
|
|
|
// global background job responsible for checking every X amount of time
|
|
|
|
class ReplicaSetMonitorWatcher : public BackgroundJob {
|
|
|
|
protected:
|
|
|
|
void run(){
|
|
|
|
sleepsecs( 20 );
|
|
|
|
try {
|
|
|
|
ReplicaSetMonitor::checkAll();
|
|
|
|
}
|
|
|
|
catch ( std::exception& e ){
|
|
|
|
error() << "ReplicaSetMonitorWatcher: check failed: " << e.what() << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} replicaSetMonitorWatcher;
|
|
|
|
|
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
ReplicaSetMonitor::ReplicaSetMonitor( const string& name , const vector<HostAndPort>& servers )
|
|
|
|
: _lock( "ReplicaSetMonitor instance" ) , _name( name ) , _master(-1) {
|
|
|
|
|
|
|
|
string errmsg;
|
2010-12-17 20:08:07 +01:00
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
for ( unsigned i=0; i<servers.size(); i++ ){
|
2010-12-29 01:22:37 +01:00
|
|
|
DBClientConnection conn( true );
|
|
|
|
if (!conn.connect( servers[i] , errmsg ) ){
|
|
|
|
log(1) << "error connecting to seed " << servers[i] << ": " << errmsg << endl;
|
|
|
|
// skip seeds that don't work
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
string maybePrimary;
|
|
|
|
if (_checkConnection(&conn, maybePrimary, false)) {
|
|
|
|
break;
|
2010-12-19 03:38:19 +01:00
|
|
|
}
|
|
|
|
}
|
2010-12-17 20:08:07 +01:00
|
|
|
}
|
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
ReplicaSetMonitor::~ReplicaSetMonitor(){
|
|
|
|
for ( unsigned i=0; i<_nodes.size(); i++ )
|
|
|
|
delete _nodes[i].conn;
|
|
|
|
_nodes.clear();
|
|
|
|
_master = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReplicaSetMonitorPtr ReplicaSetMonitor::get( const string& name , const vector<HostAndPort>& servers ){
|
|
|
|
scoped_lock lk( _setsLock );
|
2010-12-19 07:25:32 +01:00
|
|
|
ReplicaSetMonitorPtr& m = _sets[name];
|
|
|
|
if ( ! m )
|
|
|
|
m.reset( new ReplicaSetMonitor( name , servers ) );
|
2010-12-20 07:28:10 +01:00
|
|
|
|
|
|
|
if ( replicaSetMonitorWatcher.getState() == BackgroundJob::NotStarted )
|
|
|
|
replicaSetMonitorWatcher.go();
|
|
|
|
|
2010-12-19 07:25:32 +01:00
|
|
|
return m;
|
2010-12-17 20:08:07 +01:00
|
|
|
}
|
|
|
|
|
2010-12-20 07:28:10 +01:00
|
|
|
void ReplicaSetMonitor::checkAll(){
|
|
|
|
set<string> seen;
|
|
|
|
|
|
|
|
while ( true ){
|
|
|
|
ReplicaSetMonitorPtr m;
|
|
|
|
{
|
|
|
|
for ( map<string,ReplicaSetMonitorPtr>::iterator i=_sets.begin(); i!=_sets.end(); ++i ){
|
|
|
|
string name = i->first;
|
|
|
|
if ( seen.count( name ) )
|
|
|
|
continue;
|
|
|
|
LOG(0) << "checking replica set: " << name << endl;
|
|
|
|
seen.insert( name );
|
|
|
|
m = i->second;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! m )
|
|
|
|
break;
|
|
|
|
|
|
|
|
m->check();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-12-20 18:52:31 +01:00
|
|
|
void ReplicaSetMonitor::setConfigChangeHook( ConfigChangeHook hook ){
|
|
|
|
massert( 13610 , "ConfigChangeHook already specified" , _hook == 0 );
|
2010-12-20 07:28:10 +01:00
|
|
|
_hook = hook;
|
|
|
|
}
|
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
string ReplicaSetMonitor::getServerAddress() const {
|
2010-12-17 20:08:07 +01:00
|
|
|
StringBuilder ss;
|
|
|
|
if ( _name.size() )
|
|
|
|
ss << _name << "/";
|
2010-12-19 03:38:19 +01:00
|
|
|
|
|
|
|
{
|
|
|
|
scoped_lock lk( _lock );
|
|
|
|
for ( unsigned i=0; i<_nodes.size(); i++ ){
|
|
|
|
if ( i > 0 )
|
|
|
|
ss << ",";
|
|
|
|
ss << _nodes[i].addr.toString();
|
|
|
|
}
|
2010-12-17 20:08:07 +01:00
|
|
|
}
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
void ReplicaSetMonitor::notifyFailure( const HostAndPort& server ){
|
|
|
|
if ( _master >= 0 ){
|
|
|
|
scoped_lock lk( _lock );
|
|
|
|
if ( server == _nodes[_master].addr )
|
|
|
|
_master = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HostAndPort ReplicaSetMonitor::getMaster(){
|
|
|
|
if ( _master < 0 )
|
|
|
|
_check();
|
2010-12-17 20:08:07 +01:00
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
uassert( 10009 , str::stream() << "ReplicaSetMonitor no master found for set: " << _name , _master >= 0 );
|
2010-12-17 20:08:07 +01:00
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
scoped_lock lk( _lock );
|
|
|
|
return _nodes[_master].addr;
|
|
|
|
}
|
2010-12-19 05:54:29 +01:00
|
|
|
|
|
|
|
HostAndPort ReplicaSetMonitor::getSlave(){
|
|
|
|
int x = rand() % _nodes.size();
|
|
|
|
{
|
|
|
|
scoped_lock lk( _lock );
|
2010-12-19 06:00:48 +01:00
|
|
|
for ( unsigned i=0; i<_nodes.size(); i++ ){
|
2010-12-19 05:54:29 +01:00
|
|
|
int p = ( i + x ) % _nodes.size();
|
|
|
|
if ( p == _master )
|
|
|
|
continue;
|
|
|
|
if ( _nodes[p].ok )
|
|
|
|
return _nodes[p].addr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return _nodes[0].addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* notify the monitor that server has faild
|
|
|
|
*/
|
|
|
|
void ReplicaSetMonitor::notifySlaveFailure( const HostAndPort& server ){
|
|
|
|
int x = _find( server );
|
|
|
|
if ( x >= 0 ){
|
|
|
|
scoped_lock lk( _lock );
|
|
|
|
_nodes[x].ok = false;
|
|
|
|
}
|
|
|
|
}
|
2010-12-19 03:38:19 +01:00
|
|
|
|
2010-12-29 01:22:37 +01:00
|
|
|
void ReplicaSetMonitor::_checkStatus(DBClientConnection *conn) {
|
|
|
|
BSONObj status;
|
|
|
|
|
|
|
|
if (!conn->runCommand("admin", BSON("replSetGetStatus" << 1), status) ||
|
|
|
|
!status.hasField("members") ||
|
|
|
|
status["members"].type() != Array) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BSONObjIterator hi(status["members"].Obj());
|
|
|
|
while (hi.more()) {
|
|
|
|
BSONObj member = hi.next().Obj();
|
|
|
|
string host = member["name"].String();
|
|
|
|
|
|
|
|
int m = -1;
|
|
|
|
if ((m = _find(host)) <= 0) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
double state = member["state"].Number();
|
|
|
|
if (member["health"].Number() == 1 && (state == 1 || state == 2)) {
|
|
|
|
scoped_lock lk( _lock );
|
|
|
|
_nodes[m].ok = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
scoped_lock lk( _lock );
|
|
|
|
_nodes[m].ok = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReplicaSetMonitor::_checkHosts( const BSONObj& hostList, bool& changed ) {
|
|
|
|
BSONObjIterator hi(hostList);
|
|
|
|
while ( hi.more() ){
|
|
|
|
string toCheck = hi.next().String();
|
|
|
|
|
|
|
|
if ( _find( toCheck ) >= 0 )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
HostAndPort h( toCheck );
|
|
|
|
DBClientConnection * newConn = new DBClientConnection( true );
|
|
|
|
string temp;
|
|
|
|
newConn->connect( h , temp );
|
|
|
|
{
|
|
|
|
scoped_lock lk( _lock );
|
|
|
|
_nodes.push_back( Node( h , newConn ) );
|
|
|
|
}
|
|
|
|
log() << "updated set (" << _name << ") to: " << getServerAddress() << endl;
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
bool ReplicaSetMonitor::_checkConnection( DBClientConnection * c , string& maybePrimary , bool verbose ) {
|
|
|
|
bool good = false;
|
2010-12-20 07:28:10 +01:00
|
|
|
bool changed = false;
|
2010-12-19 03:38:19 +01:00
|
|
|
try {
|
|
|
|
BSONObj o;
|
|
|
|
c->isMaster(good, &o);
|
|
|
|
|
|
|
|
log( ! verbose ) << "ReplicaSetMonitor::_checkConnection: " << c->toString() << ' ' << o << '\n';
|
|
|
|
|
|
|
|
// add other nodes
|
|
|
|
string maybePrimary;
|
|
|
|
if ( o["hosts"].type() == Array ){
|
|
|
|
if ( o["primary"].type() == String )
|
|
|
|
maybePrimary = o["primary"].String();
|
2010-12-17 20:08:07 +01:00
|
|
|
|
2010-12-29 01:22:37 +01:00
|
|
|
_checkHosts(o["hosts"].Obj(), changed);
|
|
|
|
}
|
|
|
|
if (o.hasField("passives") && o["passives"].type() == Array) {
|
|
|
|
_checkHosts(o["passives"].Obj(), changed);
|
|
|
|
}
|
|
|
|
|
|
|
|
_checkStatus(c);
|
2010-12-19 03:38:19 +01:00
|
|
|
}
|
|
|
|
catch ( std::exception& e ) {
|
|
|
|
log( ! verbose ) << "ReplicaSetMonitor::_checkConnection: caught exception " << c->toString() << ' ' << e.what() << endl;
|
|
|
|
}
|
|
|
|
|
2010-12-20 07:28:10 +01:00
|
|
|
if ( _hook )
|
2010-12-20 18:52:31 +01:00
|
|
|
_hook( this );
|
2010-12-20 07:28:10 +01:00
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
return good;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReplicaSetMonitor::_check() {
|
|
|
|
|
|
|
|
bool triedQuickCheck = false;
|
|
|
|
|
|
|
|
LOG(1) << "_check : " << getServerAddress() << endl;
|
|
|
|
|
|
|
|
for ( int retry = 0; retry < 2; retry++ ) {
|
|
|
|
for ( unsigned i=0; i<_nodes.size(); i++ ){
|
|
|
|
DBClientConnection * c;
|
|
|
|
{
|
|
|
|
scoped_lock lk( _lock );
|
|
|
|
c = _nodes[i].conn;
|
|
|
|
}
|
|
|
|
|
|
|
|
string maybePrimary;
|
|
|
|
if ( _checkConnection( c , maybePrimary , retry ) ){
|
|
|
|
_master = i;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! triedQuickCheck && maybePrimary.size() ){
|
|
|
|
int x = _find( maybePrimary );
|
|
|
|
if ( x >= 0 ){
|
|
|
|
triedQuickCheck = true;
|
|
|
|
string dummy;
|
|
|
|
DBClientConnection * testConn;
|
|
|
|
{
|
|
|
|
scoped_lock lk( _lock );
|
|
|
|
testConn = _nodes[x].conn;
|
|
|
|
}
|
|
|
|
if ( _checkConnection( testConn , dummy , false ) ){
|
|
|
|
_master = x;
|
|
|
|
return;
|
2010-12-17 20:08:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-12-19 03:38:19 +01:00
|
|
|
|
2010-12-17 20:08:07 +01:00
|
|
|
}
|
|
|
|
sleepsecs(1);
|
|
|
|
}
|
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
}
|
|
|
|
|
2010-12-20 07:28:10 +01:00
|
|
|
void ReplicaSetMonitor::check(){
|
|
|
|
// first see if the current master is fine
|
|
|
|
if ( _master >= 0 ){
|
|
|
|
string temp;
|
|
|
|
if ( _checkConnection( _nodes[_master].conn , temp , false ) ){
|
|
|
|
// current master is fine, so we're done
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// we either have no master, or the current is dead
|
|
|
|
_check();
|
|
|
|
}
|
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
int ReplicaSetMonitor::_find( const string& server ) const {
|
|
|
|
scoped_lock lk( _lock );
|
|
|
|
for ( unsigned i=0; i<_nodes.size(); i++ )
|
|
|
|
if ( _nodes[i].addr == server )
|
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-12-19 05:54:29 +01:00
|
|
|
int ReplicaSetMonitor::_find( const HostAndPort& server ) const {
|
|
|
|
scoped_lock lk( _lock );
|
|
|
|
for ( unsigned i=0; i<_nodes.size(); i++ )
|
|
|
|
if ( _nodes[i].addr == server )
|
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
mongo::mutex ReplicaSetMonitor::_setsLock( "ReplicaSetMonitor" );
|
|
|
|
map<string,ReplicaSetMonitorPtr> ReplicaSetMonitor::_sets;
|
2010-12-20 18:52:31 +01:00
|
|
|
ReplicaSetMonitor::ConfigChangeHook ReplicaSetMonitor::_hook;
|
2010-12-19 03:38:19 +01:00
|
|
|
// --------------------------------
|
|
|
|
// ----- DBClientReplicaSet ---------
|
|
|
|
// --------------------------------
|
|
|
|
|
|
|
|
DBClientReplicaSet::DBClientReplicaSet( const string& name , const vector<HostAndPort>& servers )
|
|
|
|
: _monitor( ReplicaSetMonitor::get( name , servers ) ){
|
|
|
|
}
|
|
|
|
|
|
|
|
DBClientReplicaSet::~DBClientReplicaSet(){
|
2010-12-17 20:08:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
DBClientConnection * DBClientReplicaSet::checkMaster() {
|
2010-12-19 03:38:19 +01:00
|
|
|
if ( _master ){
|
2010-12-17 20:08:07 +01:00
|
|
|
// a master is selected. let's just make sure connection didn't die
|
2010-12-19 03:38:19 +01:00
|
|
|
if ( ! _master->isFailed() )
|
|
|
|
return _master.get();
|
|
|
|
_monitor->notifyFailure( _masterHost );
|
2010-12-17 20:08:07 +01:00
|
|
|
}
|
2010-12-19 05:54:29 +01:00
|
|
|
|
|
|
|
HostAndPort h = _monitor->getMaster();
|
|
|
|
if ( h != _masterHost ){
|
|
|
|
_masterHost = h;
|
|
|
|
_master.reset( new DBClientConnection( true ) );
|
|
|
|
_master->connect( _masterHost );
|
|
|
|
_auth( _master.get() );
|
|
|
|
}
|
|
|
|
return _master.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
DBClientConnection * DBClientReplicaSet::checkSlave() {
|
|
|
|
if ( _slave ){
|
|
|
|
if ( ! _slave->isFailed() )
|
|
|
|
return _slave.get();
|
|
|
|
_monitor->notifySlaveFailure( _slaveHost );
|
|
|
|
}
|
|
|
|
|
|
|
|
HostAndPort h = _monitor->getSlave();
|
|
|
|
if ( h != _slaveHost ){
|
|
|
|
_slaveHost = h;
|
|
|
|
_slave.reset( new DBClientConnection( true ) );
|
|
|
|
_slave->connect( _slaveHost );
|
|
|
|
_auth( _slave.get() );
|
|
|
|
}
|
|
|
|
return _slave.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DBClientReplicaSet::_auth( DBClientConnection * conn ){
|
2010-12-19 03:38:19 +01:00
|
|
|
for ( list<AuthInfo>::iterator i=_auths.begin(); i!=_auths.end(); ++i ){
|
|
|
|
const AuthInfo& a = *i;
|
|
|
|
string errmsg;
|
2010-12-19 05:54:29 +01:00
|
|
|
if ( ! conn->auth( a.dbname , a.username , a.pwd , errmsg, a.digestPassword ) )
|
2010-12-20 07:28:10 +01:00
|
|
|
warning() << "cached auth failed for set: " << _monitor->getName() << " db: " << a.dbname << " user: " << a.username << endl;
|
2010-12-17 20:08:07 +01:00
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
}
|
|
|
|
|
2010-12-17 20:08:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
DBClientConnection& DBClientReplicaSet::masterConn(){
|
|
|
|
return *checkMaster();
|
|
|
|
}
|
|
|
|
|
|
|
|
DBClientConnection& DBClientReplicaSet::slaveConn(){
|
2010-12-19 05:54:29 +01:00
|
|
|
return *checkSlave();
|
2010-12-17 20:08:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool DBClientReplicaSet::connect(){
|
|
|
|
try {
|
|
|
|
checkMaster();
|
|
|
|
}
|
|
|
|
catch (AssertionException&) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DBClientReplicaSet::auth(const string &dbname, const string &username, const string &pwd, string& errmsg, bool digestPassword ) {
|
|
|
|
DBClientConnection * m = checkMaster();
|
2010-12-19 03:38:19 +01:00
|
|
|
|
|
|
|
// first make sure it actually works
|
|
|
|
if( ! m->auth(dbname, username, pwd, errmsg, digestPassword ) )
|
2010-12-17 20:08:07 +01:00
|
|
|
return false;
|
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
// now that it does, we should save so that for a new node we can auth
|
|
|
|
_auths.push_back( AuthInfo( dbname , username , pwd , digestPassword ) );
|
2010-12-17 20:08:07 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
// ------------- simple functions -----------------
|
|
|
|
|
|
|
|
void DBClientReplicaSet::insert( const string &ns , BSONObj obj ) {
|
|
|
|
checkMaster()->insert(ns, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBClientReplicaSet::insert( const string &ns, const vector< BSONObj >& v ) {
|
|
|
|
checkMaster()->insert(ns, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBClientReplicaSet::remove( const string &ns , Query obj , bool justOne ) {
|
|
|
|
checkMaster()->remove(ns, obj, justOne);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DBClientReplicaSet::update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi ) {
|
|
|
|
return checkMaster()->update(ns, query, obj, upsert,multi);
|
|
|
|
}
|
|
|
|
|
2010-12-19 06:11:23 +01:00
|
|
|
auto_ptr<DBClientCursor> DBClientReplicaSet::query(const string &ns, Query query, int nToReturn, int nToSkip,
|
|
|
|
const BSONObj *fieldsToReturn, int queryOptions, int batchSize){
|
|
|
|
|
|
|
|
if ( queryOptions & QueryOption_SlaveOk ){
|
|
|
|
// we're ok sending to a slave
|
|
|
|
// we'll try 2 slaves before just using master
|
|
|
|
// checkSlave will try a different slave automatically after a failure
|
|
|
|
for ( int i=0; i<2; i++ ){
|
|
|
|
try {
|
|
|
|
return checkSlave()->query(ns,query,nToReturn,nToSkip,fieldsToReturn,queryOptions,batchSize);
|
|
|
|
}
|
2010-12-19 17:47:39 +01:00
|
|
|
catch ( DBException & ){
|
2010-12-19 06:11:23 +01:00
|
|
|
LOG(1) << "can't query replica set slave: " << _slaveHost << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return checkMaster()->query(ns,query,nToReturn,nToSkip,fieldsToReturn,queryOptions,batchSize);
|
2010-12-17 20:08:07 +01:00
|
|
|
}
|
|
|
|
|
2010-12-19 06:11:23 +01:00
|
|
|
BSONObj DBClientReplicaSet::findOne(const string &ns, const Query& query, const BSONObj *fieldsToReturn, int queryOptions) {
|
|
|
|
if ( queryOptions & QueryOption_SlaveOk ){
|
|
|
|
// we're ok sending to a slave
|
|
|
|
// we'll try 2 slaves before just using master
|
|
|
|
// checkSlave will try a different slave automatically after a failure
|
|
|
|
for ( int i=0; i<2; i++ ){
|
|
|
|
try {
|
|
|
|
return checkSlave()->findOne(ns,query,fieldsToReturn,queryOptions);
|
|
|
|
}
|
2010-12-19 17:47:39 +01:00
|
|
|
catch ( DBException & ){
|
2010-12-19 06:11:23 +01:00
|
|
|
LOG(1) << "can't query replica set slave: " << _slaveHost << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return checkMaster()->findOne(ns,query,fieldsToReturn,queryOptions);
|
2010-12-17 20:08:07 +01:00
|
|
|
}
|
|
|
|
|
2010-12-19 03:38:19 +01:00
|
|
|
void DBClientReplicaSet::killCursor( long long cursorID ){
|
|
|
|
checkMaster()->killCursor( cursorID );
|
|
|
|
}
|
2010-12-17 20:08:07 +01:00
|
|
|
|
|
|
|
|
2010-12-20 08:21:41 +01:00
|
|
|
bool DBClientReplicaSet::call( Message &toSend, Message &response, bool assertOk ) {
|
|
|
|
if ( toSend.operation() == dbQuery ){
|
|
|
|
// TODO: might be possible to do this faster by changing api
|
|
|
|
DbMessage dm( toSend );
|
|
|
|
QueryMessage qm( dm );
|
|
|
|
if ( qm.queryOptions & QueryOption_SlaveOk ){
|
|
|
|
for ( int i=0; i<2; i++ ){
|
|
|
|
try {
|
|
|
|
return checkSlave()->call( toSend , response , assertOk );
|
|
|
|
}
|
|
|
|
catch ( DBException & ){
|
2010-12-20 09:53:15 +01:00
|
|
|
log(1) << "can't query replica set slave: " << _slaveHost << endl;
|
2010-12-20 08:21:41 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-12-20 09:53:15 +01:00
|
|
|
return checkMaster()->call( toSend , response , assertOk );
|
2010-12-20 08:21:41 +01:00
|
|
|
}
|
|
|
|
|
2010-12-17 20:08:07 +01:00
|
|
|
}
|