diff options
Diffstat (limited to 'db/repl/health.cpp')
-rw-r--r-- | db/repl/health.cpp | 161 |
1 files changed, 92 insertions, 69 deletions
diff --git a/db/repl/health.cpp b/db/repl/health.cpp index c75221c..762ca90 100644 --- a/db/repl/health.cpp +++ b/db/repl/health.cpp @@ -32,20 +32,22 @@ #include "../dbhelpers.h" namespace mongo { + /* decls for connections.h */ - ScopedConn::M& ScopedConn::_map = *(new ScopedConn::M()); + ScopedConn::M& ScopedConn::_map = *(new ScopedConn::M()); mutex ScopedConn::mapMutex("ScopedConn::mapMutex"); } -namespace mongo { +namespace mongo { using namespace mongoutils::html; using namespace bson; static RamLog _rsLog; Tee *rsLog = &_rsLog; + extern bool replSetBlind; - string ago(time_t t) { + string ago(time_t t) { if( t == 0 ) return ""; time_t x = time(0) - t; @@ -58,14 +60,14 @@ namespace mongo { s.precision(2); s << x / 60.0 << " mins"; } - else { + else { s.precision(2); s << x / 3600.0 << " hrs"; } return s.str(); } - void Member::summarizeMember(stringstream& s) const { + void Member::summarizeMember(stringstream& s) const { s << tr(); { stringstream u; @@ -89,27 +91,29 @@ namespace mongo { s << td(h); } s << td(config().votes); - { + s << td(config().priority); + { string stateText = state().toString(); if( _config.hidden ) stateText += " (hidden)"; - if( ok || stateText.empty() ) + if( ok || stateText.empty() ) s << td(stateText); // text blank if we've never connected else s << td( grey(str::stream() << "(was " << state().toString() << ')', true) ); } s << td( grey(hbinfo().lastHeartbeatMsg,!ok) ); stringstream q; - q << "/_replSetOplog?" << id(); + q << "/_replSetOplog?_id=" << id(); s << td( a(q.str(), "", never ? "?" : hbinfo().opTime.toString()) ); if( hbinfo().skew > INT_MIN ) { s << td( grey(str::stream() << hbinfo().skew,!ok) ); - } else + } + else s << td(""); s << _tr(); } - - string ReplSetImpl::stateAsHtml(MemberState s) { + + string ReplSetImpl::stateAsHtml(MemberState s) { if( s.s == MemberState::RS_STARTUP ) return a("", "serving still starting up, or still trying to initiate the set", "STARTUP"); if( s.s == MemberState::RS_PRIMARY ) return a("", "this server thinks it is primary", "PRIMARY"); if( s.s == MemberState::RS_SECONDARY ) return a("", "this server thinks it is a secondary (slave mode)", "SECONDARY"); @@ -122,7 +126,7 @@ namespace mongo { return ""; } - string MemberState::toString() const { + string MemberState::toString() const { if( s == MemberState::RS_STARTUP ) return "STARTUP"; if( s == MemberState::RS_PRIMARY ) return "PRIMARY"; if( s == MemberState::RS_SECONDARY ) return "SECONDARY"; @@ -143,9 +147,9 @@ namespace mongo { set<string> skip; be e = op["ts"]; - if( e.type() == Date || e.type() == Timestamp ) { + if( e.type() == Date || e.type() == Timestamp ) { OpTime ot = e._opTime(); - ss << td( time_t_to_String_short( ot.getSecs() ) ); + ss << td( time_t_to_String_short( ot.getSecs() ) ); ss << td( ot.toString() ); skip.insert("ts"); } @@ -155,7 +159,8 @@ namespace mongo { if( e.type() == NumberLong ) { ss << "<td>" << hex << e.Long() << "</td>\n"; skip.insert("h"); - } else + } + else ss << td("?"); ss << td(op["op"].valuestrsafe()); @@ -164,20 +169,17 @@ namespace mongo { skip.insert("ns"); ss << "<td>"; - for( bo::iterator i(op); i.more(); ) { + for( bo::iterator i(op); i.more(); ) { be e = i.next(); if( skip.count(e.fieldName()) ) continue; ss << e.toString() << ' '; } - ss << "</td>"; - - ss << "</tr>"; - ss << '\n'; + ss << "</td></tr>\n"; } - void ReplSetImpl::_getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) const { + void ReplSetImpl::_getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) const { const Member *m = findById(server_id); - if( m == 0 ) { + if( m == 0 ) { ss << "Error : can't find a member with id: " << server_id << '\n'; return; } @@ -187,21 +189,29 @@ namespace mongo { //const bo fields = BSON( "o" << false << "o2" << false ); const bo fields; - ScopedDbConnection conn(m->fullName()); + /** todo fix we might want an so timeout here */ + DBClientConnection conn(false, 0, /*timeout*/ 20); + { + string errmsg; + if( !conn.connect(m->fullName(), errmsg) ) { + ss << "couldn't connect to " << m->fullName() << ' ' << errmsg; + return; + } + } - auto_ptr<DBClientCursor> c = conn->query(rsoplog, Query().sort("$natural",1), 20, 0, &fields); - if( c.get() == 0 ) { + auto_ptr<DBClientCursor> c = conn.query(rsoplog, Query().sort("$natural",1), 20, 0, &fields); + if( c.get() == 0 ) { ss << "couldn't query " << rsoplog; return; } static const char *h[] = {"ts","optime", "h","op","ns","rest",0}; ss << "<style type=\"text/css\" media=\"screen\">" - "table { font-size:75% }\n" + "table { font-size:75% }\n" // "th { background-color:#bbb; color:#000 }\n" // "td,th { padding:.25em }\n" - "</style>\n"; - + "</style>\n"; + ss << table(h, true); //ss << "<pre>\n"; int n = 0; @@ -211,17 +221,17 @@ namespace mongo { while( c->more() ) { bo o = c->next(); otLast = o["ts"]._opTime(); - if( otFirst.isNull() ) + if( otFirst.isNull() ) otFirst = otLast; say(ss, o); - n++; + n++; } if( n == 0 ) { ss << rsoplog << " is empty\n"; } - else { - auto_ptr<DBClientCursor> c = conn->query(rsoplog, Query().sort("$natural",-1), 20, 0, &fields); - if( c.get() == 0 ) { + else { + auto_ptr<DBClientCursor> c = conn.query(rsoplog, Query().sort("$natural",-1), 20, 0, &fields); + if( c.get() == 0 ) { ss << "couldn't query [2] " << rsoplog; return; } @@ -230,7 +240,7 @@ namespace mongo { otEnd = o["ts"]._opTime(); while( 1 ) { stringstream z; - if( o["ts"]._opTime() == otLast ) + if( o["ts"]._opTime() == otLast ) break; say(z, o); x = z.str() + x; @@ -253,32 +263,31 @@ namespace mongo { ss.precision(3); if( h < 72 ) ss << h << " hours"; - else + else ss << h / 24.0 << " days"; ss << "</p>\n"; } - - conn.done(); } - void ReplSetImpl::_summarizeAsHtml(stringstream& s) const { + void ReplSetImpl::_summarizeAsHtml(stringstream& s) const { s << table(0, false); s << tr("Set name:", _name); s << tr("Majority up:", elect.aMajoritySeemsToBeUp()?"yes":"no" ); s << _table(); - const char *h[] = {"Member", - "<a title=\"member id in the replset config\">id</a>", - "Up", - "<a title=\"length of time we have been continuously connected to the other member with no reconnects (for self, shows uptime)\">cctime</a>", - "<a title=\"when this server last received a heartbeat response - includes error code responses\">Last heartbeat</a>", - "Votes", "State", "Status", - "<a title=\"how up to date this server is. this value polled every few seconds so actually lag is typically much lower than value shown here.\">optime</a>", - "<a title=\"Clock skew in seconds relative to this server. Informational; server clock variances will make the diagnostics hard to read, but otherwise are benign..\">skew</a>", - 0}; + const char *h[] = {"Member", + "<a title=\"member id in the replset config\">id</a>", + "Up", + "<a title=\"length of time we have been continuously connected to the other member with no reconnects (for self, shows uptime)\">cctime</a>", + "<a title=\"when this server last received a heartbeat response - includes error code responses\">Last heartbeat</a>", + "Votes", "Priority", "State", "Messages", + "<a title=\"how up to date this server is. this value polled every few seconds so actually lag is typically much lower than value shown here.\">optime</a>", + "<a title=\"Clock skew in seconds relative to this server. Informational; server clock variances will make the diagnostics hard to read, but otherwise are benign..\">skew</a>", + 0 + }; s << table(h); - /* this is to sort the member rows by their ordinal _id, so they show up in the same + /* this is to sort the member rows by their ordinal _id, so they show up in the same order on all the different web ui's; that is less confusing for the operator. */ map<int,string> mp; @@ -287,13 +296,13 @@ namespace mongo { readlocktry lk("local.replset.minvalid", 300); if( lk.got() ) { BSONObj mv; - if( Helpers::getSingleton("local.replset.minvalid", mv) ) { + if( Helpers::getSingleton("local.replset.minvalid", mv) ) { myMinValid = "minvalid:" + mv["ts"]._opTime().toString(); } } else myMinValid = "."; } - catch(...) { + catch(...) { myMinValid = "exception fetching minvalid"; } @@ -301,25 +310,26 @@ namespace mongo { stringstream s; /* self row */ s << tr() << td(_self->fullName() + " (me)") << - td(_self->id()) << - td("1") << //up - td(ago(started)) << - td("") << // last heartbeat - td(ToString(_self->config().votes)) << - td( stateAsHtml(box.getState()) + (_self->config().hidden?" (hidden)":"") ); + td(_self->id()) << + td("1") << //up + td(ago(started)) << + td("") << // last heartbeat + td(ToString(_self->config().votes)) << + td(ToString(_self->config().priority)) << + td( stateAsHtml(box.getState()) + (_self->config().hidden?" (hidden)":"") ); s << td( _hbmsg ); stringstream q; - q << "/_replSetOplog?" << _self->id(); + q << "/_replSetOplog?_id=" << _self->id(); s << td( a(q.str(), myMinValid, theReplSet->lastOpTimeWritten.toString()) ); s << td(""); // skew s << _tr(); - mp[_self->hbinfo().id()] = s.str(); + mp[_self->hbinfo().id()] = s.str(); } Member *m = head(); while( m ) { - stringstream s; + stringstream s; m->summarizeMember(s); - mp[m->hbinfo().id()] = s.str(); + mp[m->hbinfo().id()] = s.str(); m = m->next(); } @@ -333,26 +343,27 @@ namespace mongo { _rsLog.toHTML( s ); } - const Member* ReplSetImpl::findById(unsigned id) const { + const Member* ReplSetImpl::findById(unsigned id) const { if( id == _self->id() ) return _self; for( Member *m = head(); m; m = m->next() ) - if( m->id() == id ) + if( m->id() == id ) return m; return 0; } - void ReplSetImpl::_summarizeStatus(BSONObjBuilder& b) const { + void ReplSetImpl::_summarizeStatus(BSONObjBuilder& b) const { vector<BSONObj> v; // add self { - HostAndPort h(getHostName(), cmdLine.port); - BSONObjBuilder bb; bb.append("_id", (int) _self->id()); - bb.append("name", h.toString()); + bb.append("name", _self->fullName()); bb.append("health", 1.0); bb.append("state", (int) box.getState().s); + bb.append("stateStr", box.getState().toString()); + bb.appendTimestamp("optime", lastOpTimeWritten.asDate()); + bb.appendDate("optimeDate", lastOpTimeWritten.getSecs() * 1000LL); string s = _self->lhb(); if( !s.empty() ) bb.append("errmsg", s); @@ -365,9 +376,19 @@ namespace mongo { BSONObjBuilder bb; bb.append("_id", (int) m->id()); bb.append("name", m->fullName()); - bb.append("health", m->hbinfo().health); + double h = m->hbinfo().health; + bb.append("health", h); bb.append("state", (int) m->state().s); + if( h == 0 ) { + // if we can't connect the state info is from the past and could be confusing to show + bb.append("stateStr", "(not reachable/healthy)"); + } + else { + bb.append("stateStr", m->state().toString()); + } bb.append("uptime", (unsigned) (m->hbinfo().upSince ? (time(0)-m->hbinfo().upSince) : 0)); + bb.appendTimestamp("optime", m->hbinfo().opTime.asDate()); + bb.appendDate("optimeDate", m->hbinfo().opTime.getSecs() * 1000LL); bb.appendTimeT("lastHeartbeat", m->hbinfo().lastHeartbeat); string s = m->lhb(); if( !s.empty() ) @@ -380,10 +401,12 @@ namespace mongo { b.appendTimeT("date", time(0)); b.append("myState", box.getState().s); b.append("members", v); + if( replSetBlind ) + b.append("blind",true); // to avoid confusion if set...normally never set except for testing. } - static struct Test : public UnitTest { - void run() { + static struct Test : public UnitTest { + void run() { HealthOptions a,b; assert( a == b ); assert( a.isDefault() ); |