Beispiel #1
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 #2
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 #3
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;
}