Files
mongo/db/repl/rs_config.cpp

246 lines
9.0 KiB
C++
Raw Normal View History

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-04-22 18:43:37 -04:00
#include "replset.h"
2010-04-20 21:55:34 -04:00
#include "../../client/dbclient.h"
#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-04-20 16:24:06 -04:00
2010-04-24 19:56:42 -04:00
using namespace bson;
2010-04-20 16:24:06 -04:00
namespace mongo {
2010-04-28 08:25:56 -04:00
void ReplSetConfig::save() {
check();
2010-05-13 17:18:17 -04:00
log() << "replSet info saving a newer config version to local.system.replset" << rsLog;
MemoryMappedFile::flushAll(true);
{
writelock lk("admin.");
BSONObj o = asBson();
Helpers::putSingletonGod(rsConfigNs.c_str(), o, false/*logOp=false; local db so would work regardless...*/);
MemoryMappedFile::flushAll(true);
}
2010-04-28 08:25:56 -04:00
}
2010-05-05 14:57:49 -04: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;
return b.obj();
}
2010-04-24 19:56:42 -04:00
bo ReplSetConfig::asBson() const {
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() )
settings << "heartbeatConnRetries " << ho.heartbeatConnRetries <<
"heartbeatSleep" << ho.heartbeatSleepMillis / 1000 <<
"heartbeatTimeout" << ho.heartbeatTimeoutMillis / 1000;
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();
}
static inline void mchk(bool expr) {
uassert(13126, "bad Member config", expr);
}
2010-05-05 14:57:49 -04:00
void ReplSetConfig::MemberCfg::check() const{
2010-04-25 16:13:21 -04:00
mchk(_id >= 0 && _id <= 255);
mchk(priority >= 0 && priority <= 1000);
mchk(votes >= 0 && votes <= 100);
}
void ReplSetConfig::clear() {
version = -5;
_ok = false;
}
2010-04-27 14:37:41 -04:00
void ReplSetConfig::check() const {
uassert(13132,
2010-04-27 18:55:45 -04:00
"nonmatching repl set name in _id field; check --replSet command line",
2010-04-27 14:37:41 -04:00
startsWith(cmdLine.replSet, _id + '/'));
uassert(13133,
"replSet config value is not valid",
members.size() >= 1 && members.size() <= 64 &&
version > 0);
}
2010-04-21 16:14:28 -04:00
void ReplSetConfig::from(BSONObj o) {
2010-04-21 16:43:51 -04:00
md5 = o.md5();
2010-04-21 15:26:08 -04:00
_id = o["_id"].String();
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-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();
2010-04-27 14:22:46 -04:00
try { getLastErrorDefaults = settings["getLastErrorDefaults"].Obj(); } 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-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 {
2010-04-27 18:55:45 -04:00
try {
m._id = (int) mobj["_id"].Number();
} catch(...) { throw "_id must be numeric"; }
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
}
catch(...) { throw "bad or missing host field?"; }
2010-04-21 16:14:28 -04:00
m.arbiterOnly = mobj.getBoolField("arbiterOnly");
try { m.priority = mobj["priority"].Number(); } catch(...) { }
try { m.votes = (unsigned) mobj["votes"].Number(); } catch(...) { }
m.check();
2010-04-21 14:41:09 -04:00
}
2010-04-27 18:55:45 -04: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);
}
2010-04-27 14:22:46 -04: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;
ss << "replSet members[" << i << "] bad config object";
2010-04-27 18:55:45 -04:00
uassert(13135, ss.str(), false);
2010-04-21 14:41:09 -04:00
}
2010-05-09 15:16:14 -04:00
uassert(13108, "bad " + rsConfigNs + " config dups?", ords.count(m._id) == 0 && hosts.count(m.h.toString()) == 0);
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-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-05-09 15:16:14 -04:00
uassert(13122, "bad " + rsConfigNs + " config", expr);
2010-04-21 16:43:51 -04:00
}
2010-04-23 17:35:05 -04:00
ReplSetConfig::ReplSetConfig(BSONObj cfg) {
clear();
2010-04-23 17:35:05 -04:00
from(cfg);
configAssert( version < 0 /*unspecified*/ || 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) {
clear();
2010-04-21 17:40:24 -04:00
int level = 2;
DEV level = 0;
2010-05-11 15:58:44 -04:00
//log(0) << "replSet load config from: " << h.toString() << rsLog;
2010-04-21 17:40:24 -04:00
auto_ptr<DBClientCursor> c;
2010-05-13 17:18:17 -04:00
int v = -5;
2010-04-21 17:40:24 -04:00
try {
2010-05-13 11:03:23 -04:00
if( h.isSelf() ) {
;
}
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-05-09 17:29:35 -04:00
size_t sl = cmdLine.replSet.find('/');
assert( sl != string::npos );
string setname = cmdLine.replSet.substr(0, sl);
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-05-13 11:03:23 -04:00
bool ok = requestHeartbeat(setname, h.toString(), info, -2, theirVersion);
2010-05-13 17:18:17 -04:00
if( info["rs"].trueValue() ) {
// 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;
if( !info.isEmpty() ) log() << "replSet TEMP response was: " << info.toString() << rsLog;
return;
}
{
stringstream ss;
ss << "replSet error: member " << h.toString() << " is not in --replSet mode";
cout << "TEMP " << info.toString() << endl;
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-05-13 11:03:23 -04:00
ScopedConn conn(h.toString());
2010-05-13 17:18:17 -04:00
v = -3;
2010-05-09 17:29:35 -04:00
c = conn->query(rsConfigNs);
2010-05-13 17:18:17 -04:00
if( c.get() == 0 ) {
version = v; return;
}
2010-04-22 16:17:18 -04:00
if( !c->more() ) {
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
}
2010-05-10 21:26:32 -04:00
catch( DBException& e) {
2010-05-13 17:18:17 -04:00
version = v;
2010-05-11 15:58:44 -04:00
log(level) << "replSet load config couldn't load " << h.toString() << ' ' << e.what() << rsLog;
2010-04-21 17:40:24 -04:00
return;
}
2010-04-21 17:13:25 -04:00
2010-04-21 16:14:28 -04:00
BSONObj o = c->nextSafe();
2010-05-09 15:16:14 -04:00
uassert(13109, "multiple rows in " + rsConfigNs + " not supported", !c->more());
2010-04-21 16:14:28 -04:00
from(o);
2010-04-21 17:40:24 -04:00
_ok = true;
2010-05-11 15:58:44 -04:00
log(level) << "replSet load config ok " << 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
}