void SyncClusterConnection::update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi ){ 

        if ( upsert ){
            uassert( 13120 , "SyncClusterConnection::update upsert query needs _id" , query.obj["_id"].type() );
        }

        if ( _writeConcern ){
            string errmsg;
            if ( ! prepare( errmsg ) )
                throw UserException( 8005 , (string)"SyncClusterConnection::udpate prepare failed: " + errmsg );
        }

        for ( size_t i=0; i<_conns.size(); i++ ){
            try {
                _conns[i]->update( ns , query , obj , upsert , multi );
            }
            catch ( std::exception& e ){
                if ( _writeConcern )
                    throw e;
            }
        }
        
        if ( _writeConcern ){
            _checkLast();
        }
    }
    void SyncClusterConnection::insert( const string &ns, const vector< BSONObj >& v , int flags) {
        if (v.size() == 1){
            insert(ns, v[0], flags);
            return;
        }

        for (vector<BSONObj>::const_iterator it = v.begin(); it != v.end(); ++it ) {
            BSONObj obj = *it;
            if ( obj["_id"].type() == EOO ) {
                string assertMsg = "SyncClusterConnection::insert (batched) obj misses an _id: ";
                uasserted( 16743, assertMsg + obj.jsonString() );
            }
        }

        // fsync all connections before starting the batch.
        string errmsg;
        if ( ! prepare( errmsg ) ) {
            string assertMsg = "SyncClusterConnection::insert (batched) prepare failed: ";
            throw UserException( 16744, assertMsg + errmsg );
        }

        // We still want one getlasterror per document, even if they're batched.
        for ( size_t i=0; i<_conns.size(); i++ ) {
            for ( vector<BSONObj>::const_iterator it = v.begin(); it != v.end(); ++it ) {
                _conns[i]->insert( ns, *it, flags );
                _conns[i]->getLastErrorDetailed();
            }
        }

        // We issue a final getlasterror, but this time with an fsync.
        _checkLast();
    }
    BSONObj SyncClusterConnection::findOne(const string &ns, Query query, const BSONObj *fieldsToReturn, int queryOptions) {
        
        if ( ns.find( ".$cmd" ) != string::npos ){
            string cmdName = query.obj.firstElement().fieldName();

            int lockType = _lockType( cmdName );

            if ( lockType > 0 ){ // write $cmd
                string errmsg;
                if ( ! prepare( errmsg ) )
                    throw UserException( 13104 , (string)"SyncClusterConnection::insert prepare failed: " + errmsg );
                
                vector<BSONObj> all;
                for ( size_t i=0; i<_conns.size(); i++ ){
                    all.push_back( _conns[i]->findOne( ns , query , 0 , queryOptions ).getOwned() );
                }
                
                _checkLast();
                
                for ( size_t i=0; i<all.size(); i++ ){
                    BSONObj temp = all[i];
                    if ( isOk( temp ) )
                        continue;
                    stringstream ss;
                    ss << "write $cmd failed on a shard: " << temp.jsonString();
                    ss << " " << _conns[i]->toString();
                    throw UserException( 13105 , ss.str() );
                }
                
                return all[0];
            }
        }

        return DBClientBase::findOne( ns , query , fieldsToReturn , queryOptions );
    }
    void SyncClusterConnection::remove( const string &ns , Query query, int flags ) {
        string errmsg;
        if ( ! prepare( errmsg ) )
            throw UserException( 8020 , (string)"SyncClusterConnection::remove prepare failed: " + errmsg );

        for ( size_t i=0; i<_conns.size(); i++ ) {
            _conns[i]->remove( ns , query , flags );
        }

        _checkLast();
    }
void SyncClusterConnection::say( Message &toSend ) {
    string errmsg;
    if ( ! prepare( errmsg ) )
        throw UserException( 13397 , (string)"SyncClusterConnection::say prepare failed: " + errmsg );

    for ( size_t i=0; i<_conns.size(); i++ ) {
        _conns[i]->say( toSend );
    }

    _checkLast();
}
    void SyncClusterConnection::say( Message &toSend, bool isRetry , string * actualServer ) {
        string errmsg;
        if ( ! prepare( errmsg ) )
            throw UserException( 13397 , (string)"SyncClusterConnection::say prepare failed: " + errmsg );

        for ( size_t i=0; i<_conns.size(); i++ ) {
            _conns[i]->say( toSend );
        }

        // TODO: should we set actualServer??

        _checkLast();
    }
    void SyncClusterConnection::insert( const string &ns, BSONObj obj ){ 

        uassert( 13119 , (string)"SyncClusterConnection::insert obj has to have an _id: " + obj.jsonString() , 
                 ns.find( ".system.indexes" ) != string::npos || obj["_id"].type() );
        
        string errmsg;
        if ( ! prepare( errmsg ) )
            throw UserException( 8003 , (string)"SyncClusterConnection::insert prepare failed: " + errmsg );

        for ( size_t i=0; i<_conns.size(); i++ ){
            _conns[i]->insert( ns , obj );
        }
        
        _checkLast();
    }
    void SyncClusterConnection::insert( const string &ns, BSONObj obj , int flags) {

        uassert(13119,
                (string)"SyncClusterConnection::insert obj has to have an _id: " + obj.jsonString(),
                 NamespaceString(ns).coll == "system.indexes" || obj["_id"].type());

        string errmsg;
        if ( ! prepare( errmsg ) )
            throw UserException( 8003 , (string)"SyncClusterConnection::insert prepare failed: " + errmsg );

        for ( size_t i=0; i<_conns.size(); i++ ) {
            _conns[i]->insert( ns , obj , flags);
        }

        _checkLast();
    }
    void SyncClusterConnection::update( const string &ns , Query query , BSONObj obj , int flags ) {

        if ( flags & UpdateOption_Upsert ) {
            uassert( 13120 , "SyncClusterConnection::update upsert query needs _id" , query.obj["_id"].type() );
        }

        if ( _writeConcern ) {
            string errmsg;
            if ( ! prepare( errmsg ) )
                throw UserException( 8005 , (string)"SyncClusterConnection::udpate prepare failed: " + errmsg );
        }

        for ( size_t i = 0; i < _conns.size(); i++ ) {
            try {
                _conns[i]->update( ns , query , obj , flags );
            }
            catch ( std::exception& e ) {
                if ( _writeConcern )
                    throw e;
            }
        }

        if ( _writeConcern ) {
            _checkLast();
            verify( _lastErrors.size() > 1 );

            int a = _lastErrors[0]["n"].numberInt();
            for ( unsigned i=1; i<_lastErrors.size(); i++ ) {
                int b = _lastErrors[i]["n"].numberInt();
                if ( a == b )
                    continue;

                throw UpdateNotTheSame( 8017 , 
                                        str::stream() 
                                        << "update not consistent " 
                                        << " ns: " << ns
                                        << " query: " << query.toString()
                                        << " update: " << obj
                                        << " gle1: " << _lastErrors[0]
                                        << " gle2: " << _lastErrors[i] ,
                                        _connAddresses , _lastErrors );
            }
        }
    }
void SyncClusterConnection::update( const string &ns , Query query , BSONObj obj , bool upsert , bool multi ) {

    if ( upsert ) {
        uassert( 13120 , "SyncClusterConnection::update upsert query needs _id" , query.obj["_id"].type() );
    }

    if ( _writeConcern ) {
        string errmsg;
        if ( ! prepare( errmsg ) )
            throw UserException( 8005 , (string)"SyncClusterConnection::udpate prepare failed: " + errmsg );
    }

    for ( size_t i=0; i<_conns.size(); i++ ) {
        try {
            _conns[i]->update( ns , query , obj , upsert , multi );
        }
        catch ( std::exception& e ) {
            if ( _writeConcern )
                throw e;
        }
    }

    if ( _writeConcern ) {
        _checkLast();
        assert( _lastErrors.size() > 1 );

        int a = _lastErrors[0]["n"].numberInt();
        for ( unsigned i=1; i<_lastErrors.size(); i++ ) {
            int b = _lastErrors[i]["n"].numberInt();
            if ( a == b )
                continue;

            throw UpdateNotTheSame( 8017 , "update not consistent" , _connAddresses , _lastErrors );
        }
    }
}