Beispiel #1
0
    void ReplSet::haveNewConfig(ReplSetConfig& newConfig, bool addComment) {
        bo comment;
        if( addComment )
            comment = BSON( "msg" << "Reconfig set" << "version" << newConfig.version );

        newConfig.saveConfigLocally(comment);

        try {
            BSONObj oldConfForAudit = config().asBson();
            BSONObj newConfForAudit = newConfig.asBson();
            audit::logReplSetReconfig(ClientBasic::getCurrent(),
                                      &oldConfForAudit,
                                      &newConfForAudit);
            if (initFromConfig(newConfig, true)) {
                log() << "replSet replSetReconfig new config saved locally" << rsLog;
            }
        }
        catch(DBException& e) {
            log() << "replSet error unexpected exception in haveNewConfig() : " << e.toString() << rsLog;
            _fatal();
        }
        catch(...) {
            log() << "replSet error unexpected exception in haveNewConfig()" << rsLog;
            _fatal();
        }
    }
StatusWith<int> validateConfigForInitiate(ReplicationCoordinatorExternalState* externalState,
                                          const ReplSetConfig& newConfig,
                                          ServiceContext* ctx) {
    Status status = newConfig.validate();
    if (!status.isOK()) {
        return StatusWith<int>(status);
    }

    status = newConfig.checkIfWriteConcernCanBeSatisfied(newConfig.getDefaultWriteConcern());
    if (!status.isOK()) {
        return status.withContext(
            "Found invalid default write concern in 'getLastErrorDefaults' field");
    }

    status = validateArbiterPriorities(newConfig);
    if (!status.isOK()) {
        return StatusWith<int>(status);
    }

    if (newConfig.getConfigVersion() != 1) {
        return StatusWith<int>(ErrorCodes::NewReplicaSetConfigurationIncompatible,
                               str::stream() << "Configuration used to initiate a replica set must "
                                             << " have version 1, but found "
                                             << newConfig.getConfigVersion());
    }
    return findSelfInConfigIfElectable(externalState, newConfig, ctx);
}
Beispiel #3
0
    // Our own config must be the first one.
    bool ReplSetImpl::_loadConfigFinish(OperationContext* txn, vector<ReplSetConfig*>& cfgs) {
        int v = -1;
        ReplSetConfig *highest = 0;
        int myVersion = -2000;
        int n = 0;
        for (vector<ReplSetConfig*>::iterator i = cfgs.begin(); i != cfgs.end(); i++) {
            ReplSetConfig* cfg = *i;
            DEV { LOG(1) << n+1 << " config shows version " << cfg->version << rsLog; }
            if (++n == 1) myVersion = cfg->version;
            if (cfg->ok() && cfg->version > v) {
                highest = cfg;
                v = cfg->version;
            }
        }
        verify(highest);

        if (!initFromConfig(txn, *highest))
            return false;

        if (highest->version > myVersion && highest->version >= 0) {
            log() << "replSet got config version " << highest->version
                  << " from a remote, saving locally" << rsLog;
            highest->saveConfigLocally(txn, BSONObj());
        }
        return true;
    }
StatusWith<int> validateConfigForReconfig(ReplicationCoordinatorExternalState* externalState,
                                          const ReplSetConfig& oldConfig,
                                          const ReplSetConfig& newConfig,
                                          ServiceContext* ctx,
                                          bool force) {
    Status status = newConfig.validate();
    if (!status.isOK()) {
        return StatusWith<int>(status);
    }

    status = newConfig.checkIfWriteConcernCanBeSatisfied(newConfig.getDefaultWriteConcern());
    if (!status.isOK()) {
        return status.withContext(
            "Found invalid default write concern in 'getLastErrorDefaults' field");
    }

    status = validateOldAndNewConfigsCompatible(oldConfig, newConfig);
    if (!status.isOK()) {
        return StatusWith<int>(status);
    }

    status = validateArbiterPriorities(newConfig);
    if (!status.isOK()) {
        return StatusWith<int>(status);
    }

    if (force) {
        return findSelfInConfig(externalState, newConfig, ctx);
    }

    return findSelfInConfigIfElectable(externalState, newConfig, ctx);
}
Beispiel #5
0
    void ReplSet::haveNewConfig(OperationContext* txn, ReplSetConfig& newConfig, bool addComment) {
        bo comment;
        if( addComment )
            comment = BSON( "msg" << "Reconfig set" << "version" << newConfig.version );

        newConfig.saveConfigLocally(txn, comment);

        try {
            BSONObj oldConfForAudit = config().asBson();
            BSONObj newConfForAudit = newConfig.asBson();
            audit::logReplSetReconfig(ClientBasic::getCurrent(),
                                      &oldConfForAudit,
                                      &newConfForAudit);
            if (initFromConfig(txn, newConfig, true)) {
                log() << "replSet replSetReconfig new config saved locally" << rsLog;
            }
        }
        catch (const DBException& e) {
            log() << "replSet error unexpected exception in haveNewConfig() : " << e.toString() << rsLog;
            fassertFailedNoTrace(18755);
        }
        catch (...) {
            std::terminate();
        }
    }
Beispiel #6
0
OplogFetcher::OplogFetcher(executor::TaskExecutor* executor,
                           OpTimeWithHash lastFetched,
                           HostAndPort source,
                           NamespaceString nss,
                           ReplSetConfig config,
                           std::size_t maxFetcherRestarts,
                           int requiredRBID,
                           bool requireFresherSyncSource,
                           DataReplicatorExternalState* dataReplicatorExternalState,
                           EnqueueDocumentsFn enqueueDocumentsFn,
                           OnShutdownCallbackFn onShutdownCallbackFn,
                           const int batchSize)
    : AbstractOplogFetcher(executor,
                           lastFetched,
                           source,
                           nss,
                           maxFetcherRestarts,
                           onShutdownCallbackFn,
                           "oplog fetcher"),
      _metadataObject(makeMetadataObject(config.getProtocolVersion() == 1LL)),
      _requiredRBID(requiredRBID),
      _requireFresherSyncSource(requireFresherSyncSource),
      _dataReplicatorExternalState(dataReplicatorExternalState),
      _enqueueDocumentsFn(enqueueDocumentsFn),
      _awaitDataTimeout(calculateAwaitDataTimeout(config)),
      _batchSize(batchSize) {

    invariant(config.isInitialized());
    invariant(enqueueDocumentsFn);
}
Beispiel #7
0
Datei: rs.cpp Projekt: sivy/mongo
    // Our own config must be the first one.
    bool ReplSetImpl::_loadConfigFinish(vector<ReplSetConfig>& cfgs) { 
        int v = -1;
        ReplSetConfig *highest = 0;
        int myVersion = -2000;
        int n = 0;
        for( vector<ReplSetConfig>::iterator i = cfgs.begin(); i != cfgs.end(); i++ ) { 
            ReplSetConfig& cfg = *i;
            if( ++n == 1 ) myVersion = cfg.version;
            if( cfg.ok() && cfg.version > v ) { 
                highest = &cfg;
                v = cfg.version;
            }
        }
        assert( highest );

        if( !initFromConfig(*highest) ) 
            return false;

        if( highest->version > myVersion && highest->version >= 0 ) { 
            log() << "replSet got config version " << highest->version << " from a remote, saving locally" << rsLog;
            writelock lk("admin.");
            highest->saveConfigLocally(BSONObj());
        }
        return true;
    }
Status checkQuorumForReconfig(executor::TaskExecutor* executor,
                              const ReplSetConfig& rsConfig,
                              const int myIndex,
                              long long term) {
    invariant(rsConfig.getConfigVersion() > 1);
    return checkQuorumGeneral(executor, rsConfig, myIndex, term, "reconfig quorum check");
}
Beispiel #9
0
void ReplSet::haveNewConfig(ReplSetConfig& newConfig, bool addComment) {
    bo comment;
    if( addComment )
        comment = BSON( "msg" << "Reconfig set" << "version" << newConfig.version );

    newConfig.saveConfigLocally(comment);

    try {
        if (initFromConfig(newConfig, true)) {
            log() << "replSet replSetReconfig new config saved locally" << rsLog;
        }
    }
    catch(DBException& e) {
        if( e.getCode() == 13497 /* removed from set */ ) {
            cc().shutdown();
            dbexit( EXIT_CLEAN , "removed from replica set" ); // never returns
            assert(0);
        }
        log() << "replSet error unexpected exception in haveNewConfig() : " << e.toString() << rsLog;
        _fatal();
    }
    catch(...) {
        log() << "replSet error unexpected exception in haveNewConfig()" << rsLog;
        _fatal();
    }
}
Status checkQuorumForInitiate(executor::TaskExecutor* executor,
                              const ReplSetConfig& rsConfig,
                              const int myIndex,
                              long long term) {
    invariant(rsConfig.getConfigVersion() == 1);
    return checkQuorumGeneral(executor, rsConfig, myIndex, term);
}
StatusWith<int> validateConfigForStartUp(ReplicationCoordinatorExternalState* externalState,
                                         const ReplSetConfig& newConfig,
                                         ServiceContext* ctx) {
    Status status = newConfig.validate();
    if (!status.isOK()) {
        return StatusWith<int>(status);
    }
    return findSelfInConfig(externalState, newConfig, ctx);
}
Beispiel #12
0
 void ReplSet::haveNewConfig(ReplSetConfig& newConfig, bool addComment) { 
     lock l(this); // convention is to lock replset before taking the db rwlock
     writelock lk("");
     bo comment;
     if( addComment )
         comment = BSON( "msg" << "Reconfig set" << "version" << newConfig.version );
     newConfig.saveConfigLocally(comment);
     try { 
         initFromConfig(newConfig, true);
         log() << "replSet replSetReconfig new config saved locally" << rsLog;
     }
     catch(DBException& e) { 
         log() << "replSet error unexpected exception in haveNewConfig() : " << e.toString() << rsLog;
         _fatal();
     }
     catch(...) { 
         log() << "replSet error unexpected exception in haveNewConfig()" << rsLog;
         _fatal();
     }
 }
Beispiel #13
0
    void ReplSet::haveNewConfig(ReplSetConfig& newConfig, bool addComment) {
        bo comment;
        if( addComment )
            comment = BSON( "msg" << "Reconfig set" << "version" << newConfig.version );

        newConfig.saveConfigLocally(comment);

        try {
            if (initFromConfig(newConfig, true)) {
                log() << "replSet replSetReconfig new config saved locally" << rsLog;
            }
        }
        catch(DBException& e) {
            log() << "replSet error unexpected exception in haveNewConfig() : " << e.toString() << rsLog;
            _fatal();
        }
        catch(...) {
            log() << "replSet error unexpected exception in haveNewConfig()" << rsLog;
            _fatal();
        }
    }
Beispiel #14
0
    // @param reconf true if this is a reconfiguration and not an initial load of the configuration.
    // @return true if ok; throws if config really bad; false if config doesn't include self
    bool ReplSetImpl::initFromConfig(OperationContext* txn, ReplSetConfig& c, bool reconf) {
        // NOTE: haveNewConfig() writes the new config to disk before we get here.  So
        //       we cannot error out at this point, except fatally.  Check errors earlier.
        lock lk(this);

        if (!getLastErrorDefault.isEmpty() || !c.getLastErrorDefaults.isEmpty()) {
            getLastErrorDefault = c.getLastErrorDefaults;
        }

        list<ReplSetConfig::MemberCfg*> newOnes;
        // additive short-cuts the new config setup. If we are just adding a
        // node/nodes and nothing else is changing, this is additive. If it's
        // not a reconfig, we're not adding anything
        bool additive = reconf;
        bool updateConfigs = false;
        {
            unsigned nfound = 0;
            int me = 0;
            for (vector<ReplSetConfig::MemberCfg>::iterator i = c.members.begin();
                    i != c.members.end();
                    i++) {
                
                ReplSetConfig::MemberCfg& m = *i;
                if (isSelf(m.h)) {
                    me++;
                }
                
                if (reconf) {
                    const Member *old = findById(m._id);
                    if (old) {
                        nfound++;
                        verify((int) old->id() == m._id);
                        if (!old->config().isSameIgnoringTags(m)) {
                            additive = false;
                        }
                        if (!updateConfigs && old->config() != m) {
                            updateConfigs = true;
                        }
                    }
                    else {
                        newOnes.push_back(&m);
                    }
                }
            }
            if (me == 0) { // we're not in the config -- we must have been removed
                if (state().removed()) {
                    // already took note of our ejection from the set
                    // so just sit tight and poll again
                    return false;
                }

                _members.orphanAll();

                // kill off rsHealthPoll threads (because they Know Too Much about our past)
                endOldHealthTasks();

                // clear sync target to avoid faulty sync attempts; we must do this before we
                // close sockets, since that will trigger the bgsync thread to reconnect.
                BackgroundSync::get()->clearSyncTarget();

                // close sockets to force clients to re-evaluate this member
                MessagingPort::closeAllSockets(0);

                // take note of our ejection
                changeState(MemberState::RS_REMOVED);

                // go into holding pattern
                log() << "replSet info self not present in the repl set configuration:" << rsLog;
                log() << c.toString() << rsLog;

                loadConfig(txn);  // redo config from scratch
                return false; 
            }
            uassert(13302, "replSet error self appears twice in the repl set configuration", me<=1);

            if (state().removed()) {
                // If we were removed and have now been added back in, switch state.
                changeState(MemberState::RS_RECOVERING);
            }

            // if we found different members that the original config, reload everything
            if (reconf && config().members.size() != nfound)
                additive = false;
        }

        // If we are changing chaining rules, we don't want this to be an additive reconfig so that
        // the primary can step down and the sync targets change.
        // TODO: This can be removed once SERVER-5208 is fixed.
        if (reconf && config().chainingAllowed() != c.chainingAllowed()) {
            additive = false;
        }

        _cfg = new ReplSetConfig(c);

        // config() is same thing but const, so we use that when we can for clarity below
        dassert(&config() == _cfg);
        verify(config().ok());
        verify(_name.empty() || _name == config()._id);
        _name = config()._id;
        verify(!_name.empty());

        // this is a shortcut for simple changes
        if (additive) {
            log() << "replSet info : additive change to configuration" << rsLog;
            if (updateConfigs) {
                // we have new configs for existing members, so we need to repopulate _members
                // with the most recent configs
                _members.orphanAll();

                // for logging
                string members = "";

                // not setting _self to 0 as other threads use _self w/o locking
                int me = 0;
                for(vector<ReplSetConfig::MemberCfg>::const_iterator i = config().members.begin();
                    i != config().members.end(); i++) {
                    const ReplSetConfig::MemberCfg& m = *i;
                    Member *mi;
                    members += (members == "" ? "" : ", ") + m.h.toString();
                    if (isSelf(m.h)) {
                        verify(me++ == 0);
                        mi = new Member(m.h, m._id, &m, true);
                        setSelfTo(mi);
                    }
                    else {
                        mi = new Member(m.h, m._id, &m, false);
                        _members.push(mi);
                    }
                }
                // trigger a handshake to update the syncSource of our writeconcern information
                syncSourceFeedback.forwardSlaveHandshake();
            }

            // add any new members
            for (list<ReplSetConfig::MemberCfg*>::const_iterator i = newOnes.begin();
                    i != newOnes.end();
                    i++) {
                ReplSetConfig::MemberCfg *m = *i;
                Member *mi = new Member(m->h, m->_id, m, false);

                // we will indicate that new members are up() initially so that we don't relinquish
                // our primary state because we can't (transiently) see a majority. they should be
                // up as we check that new members are up before getting here on reconfig anyway.
                mi->get_hbinfo().health = 0.1;

                _members.push(mi);
                startHealthTaskFor(mi);
            }

            // if we aren't creating new members, we may have to update the
            // groups for the current ones
            _cfg->updateMembers(_members);

            return true;
        }

        // start with no members.  if this is a reconfig, drop the old ones.
        _members.orphanAll();

        endOldHealthTasks();
        
        int oldPrimaryId = -1;
        {
            const Member *p = box.getPrimary();
            if (p)
                oldPrimaryId = p->id();
        }
        forgetPrimary(txn);

        // not setting _self to 0 as other threads use _self w/o locking
        int me = 0;

        // For logging
        string members = "";

        for (vector<ReplSetConfig::MemberCfg>::const_iterator i = config().members.begin();
                i != config().members.end();
                i++) {
            const ReplSetConfig::MemberCfg& m = *i;
            Member *mi;
            members += (members == "" ? "" : ", ") + m.h.toString();
            if (isSelf(m.h)) {
                verify(me++ == 0);
                mi = new Member(m.h, m._id, &m, true);
                if (!reconf) {
                    log() << "replSet I am " << m.h.toString() << rsLog;
                }
                setSelfTo(mi);

                if ((int)mi->id() == oldPrimaryId)
                    box.setSelfPrimary(mi);
            }
            else {
                mi = new Member(m.h, m._id, &m, false);
                _members.push(mi);
                if ((int)mi->id() == oldPrimaryId)
                    box.setOtherPrimary(mi);
            }
        }

        if (me == 0){
            log() << "replSet warning did not detect own host in full reconfig, members "
                  << members << " config: " << c << rsLog;
        }
        else {
            // Do this after we've found ourselves, since _self needs
            // to be set before we can start the heartbeat tasks
            for (Member *mb = _members.head(); mb; mb=mb->next()) {
                startHealthTaskFor(mb);
            }
        }
        return true;
    }
Beispiel #15
0
Datei: rs.cpp Projekt: sivy/mongo
    /** @param reconf true if this is a reconfiguration and not an initial load of the configuration.
        @return true if ok; throws if config really bad; false if config doesn't include self
    */
    bool ReplSetImpl::initFromConfig(ReplSetConfig& c, bool reconf) {
        /* NOTE: haveNewConfig() writes the new config to disk before we get here.  So 
                 we cannot error out at this point, except fatally.  Check errors earlier.
                 */
        lock lk(this);

        if( getLastErrorDefault || !c.getLastErrorDefaults.isEmpty() ) {
            // see comment in dbcommands.cpp for getlasterrordefault
            getLastErrorDefault = new BSONObj( c.getLastErrorDefaults );
        }

        list<const ReplSetConfig::MemberCfg*> newOnes;
        bool additive = reconf;
        {
            unsigned nfound = 0;
            int me = 0;
            for( vector<ReplSetConfig::MemberCfg>::iterator i = c.members.begin(); i != c.members.end(); i++ ) { 
                const ReplSetConfig::MemberCfg& m = *i;
                if( m.h.isSelf() ) {
                    nfound++;
                    me++;
                    if( !reconf || (_self && _self->id() == (unsigned) m._id) )
                        ;
                    else { 
                        log() << "replSet " << _self->id() << ' ' << m._id << rsLog;
                        assert(false);
                    }
                }
                else if( reconf ) { 
                    const Member *old = findById(m._id);
                    if( old ) { 
                        nfound++;
                        assert( (int) old->id() == m._id );
                        if( old->config() == m ) { 
                            additive = false;
                        }
                    }
                    else {
                        newOnes.push_back(&m);
                    }
                }
            }
            if( me == 0 ) {
                // log() << "replSet config : " << _cfg->toString() << rsLog;
                log() << "replSet error self not present in the repl set configuration:" << rsLog;
                log() << c.toString() << rsLog;
                uasserted(13497, "replSet error self not present in the configuration");
            }
            uassert( 13302, "replSet error self appears twice in the repl set configuration", me<=1 );

            if( reconf && config().members.size() != nfound ) 
                additive = false;
        }

        _cfg = new ReplSetConfig(c);
        assert( _cfg->ok() );
        assert( _name.empty() || _name == _cfg->_id );
        _name = _cfg->_id;
        assert( !_name.empty() );

        if( additive ) { 
            log() << "replSet info : additive change to configuration" << rsLog;
            for( list<const ReplSetConfig::MemberCfg*>::const_iterator i = newOnes.begin(); i != newOnes.end(); i++ ) {
                const ReplSetConfig::MemberCfg* m = *i;
                Member *mi = new Member(m->h, m->_id, m, false);

                /** we will indicate that new members are up() initially so that we don't relinquish our 
                    primary state because we can't (transiently) see a majority.  they should be up as we 
                    check that new members are up before getting here on reconfig anyway.
                    */
                mi->get_hbinfo().health = 0.1;

                _members.push(mi);
                startHealthTaskFor(mi);
            }
            return true;
        }

        // start with no members.  if this is a reconfig, drop the old ones.
        _members.orphanAll();

        endOldHealthTasks();

        int oldPrimaryId = -1;
        {
            const Member *p = box.getPrimary();
            if( p ) 
                oldPrimaryId = p->id();
        }
        forgetPrimary();
        setSelfTo(0);
        for( vector<ReplSetConfig::MemberCfg>::iterator i = _cfg->members.begin(); i != _cfg->members.end(); i++ ) { 
            const ReplSetConfig::MemberCfg& m = *i;
            Member *mi;
            if( m.h.isSelf() ) {
                assert( _self == 0 );
                mi = new Member(m.h, m._id, &m, true);
                setSelfTo(mi);
                if( (int)mi->id() == oldPrimaryId )
                    box.setSelfPrimary(mi);
            } else {
                mi = new Member(m.h, m._id, &m, false);
                _members.push(mi);
                startHealthTaskFor(mi);
                if( (int)mi->id() == oldPrimaryId )
                    box.setOtherPrimary(mi);
            }
        }
        return true;
    }
Beispiel #16
0
/** @param reconf true if this is a reconfiguration and not an initial load of the configuration.
    @return true if ok; throws if config really bad; false if config doesn't include self
*/
bool ReplSetImpl::initFromConfig(ReplSetConfig& c, bool reconf) {
    /* NOTE: haveNewConfig() writes the new config to disk before we get here.  So
             we cannot error out at this point, except fatally.  Check errors earlier.
             */
    lock lk(this);

    if( getLastErrorDefault || !c.getLastErrorDefaults.isEmpty() ) {
        // see comment in dbcommands.cpp for getlasterrordefault
        getLastErrorDefault = new BSONObj( c.getLastErrorDefaults );
    }

    list<const ReplSetConfig::MemberCfg*> newOnes;
    // additive short-cuts the new config setup. If we are just adding a
    // node/nodes and nothing else is changing, this is additive. If it's
    // not a reconfig, we're not adding anything
    bool additive = reconf;
    {
        unsigned nfound = 0;
        int me = 0;
        for( vector<ReplSetConfig::MemberCfg>::iterator i = c.members.begin(); i != c.members.end(); i++ ) {
            const ReplSetConfig::MemberCfg& m = *i;

            if( m.h.isSelf() ) {
                me++;
            }

            if( reconf ) {
                if (m.h.isSelf() && (!_self || (int)_self->id() != m._id)) {
                    log() << "self doesn't match: " << m._id << rsLog;
                    assert(false);
                }

                const Member *old = findById(m._id);
                if( old ) {
                    nfound++;
                    assert( (int) old->id() == m._id );
                    if( old->config() != m ) {
                        additive = false;
                    }
                }
                else {
                    newOnes.push_back(&m);
                }
            }
        }
        if( me == 0 ) {
            _members.orphanAll();
            // hbs must continue to pick up new config
            // stop sync thread
            box.set(MemberState::RS_STARTUP, 0);

            // go into holding pattern
            log() << "replSet error self not present in the repl set configuration:" << rsLog;
            log() << c.toString() << rsLog;
            return false;
        }
        uassert( 13302, "replSet error self appears twice in the repl set configuration", me<=1 );

        // if we found different members that the original config, reload everything
        if( reconf && config().members.size() != nfound )
            additive = false;
    }

    _cfg = new ReplSetConfig(c);
    assert( _cfg->ok() );
    assert( _name.empty() || _name == _cfg->_id );
    _name = _cfg->_id;
    assert( !_name.empty() );

    // this is a shortcut for simple changes
    if( additive ) {
        log() << "replSet info : additive change to configuration" << rsLog;
        for( list<const ReplSetConfig::MemberCfg*>::const_iterator i = newOnes.begin(); i != newOnes.end(); i++ ) {
            const ReplSetConfig::MemberCfg* m = *i;
            Member *mi = new Member(m->h, m->_id, m, false);

            /** we will indicate that new members are up() initially so that we don't relinquish our
                primary state because we can't (transiently) see a majority.  they should be up as we
                check that new members are up before getting here on reconfig anyway.
                */
            mi->get_hbinfo().health = 0.1;

            _members.push(mi);
            startHealthTaskFor(mi);
        }
        return true;
    }

    // start with no members.  if this is a reconfig, drop the old ones.
    _members.orphanAll();

    endOldHealthTasks();

    int oldPrimaryId = -1;
    {
        const Member *p = box.getPrimary();
        if( p )
            oldPrimaryId = p->id();
    }
    forgetPrimary();

    // not setting _self to 0 as other threads use _self w/o locking
    int me = 0;

    // For logging
    string members = "";

    for( vector<ReplSetConfig::MemberCfg>::iterator i = _cfg->members.begin(); i != _cfg->members.end(); i++ ) {
        const ReplSetConfig::MemberCfg& m = *i;
        Member *mi;
        members += ( members == "" ? "" : ", " ) + m.h.toString();
        if( m.h.isSelf() ) {
            assert( me++ == 0 );
            mi = new Member(m.h, m._id, &m, true);
            setSelfTo(mi);

            if( (int)mi->id() == oldPrimaryId )
                box.setSelfPrimary(mi);
        }
        else {
            mi = new Member(m.h, m._id, &m, false);
            _members.push(mi);
            startHealthTaskFor(mi);
            if( (int)mi->id() == oldPrimaryId )
                box.setOtherPrimary(mi);
        }
    }

    if( me == 0 ) {
        log() << "replSet warning did not detect own host in full reconfig, members " << members << " config: " << c << rsLog;
    }

    return true;
}