145 lines
4.8 KiB
C++
145 lines
4.8 KiB
C++
/**
|
|
* 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,b
|
|
* 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/>.
|
|
*/
|
|
|
|
#include "pch.h"
|
|
#include "replset.h"
|
|
#include "health.h"
|
|
#include "../../util/background.h"
|
|
#include "../../client/dbclient.h"
|
|
#include "../commands.h"
|
|
#include "../../util/concurrency/value.h"
|
|
|
|
namespace mongo {
|
|
|
|
/* { replSetHeartbeat : <setname> } */
|
|
class CmdReplSetHeartbeat : public Command {
|
|
public:
|
|
virtual bool slaveOk() const { return true; }
|
|
virtual bool adminOnly() const { return false; }
|
|
virtual bool logTheOp() { return false; }
|
|
virtual LockType locktype() const { return NONE; }
|
|
virtual void help( stringstream &help ) const { help<<"internal"; }
|
|
CmdReplSetHeartbeat() : Command("replSetHeartbeat") { }
|
|
virtual bool run(const char *ns, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
|
|
if( !replSet ) {
|
|
errmsg = "not a replset member";
|
|
return false;
|
|
}
|
|
result.append("rs", true);
|
|
if( theReplSet == 0 ) {
|
|
errmsg = "still initializing";
|
|
return false;
|
|
}
|
|
if( theReplSet->getName() != cmdObj.getStringField("replSetHeartbeat") ) {
|
|
errmsg = "repl set names do not match";
|
|
return false;
|
|
}
|
|
//result.append("set", theReplSet->getName());
|
|
return true;
|
|
}
|
|
} cmdReplSetHeartbeat;
|
|
|
|
/* poll every other set member to check its status */
|
|
class FeedbackThread : public BackgroundJob {
|
|
public:
|
|
ReplSet::MemberInfo *m;
|
|
|
|
private:
|
|
void down() {
|
|
m->_health = 0.0;
|
|
if( m->_upSince ) {
|
|
m->_upSince = 0;
|
|
log() << "replSet " << m->fullName() << " is now down" << endl;
|
|
}
|
|
}
|
|
|
|
public:
|
|
void run() {
|
|
mongo::lastError.reset( new LastError() );
|
|
DBClientConnection conn(true, 0, 10);
|
|
conn._logLevel = 2;
|
|
string err;
|
|
conn.connect(m->fullName(), err);
|
|
|
|
BSONObj cmd = BSON( "replSetHeartbeat" << theReplSet->getName() );
|
|
while( 1 ) {
|
|
try {
|
|
BSONObj info;
|
|
bool ok = conn.runCommand("admin", cmd, info);
|
|
m->_lastHeartbeat = time(0);
|
|
if( ok ) {
|
|
if( m->_upSince == 0 ) {
|
|
log() << "replSet " << m->fullName() << " is now up" << endl;
|
|
m->_upSince = m->_lastHeartbeat;
|
|
}
|
|
m->_health = 1.0;
|
|
m->_lastHeartbeatErrMsg.set("");
|
|
}
|
|
else {
|
|
down();
|
|
m->_lastHeartbeatErrMsg.set(info.getStringField("errmsg"));
|
|
}
|
|
}
|
|
catch(...) {
|
|
down();
|
|
m->_lastHeartbeatErrMsg.set("connect/transport error");
|
|
}
|
|
sleepsecs(2);
|
|
}
|
|
}
|
|
};
|
|
|
|
void ReplSet::summarizeStatus(BSONObjBuilder& b) const {
|
|
MemberInfo *m =_members.head();
|
|
vector<BSONObj> v;
|
|
|
|
// add self
|
|
{
|
|
HostAndPort h(getHostName(), cmdLine.port);
|
|
v.push_back( BSON( "name" << h.toString() << "self" << true ) );
|
|
}
|
|
|
|
while( m ) {
|
|
BSONObjBuilder bb;
|
|
bb.append("name", m->fullName());
|
|
bb.append("health", m->health());
|
|
bb.append("uptime", (unsigned) (m->upSince() ? (time(0)-m->upSince()) : 0));
|
|
bb.appendDate("lastHeartbeat", m->lastHeartbeat());
|
|
bb.append("errmsg", m->_lastHeartbeatErrMsg.get());
|
|
v.push_back(bb.obj());
|
|
m = m->next();
|
|
}
|
|
b.append("set", getName());
|
|
b.appendDate("date", time(0));
|
|
b.append("members", v);
|
|
}
|
|
|
|
void ReplSet::startHealthThreads() {
|
|
MemberInfo* m = _members.head();
|
|
while( m ) {
|
|
FeedbackThread *f = new FeedbackThread();
|
|
f->m = m;
|
|
f->go();
|
|
m = m->next();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* todo:
|
|
stop bg job and delete on removefromset
|
|
*/
|