/** @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; }
// @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; }
/** @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; }