2010-04-20 19:07:37 -04:00
|
|
|
// rs_config.cpp
|
|
|
|
|
|
2010-04-20 16:24:06 -04:00
|
|
|
/**
|
|
|
|
|
* Copyright (C) 2008 10gen Inc.
|
|
|
|
|
*
|
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU Affero General Public License, version 3,
|
|
|
|
|
* as published by the Free Software Foundation.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
|
2010-04-27 15:27:52 -04:00
|
|
|
#include "pch.h"
|
2010-05-29 15:45:47 -04:00
|
|
|
#include "rs.h"
|
2010-04-20 21:55:34 -04:00
|
|
|
#include "../../client/dbclient.h"
|
2010-05-14 14:01:51 -04:00
|
|
|
#include "../../client/syncclusterconnection.h"
|
2010-04-20 21:55:34 -04:00
|
|
|
#include "../../util/hostandport.h"
|
2010-04-28 09:54:01 -04:00
|
|
|
#include "../dbhelpers.h"
|
2010-05-09 17:29:35 -04:00
|
|
|
#include "connections.h"
|
2010-06-04 15:54:25 -04:00
|
|
|
#include "../oplog.h"
|
2010-04-20 16:24:06 -04:00
|
|
|
|
2010-04-24 19:56:42 -04:00
|
|
|
using namespace bson;
|
|
|
|
|
|
2011-01-04 00:40:41 -05:00
|
|
|
namespace mongo {
|
2010-04-20 16:24:06 -04:00
|
|
|
|
2010-06-29 18:27:09 -04:00
|
|
|
void logOpInitiate(const bo&);
|
|
|
|
|
|
2011-01-04 00:40:41 -05:00
|
|
|
void assertOnlyHas(BSONObj o, const set<string>& fields) {
|
2010-08-26 13:33:26 -04:00
|
|
|
BSONObj::iterator i(o);
|
|
|
|
|
while( i.more() ) {
|
|
|
|
|
BSONElement e = i.next();
|
|
|
|
|
if( !fields.count( e.fieldName() ) ) {
|
|
|
|
|
uasserted(13434, str::stream() << "unexpected field '" << e.fieldName() << "'in object");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-04 00:40:41 -05:00
|
|
|
list<HostAndPort> ReplSetConfig::otherMemberHostnames() const {
|
2010-05-14 16:32:24 -04:00
|
|
|
list<HostAndPort> L;
|
|
|
|
|
for( vector<MemberCfg>::const_iterator i = members.begin(); i != members.end(); i++ ) {
|
2010-09-13 15:09:55 -04:00
|
|
|
if( !i->h.isSelf() )
|
2010-05-14 16:32:24 -04:00
|
|
|
L.push_back(i->h);
|
|
|
|
|
}
|
|
|
|
|
return L;
|
|
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2010-06-29 18:27:09 -04:00
|
|
|
/* comment MUST only be set when initiating the set by the initiator */
|
2011-01-04 00:40:41 -05:00
|
|
|
void ReplSetConfig::saveConfigLocally(bo comment) {
|
2010-08-26 13:47:27 -04:00
|
|
|
checkRsConfig();
|
2010-05-13 17:18:17 -04:00
|
|
|
log() << "replSet info saving a newer config version to local.system.replset" << rsLog;
|
2011-01-04 00:40:41 -05:00
|
|
|
{
|
2010-06-04 15:54:25 -04:00
|
|
|
writelock lk("");
|
2010-07-26 17:28:24 -04:00
|
|
|
Client::Context cx( rsConfigNs );
|
|
|
|
|
cx.db()->flushFiles(true);
|
|
|
|
|
|
2010-06-26 21:31:17 -04:00
|
|
|
//theReplSet->lastOpTimeWritten = ??;
|
|
|
|
|
//rather than above, do a logOp()? probably
|
2010-05-13 17:18:17 -04:00
|
|
|
BSONObj o = asBson();
|
|
|
|
|
Helpers::putSingletonGod(rsConfigNs.c_str(), o, false/*logOp=false; local db so would work regardless...*/);
|
2010-06-29 18:27:09 -04:00
|
|
|
if( !comment.isEmpty() )
|
|
|
|
|
logOpInitiate(comment);
|
2010-07-26 17:28:24 -04:00
|
|
|
|
|
|
|
|
cx.db()->flushFiles(true);
|
2010-05-13 17:18:17 -04:00
|
|
|
}
|
2011-04-26 07:38:31 -07:00
|
|
|
log() << "replSet saveConfigLocally done" << rsLog;
|
2010-04-28 08:25:56 -04:00
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
|
|
|
|
|
bo ReplSetConfig::MemberCfg::asBson() const {
|
2010-04-27 14:22:46 -04:00
|
|
|
bob b;
|
|
|
|
|
b << "_id" << _id;
|
|
|
|
|
b.append("host", h.toString());
|
|
|
|
|
if( votes != 1 ) b << "votes" << votes;
|
|
|
|
|
if( priority != 1.0 ) b << "priority" << priority;
|
|
|
|
|
if( arbiterOnly ) b << "arbiterOnly" << true;
|
2010-08-18 14:29:04 -04:00
|
|
|
if( slaveDelay ) b << "slaveDelay" << slaveDelay;
|
2010-08-18 11:37:17 -04:00
|
|
|
if( hidden ) b << "hidden" << hidden;
|
2010-09-28 14:01:54 -04:00
|
|
|
if( !buildIndexes ) b << "buildIndexes" << buildIndexes;
|
2011-01-04 00:40:41 -05:00
|
|
|
if( !tags.empty() ) {
|
2010-11-02 12:12:29 -04:00
|
|
|
BSONArrayBuilder a;
|
2010-11-02 14:46:58 -04:00
|
|
|
for( set<string>::const_iterator i = tags.begin(); i != tags.end(); i++ )
|
2010-11-02 12:12:29 -04:00
|
|
|
a.append(*i);
|
|
|
|
|
b.appendArray("tags", a.done());
|
|
|
|
|
}
|
2010-04-27 14:22:46 -04:00
|
|
|
return b.obj();
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-04 00:40:41 -05:00
|
|
|
bo ReplSetConfig::asBson() const {
|
2010-04-24 19:56:42 -04:00
|
|
|
bob b;
|
|
|
|
|
b.append("_id", _id).append("version", version);
|
2010-04-27 14:22:46 -04:00
|
|
|
if( !ho.isDefault() || !getLastErrorDefaults.isEmpty() ) {
|
|
|
|
|
bob settings;
|
|
|
|
|
if( !ho.isDefault() )
|
2011-01-04 00:40:41 -05:00
|
|
|
settings << "heartbeatConnRetries " << ho.heartbeatConnRetries <<
|
|
|
|
|
"heartbeatSleep" << ho.heartbeatSleepMillis / 1000.0 <<
|
|
|
|
|
"heartbeatTimeout" << ho.heartbeatTimeoutMillis / 1000.0;
|
2010-04-27 14:22:46 -04:00
|
|
|
if( !getLastErrorDefaults.isEmpty() )
|
|
|
|
|
settings << "getLastErrorDefaults" << getLastErrorDefaults;
|
|
|
|
|
b << "settings" << settings.obj();
|
2010-04-24 19:56:42 -04:00
|
|
|
}
|
2010-04-27 14:22:46 -04:00
|
|
|
|
|
|
|
|
BSONArrayBuilder a;
|
|
|
|
|
for( unsigned i = 0; i < members.size(); i++ )
|
|
|
|
|
a.append( members[i].asBson() );
|
|
|
|
|
b.append("members", a.arr());
|
|
|
|
|
|
2010-04-24 19:56:42 -04:00
|
|
|
return b.obj();
|
2010-04-23 18:48:20 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void mchk(bool expr) {
|
|
|
|
|
uassert(13126, "bad Member config", expr);
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-04 00:40:41 -05:00
|
|
|
void ReplSetConfig::MemberCfg::check() const {
|
2010-04-25 16:13:21 -04:00
|
|
|
mchk(_id >= 0 && _id <= 255);
|
2010-04-23 18:48:20 -04:00
|
|
|
mchk(priority >= 0 && priority <= 1000);
|
2011-03-11 13:51:45 -05:00
|
|
|
mchk(votes <= 100); // votes >= 0 because it is unsigned
|
2011-04-12 13:56:32 -04:00
|
|
|
uassert(13419, "priorities must be between 0.0 and 100.0", priority >= 0.0 && priority <= 100.0);
|
2010-08-17 23:35:53 -04:00
|
|
|
uassert(13437, "slaveDelay requires priority be zero", slaveDelay == 0 || priority == 0);
|
|
|
|
|
uassert(13438, "bad slaveDelay value", slaveDelay >= 0 && slaveDelay <= 3600 * 24 * 366);
|
2010-08-18 12:07:21 -04:00
|
|
|
uassert(13439, "priority must be 0 when hidden=true", priority == 0 || !hidden);
|
2010-11-11 15:37:36 -05:00
|
|
|
uassert(13477, "priority must be 0 when buildIndexes=false", buildIndexes || priority == 0);
|
2010-04-23 18:48:20 -04:00
|
|
|
}
|
|
|
|
|
|
2010-08-08 10:21:39 -04:00
|
|
|
/** @param o old config
|
2011-01-04 00:40:41 -05:00
|
|
|
@param n new config
|
2010-08-08 10:21:39 -04:00
|
|
|
*/
|
2011-01-04 00:40:41 -05:00
|
|
|
/*static*/
|
|
|
|
|
bool ReplSetConfig::legalChange(const ReplSetConfig& o, const ReplSetConfig& n, string& errmsg) {
|
2010-08-08 10:21:39 -04:00
|
|
|
assert( theReplSet );
|
|
|
|
|
|
2011-01-04 00:40:41 -05:00
|
|
|
if( o._id != n._id ) {
|
|
|
|
|
errmsg = "set name may not change";
|
2010-07-08 14:41:49 -04:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
/* TODO : wonder if we need to allow o.version < n.version only, which is more lenient.
|
2011-01-04 00:40:41 -05:00
|
|
|
if someone had some intermediate config this node doesnt have, that could be
|
2010-07-08 14:41:49 -04:00
|
|
|
necessary. but then how did we become primary? so perhaps we are fine as-is.
|
|
|
|
|
*/
|
2011-01-04 00:40:41 -05:00
|
|
|
if( o.version + 1 != n.version ) {
|
2010-07-08 14:41:49 -04:00
|
|
|
errmsg = "version number wrong";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-08 10:21:39 -04:00
|
|
|
map<HostAndPort,const ReplSetConfig::MemberCfg*> old;
|
2011-02-28 12:57:43 -05:00
|
|
|
bool isLocalHost = false;
|
2011-01-04 00:40:41 -05:00
|
|
|
for( vector<ReplSetConfig::MemberCfg>::const_iterator i = o.members.begin(); i != o.members.end(); i++ ) {
|
2011-02-28 12:57:43 -05:00
|
|
|
if (i->h.isLocalHost()) {
|
|
|
|
|
isLocalHost = true;
|
|
|
|
|
}
|
2010-08-08 10:21:39 -04:00
|
|
|
old[i->h] = &(*i);
|
|
|
|
|
}
|
|
|
|
|
int me = 0;
|
2011-01-04 00:40:41 -05:00
|
|
|
for( vector<ReplSetConfig::MemberCfg>::const_iterator i = n.members.begin(); i != n.members.end(); i++ ) {
|
2010-08-08 10:21:39 -04:00
|
|
|
const ReplSetConfig::MemberCfg& m = *i;
|
2011-05-06 10:43:39 -04:00
|
|
|
if ( (isLocalHost && !m.h.isLocalHost()) || (!isLocalHost && m.h.isLocalHost())) {
|
|
|
|
|
log() << "reconfig error, cannot switch between localhost and hostnames: "
|
|
|
|
|
<< m.h.toString() << rsLog;
|
|
|
|
|
uasserted(13645, "hosts cannot switch between localhost and hostname");
|
2011-02-28 12:57:43 -05:00
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
if( old.count(m.h) ) {
|
2010-09-28 14:01:54 -04:00
|
|
|
const ReplSetConfig::MemberCfg& oldCfg = *old[m.h];
|
2011-01-04 00:40:41 -05:00
|
|
|
if( oldCfg._id != m._id ) {
|
2010-08-08 10:21:39 -04:00
|
|
|
log() << "replSet reconfig error with member: " << m.h.toString() << rsLog;
|
|
|
|
|
uasserted(13432, "_id may not change for members");
|
|
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
if( oldCfg.buildIndexes != m.buildIndexes ) {
|
2010-09-28 14:01:54 -04:00
|
|
|
log() << "replSet reconfig error with member: " << m.h.toString() << rsLog;
|
|
|
|
|
uasserted(13476, "buildIndexes may not change for members");
|
|
|
|
|
}
|
2010-10-31 11:45:06 -04:00
|
|
|
/* are transitions to and from arbiterOnly guaranteed safe? if not, we should disallow here.
|
2010-10-31 12:11:38 -04:00
|
|
|
there is a test at replsets/replsetarb3.js */
|
2011-01-04 00:40:41 -05:00
|
|
|
if( oldCfg.arbiterOnly != m.arbiterOnly ) {
|
2010-10-30 14:56:56 -04:00
|
|
|
log() << "replSet reconfig error with member: " << m.h.toString() << " arbiterOnly cannot change. remove and readd the member instead " << rsLog;
|
|
|
|
|
uasserted(13510, "arbiterOnly may not change for members");
|
|
|
|
|
}
|
2010-10-30 14:57:49 -04:00
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
if( m.h.isSelf() )
|
2010-08-08 10:21:39 -04:00
|
|
|
me++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uassert(13433, "can't find self in new replset config", me == 1);
|
|
|
|
|
|
2010-07-08 14:41:49 -04:00
|
|
|
/* TODO : MORE CHECKS HERE */
|
|
|
|
|
|
2010-11-12 16:09:14 -05:00
|
|
|
DEV log() << "replSet TODO : don't allow removal of a node until we handle it at the removed node end?" << endl;
|
2010-07-09 11:20:26 -04:00
|
|
|
// we could change its votes to zero perhaps instead as a short term...
|
|
|
|
|
|
2010-07-08 14:41:49 -04:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-04 00:40:41 -05:00
|
|
|
void ReplSetConfig::clear() {
|
2010-04-23 18:48:20 -04:00
|
|
|
version = -5;
|
|
|
|
|
_ok = false;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-04 00:40:41 -05:00
|
|
|
void ReplSetConfig::checkRsConfig() const {
|
2010-04-27 14:37:41 -04:00
|
|
|
uassert(13132,
|
2011-01-04 00:40:41 -05:00
|
|
|
"nonmatching repl set name in _id field; check --replSet command line",
|
|
|
|
|
_id == cmdLine.ourSetName());
|
2010-06-24 13:42:26 -04:00
|
|
|
uassert(13308, "replSet bad config version #", version > 0);
|
|
|
|
|
uassert(13133, "replSet bad config no members", members.size() >= 1);
|
2010-12-22 17:48:54 -05:00
|
|
|
uassert(13309, "replSet bad config maximum number of members is 12", members.size() <= 12);
|
|
|
|
|
{
|
|
|
|
|
unsigned voters = 0;
|
2011-01-04 00:40:41 -05:00
|
|
|
for( vector<MemberCfg>::const_iterator i = members.begin(); i != members.end(); ++i ) {
|
2010-12-22 17:48:54 -05:00
|
|
|
if( i->votes )
|
|
|
|
|
voters++;
|
|
|
|
|
}
|
|
|
|
|
uassert(13612, "replSet bad config maximum number of voting members is 7", voters <= 7);
|
|
|
|
|
uassert(13613, "replSet bad config no voting members", voters > 0);
|
|
|
|
|
}
|
2010-04-27 14:37:41 -04:00
|
|
|
}
|
|
|
|
|
|
2010-04-21 16:14:28 -04:00
|
|
|
void ReplSetConfig::from(BSONObj o) {
|
2010-08-12 13:13:25 -04:00
|
|
|
static const string legal[] = {"_id","version", "members","settings"};
|
|
|
|
|
static const set<string> legals(legal, legal + 4);
|
|
|
|
|
assertOnlyHas(o, legals);
|
|
|
|
|
|
2010-04-21 16:43:51 -04:00
|
|
|
md5 = o.md5();
|
2010-04-21 15:26:08 -04:00
|
|
|
_id = o["_id"].String();
|
2010-04-23 18:48:20 -04:00
|
|
|
if( o["version"].ok() ) {
|
|
|
|
|
version = o["version"].numberInt();
|
2010-05-09 15:16:14 -04:00
|
|
|
uassert(13115, "bad " + rsConfigNs + " config: version", version > 0);
|
2010-04-23 18:48:20 -04:00
|
|
|
}
|
2010-04-21 14:41:09 -04:00
|
|
|
|
2010-04-21 16:14:28 -04:00
|
|
|
if( o["settings"].ok() ) {
|
|
|
|
|
BSONObj settings = o["settings"].Obj();
|
2010-04-25 16:13:21 -04:00
|
|
|
if( settings["heartbeatConnRetries "].ok() )
|
|
|
|
|
ho.heartbeatConnRetries = settings["heartbeatConnRetries "].numberInt();
|
2010-04-21 16:14:28 -04:00
|
|
|
if( settings["heartbeatSleep"].ok() )
|
2010-04-25 16:13:21 -04:00
|
|
|
ho.heartbeatSleepMillis = (unsigned) (settings["heartbeatSleep"].Number() * 1000);
|
2010-04-21 16:14:28 -04:00
|
|
|
if( settings["heartbeatTimeout"].ok() )
|
2010-04-25 16:13:21 -04:00
|
|
|
ho.heartbeatTimeoutMillis = (unsigned) (settings["heartbeatTimeout"].Number() * 1000);
|
|
|
|
|
ho.check();
|
2011-01-04 00:40:41 -05:00
|
|
|
try { getLastErrorDefaults = settings["getLastErrorDefaults"].Obj().copy(); }
|
|
|
|
|
catch(...) { }
|
2010-04-21 14:41:09 -04:00
|
|
|
}
|
|
|
|
|
|
2010-04-21 16:14:28 -04:00
|
|
|
set<string> hosts;
|
2010-04-25 16:13:21 -04:00
|
|
|
set<int> ords;
|
2010-04-27 14:22:46 -04:00
|
|
|
vector<BSONElement> members;
|
|
|
|
|
try {
|
|
|
|
|
members = o["members"].Array();
|
|
|
|
|
}
|
|
|
|
|
catch(...) {
|
2010-04-27 18:55:45 -04:00
|
|
|
uasserted(13131, "replSet error parsing (or missing) 'members' field in config object");
|
2010-04-27 14:22:46 -04:00
|
|
|
}
|
2010-07-26 09:55:10 -04:00
|
|
|
|
2010-07-26 17:28:24 -04:00
|
|
|
unsigned localhosts = 0;
|
2010-04-21 16:14:28 -04:00
|
|
|
for( unsigned i = 0; i < members.size(); i++ ) {
|
|
|
|
|
BSONObj mobj = members[i].Obj();
|
2010-05-05 14:57:49 -04:00
|
|
|
MemberCfg m;
|
2010-04-21 14:41:09 -04:00
|
|
|
try {
|
2011-01-04 00:40:41 -05:00
|
|
|
static const string legal[] = {
|
|
|
|
|
"_id","votes","priority","host", "hidden","slaveDelay",
|
2011-04-06 12:48:19 -04:00
|
|
|
"arbiterOnly","buildIndexes","tags","initialSync" // deprecated
|
2011-01-04 00:40:41 -05:00
|
|
|
};
|
2010-11-17 18:30:24 -05:00
|
|
|
static const set<string> legals(legal, legal + 10);
|
2010-08-26 13:33:26 -04:00
|
|
|
assertOnlyHas(mobj, legals);
|
|
|
|
|
|
2011-01-04 00:40:41 -05:00
|
|
|
try {
|
2010-04-27 18:55:45 -04:00
|
|
|
m._id = (int) mobj["_id"].Number();
|
2011-01-04 00:40:41 -05:00
|
|
|
}
|
|
|
|
|
catch(...) {
|
2010-07-20 16:46:32 -04:00
|
|
|
/* TODO: use of string exceptions may be problematic for reconfig case! */
|
2011-01-04 00:40:41 -05:00
|
|
|
throw "_id must be numeric";
|
2010-07-20 16:46:32 -04:00
|
|
|
}
|
2010-04-27 18:55:45 -04:00
|
|
|
string s;
|
|
|
|
|
try {
|
|
|
|
|
s = mobj["host"].String();
|
2010-05-14 13:07:24 -04:00
|
|
|
m.h = HostAndPort(s);
|
2010-04-27 18:55:45 -04:00
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
catch(...) {
|
2010-07-22 14:20:13 -04:00
|
|
|
throw string("bad or missing host field? ") + mobj.toString();
|
2010-07-20 16:46:32 -04:00
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
if( m.h.isLocalHost() )
|
2010-07-26 09:55:10 -04:00
|
|
|
localhosts++;
|
2011-03-17 12:16:46 -04:00
|
|
|
m.arbiterOnly = mobj["arbiterOnly"].trueValue();
|
2010-08-17 23:35:53 -04:00
|
|
|
m.slaveDelay = mobj["slaveDelay"].numberInt();
|
2010-08-18 11:37:17 -04:00
|
|
|
if( mobj.hasElement("hidden") )
|
2011-03-17 12:16:46 -04:00
|
|
|
m.hidden = mobj["hidden"].trueValue();
|
2011-01-04 00:40:41 -05:00
|
|
|
if( mobj.hasElement("buildIndexes") )
|
2011-03-17 12:16:46 -04:00
|
|
|
m.buildIndexes = mobj["buildIndexes"].trueValue();
|
2010-06-29 13:17:57 -04:00
|
|
|
if( mobj.hasElement("priority") )
|
|
|
|
|
m.priority = mobj["priority"].Number();
|
|
|
|
|
if( mobj.hasElement("votes") )
|
|
|
|
|
m.votes = (unsigned) mobj["votes"].Number();
|
2010-11-02 12:12:29 -04:00
|
|
|
if( mobj.hasElement("tags") ) {
|
|
|
|
|
vector<BSONElement> v = mobj["tags"].Array();
|
|
|
|
|
for( unsigned i = 0; i < v.size(); i++ )
|
|
|
|
|
m.tags.insert( v[i].String() );
|
|
|
|
|
}
|
2010-04-23 18:48:20 -04:00
|
|
|
m.check();
|
2010-04-21 14:41:09 -04:00
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
catch( const char * p ) {
|
2010-05-07 16:42:55 -04:00
|
|
|
log() << "replSet cfg parsing exception for members[" << i << "] " << p << rsLog;
|
2010-04-27 18:55:45 -04:00
|
|
|
stringstream ss;
|
|
|
|
|
ss << "replSet members[" << i << "] " << p;
|
|
|
|
|
uassert(13107, ss.str(), false);
|
|
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
catch(DBException& e) {
|
2010-05-07 16:42:55 -04:00
|
|
|
log() << "replSet cfg parsing exception for members[" << i << "] " << e.what() << rsLog;
|
2010-04-27 14:22:46 -04:00
|
|
|
stringstream ss;
|
2010-08-04 10:50:53 -04:00
|
|
|
ss << "bad config for member[" << i << "] " << e.what();
|
2010-04-27 18:55:45 -04:00
|
|
|
uassert(13135, ss.str(), false);
|
2010-04-21 14:41:09 -04:00
|
|
|
}
|
2010-07-30 15:41:54 -04:00
|
|
|
if( !(ords.count(m._id) == 0 && hosts.count(m.h.toString()) == 0) ) {
|
|
|
|
|
log() << "replSet " << o.toString() << rsLog;
|
|
|
|
|
uassert(13108, "bad replset config -- duplicate hosts in the config object?", false);
|
|
|
|
|
}
|
2010-04-21 14:41:09 -04:00
|
|
|
hosts.insert(m.h.toString());
|
2010-04-25 16:13:21 -04:00
|
|
|
ords.insert(m._id);
|
2010-04-27 14:22:46 -04:00
|
|
|
this->members.push_back(m);
|
2010-04-21 14:41:09 -04:00
|
|
|
}
|
2010-07-26 09:55:10 -04:00
|
|
|
uassert(13393, "can't use localhost in repl set member names except when using it for all members", localhosts == 0 || localhosts == members.size());
|
2010-05-09 15:16:14 -04:00
|
|
|
uassert(13117, "bad " + rsConfigNs + " config", !_id.empty());
|
2010-04-20 21:55:34 -04:00
|
|
|
}
|
2010-04-20 16:24:06 -04:00
|
|
|
|
2010-04-21 16:43:51 -04:00
|
|
|
static inline void configAssert(bool expr) {
|
2010-07-08 14:41:49 -04:00
|
|
|
uassert(13122, "bad repl set config?", expr);
|
2010-04-21 16:43:51 -04:00
|
|
|
}
|
|
|
|
|
|
2011-01-04 00:40:41 -05:00
|
|
|
ReplSetConfig::ReplSetConfig(BSONObj cfg) {
|
2010-04-23 18:48:20 -04:00
|
|
|
clear();
|
2010-04-23 17:35:05 -04:00
|
|
|
from(cfg);
|
2010-07-08 14:41:49 -04:00
|
|
|
configAssert( version < 0 /*unspecified*/ || (version >= 1 && version <= 5000) );
|
|
|
|
|
if( version < 1 )
|
|
|
|
|
version = 1;
|
2010-04-23 17:35:05 -04:00
|
|
|
_ok = true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-22 18:43:37 -04:00
|
|
|
ReplSetConfig::ReplSetConfig(const HostAndPort& h) {
|
2010-04-23 18:48:20 -04:00
|
|
|
clear();
|
2010-04-21 17:40:24 -04:00
|
|
|
int level = 2;
|
|
|
|
|
DEV level = 0;
|
|
|
|
|
|
2010-10-28 10:38:24 -04:00
|
|
|
BSONObj cfg;
|
2010-05-13 17:18:17 -04:00
|
|
|
int v = -5;
|
2010-04-21 17:40:24 -04:00
|
|
|
try {
|
2010-09-13 15:09:55 -04:00
|
|
|
if( h.isSelf() ) {
|
2010-05-13 11:03:23 -04:00
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2010-04-22 18:43:37 -04:00
|
|
|
/* first, make sure other node is configured to be a replset. just to be safe. */
|
2010-08-02 15:21:26 -04:00
|
|
|
string setname = cmdLine.ourSetName();
|
2010-05-09 17:29:35 -04:00
|
|
|
BSONObj cmd = BSON( "replSetHeartbeat" << setname );
|
2010-05-13 11:03:23 -04:00
|
|
|
int theirVersion;
|
2010-04-22 18:43:37 -04:00
|
|
|
BSONObj info;
|
2010-12-06 17:12:40 -05:00
|
|
|
log() << "trying to contact " << h.toString() << rsLog;
|
2010-07-26 21:06:37 -04:00
|
|
|
bool ok = requestHeartbeat(setname, "", h.toString(), info, -2, theirVersion);
|
2011-01-04 00:40:41 -05:00
|
|
|
if( info["rs"].trueValue() ) {
|
2010-05-13 17:18:17 -04:00
|
|
|
// yes, it is a replicate set, although perhaps not yet initialized
|
2010-05-13 11:03:23 -04:00
|
|
|
}
|
2010-05-13 17:18:17 -04:00
|
|
|
else {
|
|
|
|
|
if( !ok ) {
|
|
|
|
|
log() << "replSet TEMP !ok heartbeating " << h.toString() << " on cfg load" << rsLog;
|
2011-01-04 00:40:41 -05:00
|
|
|
if( !info.isEmpty() )
|
2010-07-12 08:19:03 -04:00
|
|
|
log() << "replSet info " << h.toString() << " : " << info.toString() << rsLog;
|
2010-05-13 17:18:17 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
{
|
2010-05-13 17:18:17 -04:00
|
|
|
stringstream ss;
|
|
|
|
|
ss << "replSet error: member " << h.toString() << " is not in --replSet mode";
|
|
|
|
|
msgassertedNoTrace(13260, ss.str().c_str()); // not caught as not a user exception - we want it not caught
|
|
|
|
|
//for python err# checker: uassert(13260, "", false);
|
|
|
|
|
}
|
2010-04-22 18:43:37 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-13 17:18:17 -04:00
|
|
|
v = -4;
|
2010-10-28 10:50:39 -04:00
|
|
|
unsigned long long count = 0;
|
2010-09-28 12:54:00 -04:00
|
|
|
try {
|
|
|
|
|
ScopedConn conn(h.toString());
|
|
|
|
|
v = -3;
|
2010-10-28 10:50:39 -04:00
|
|
|
cfg = conn.findOne(rsConfigNs, Query()).getOwned();
|
|
|
|
|
count = conn.count(rsConfigNs);
|
2010-09-28 12:54:00 -04:00
|
|
|
}
|
2010-09-28 14:02:27 -04:00
|
|
|
catch ( DBException& ) {
|
2010-09-28 12:54:00 -04:00
|
|
|
if ( !h.isSelf() ) {
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// on startup, socket is not listening yet
|
|
|
|
|
DBDirectClient cli;
|
2010-10-28 10:38:24 -04:00
|
|
|
cfg = cli.findOne( rsConfigNs, Query() ).getOwned();
|
|
|
|
|
count = cli.count(rsConfigNs);
|
2010-09-28 12:54:00 -04:00
|
|
|
}
|
2010-10-28 10:38:24 -04:00
|
|
|
|
|
|
|
|
if( count > 1 )
|
|
|
|
|
uasserted(13109, str::stream() << "multiple rows in " << rsConfigNs << " not supported host: " << h.toString());
|
2011-01-04 00:40:41 -05:00
|
|
|
|
2010-10-28 10:38:24 -04:00
|
|
|
if( cfg.isEmpty() ) {
|
2010-05-13 17:18:17 -04:00
|
|
|
version = EMPTYCONFIG;
|
2010-04-21 17:40:24 -04:00
|
|
|
return;
|
2010-04-22 16:17:18 -04:00
|
|
|
}
|
|
|
|
|
version = -1;
|
2010-04-21 17:40:24 -04:00
|
|
|
}
|
2011-01-04 00:40:41 -05:00
|
|
|
catch( DBException& e) {
|
2010-05-13 17:18:17 -04:00
|
|
|
version = v;
|
2010-06-26 20:29:39 -04:00
|
|
|
log(level) << "replSet load config couldn't get from " << h.toString() << ' ' << e.what() << rsLog;
|
2010-04-21 17:40:24 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2010-04-21 17:13:25 -04:00
|
|
|
|
2010-10-28 10:38:24 -04:00
|
|
|
from(cfg);
|
2010-08-26 13:47:27 -04:00
|
|
|
checkRsConfig();
|
2010-04-21 17:40:24 -04:00
|
|
|
_ok = true;
|
2010-09-13 15:09:55 -04:00
|
|
|
log(level) << "replSet load config ok from " << (h.isSelf() ? "self" : h.toString()) << rsLog;
|
2010-04-21 16:14:28 -04:00
|
|
|
}
|
2010-04-20 21:55:34 -04:00
|
|
|
|
2010-04-21 16:14:28 -04:00
|
|
|
}
|