Esempio n. 1
0
        void up(const BSONObj& info, HeartbeatInfo& mem, bool* needsNewStateChecked) {
            HeartbeatInfo::numPings++;
            mem.authIssue = false;

            if( mem.upSince == 0 ) {
                log() << "replSet member " << h.toString() << " is up" << rsLog;
                mem.upSince = mem.lastHeartbeat;
            }
            mem.health = 1.0;
            mem.lastHeartbeatMsg = info["hbmsg"].String();
            if (info.hasElement("syncingTo")) {
                mem.syncingTo = info["syncingTo"].String();
            }
            if( info.hasElement("opTime") ) {
                mem.opTime = info["opTime"].Date();
            }
            if ( info.hasElement("GTID")) {
                mem.gtid = getGTIDFromBSON("GTID", info);
            }
            if ( info.hasElement("lastUnappliedGTID")) {
                mem.lastUnappliedGTID = getGTIDFromBSON("lastUnappliedGTID", info);
            }
            if ( info.hasElement("minLiveGTID")) {
                mem.minLiveGTID= getGTIDFromBSON("minLiveGTID", info);
            }
            if ( info.hasElement("minUnappliedGTID")) {
                mem.minUnappliedGTID= getGTIDFromBSON("minUnappliedGTID", info);
            }
            if ( info.hasElement("oplogVersion")) {
                mem.oplogVersion = info["oplogVersion"].numberLong();
            }
            else {
                mem.oplogVersion = 0;
            }
            // for "highest known primary"
            if ( info.hasElement("hkp")) {
                mem.highestKnownPrimaryInSet = info["hkp"].numberLong();
                // if the highest known primary across the replica set has changed,
                // communicate that to the caller so that Manager::msgCheckNewState
                // eventually gets called
                *needsNewStateChecked = theReplSet->handleHighestKnownPrimaryOfMember(mem.highestKnownPrimaryInSet);
            }
            else {
                mem.highestKnownPrimaryInSet = 0;
            }
            // see if this member is in the electable set
            if( info["e"].eoo() ) {
                // for backwards compatibility
                const Member *member = theReplSet->findById(mem.id());
                if (member && member->config().potentiallyHot()) {
                    theReplSet->addToElectable(mem.id());
                }
                else {
                    theReplSet->rmFromElectable(mem.id());
                }
            }
            // add this server to the electable set if it is within 10
            // seconds of the latest optime we know of
            else if( info["e"].trueValue() &&
                     mem.opTime + 10000 >= (theReplSet->gtidManager ? theReplSet->gtidManager->getCurrTimestamp() : 0)) 
            {
                unsigned lastOp = theReplSet->lastOtherOpTime();
                if (lastOp > 0 && mem.opTime + 10000 >= lastOp) {
                    theReplSet->addToElectable(mem.id());
                }
            }
            else {
                theReplSet->rmFromElectable(mem.id());
            }

            be cfg = info["config"];
            if( cfg.ok() ) {
                // received a new config
                boost::function<void()> f =
                    boost::bind(&Manager::msgReceivedNewConfig, theReplSet->mgr, cfg.Obj().copy());
                theReplSet->mgr->send(f);
            }
        }
Esempio n. 2
0
        void doWork() {
            if ( !theReplSet ) {
                LOG(2) << "replSet not initialized yet, skipping health poll this round" << rsLog;
                return;
            }

            HeartbeatInfo mem = m;
            HeartbeatInfo old = mem;
            try {
                BSONObj info;
                int theirConfigVersion = -10000;

                Timer timer;

                bool ok = requestHeartbeat(theReplSet->name(), theReplSet->selfFullName(), h.toString(), info, theReplSet->config().version, theirConfigVersion);

                mem.ping = (unsigned int)timer.millis();

                time_t before = timer.startTime() / 1000000;
                // we set this on any response - we don't get this far if
                // couldn't connect because exception is thrown
                time_t after = mem.lastHeartbeat = before + (mem.ping / 1000);

                // weight new ping with old pings
                // on the first ping, just use the ping value
                if (old.ping != 0) {
                    mem.ping = (unsigned int)((old.ping * .8) + (mem.ping * .2));
                }

                if ( info["time"].isNumber() ) {
                    long long t = info["time"].numberLong();
                    if( t > after )
                        mem.skew = (int) (t - after);
                    else if( t < before )
                        mem.skew = (int) (t - before); // negative
                }
                else {
                    // it won't be there if remote hasn't initialized yet
                    if( info.hasElement("time") )
                        warning() << "heatbeat.time isn't a number: " << info << endl;
                    mem.skew = INT_MIN;
                }

                {
                    be state = info["state"];
                    if( state.ok() )
                        mem.hbstate = MemberState(state.Int());
                }
                if( ok ) {
                    HeartbeatInfo::numPings++;

                    if( mem.upSince == 0 ) {
                        log() << "replSet info member " << h.toString() << " is up" << rsLog;
                        mem.upSince = mem.lastHeartbeat;
                    }
                    mem.health = 1.0;
                    mem.lastHeartbeatMsg = info["hbmsg"].String();
                    if( info.hasElement("opTime") )
                        mem.opTime = info["opTime"].Date();

                    // see if this member is in the electable set
                    if( info["e"].eoo() ) {
                        // for backwards compatibility
                        const Member *member = theReplSet->findById(mem.id());
                        if (member && member->config().potentiallyHot()) {
                            theReplSet->addToElectable(mem.id());
                        }
                        else {
                            theReplSet->rmFromElectable(mem.id());
                        }
                    }
                    // add this server to the electable set if it is within 10
                    // seconds of the latest optime we know of
                    else if( info["e"].trueValue() &&
                             mem.opTime >= theReplSet->lastOpTimeWritten.getSecs() - 10) {
                        unsigned lastOp = theReplSet->lastOtherOpTime().getSecs();
                        if (lastOp > 0 && mem.opTime >= lastOp - 10) {
                            theReplSet->addToElectable(mem.id());
                        }
                    }
                    else {
                        theReplSet->rmFromElectable(mem.id());
                    }
                    
                    be cfg = info["config"];
                    if( cfg.ok() ) {
                        // received a new config
                        boost::function<void()> f =
                            boost::bind(&Manager::msgReceivedNewConfig, theReplSet->mgr, cfg.Obj().copy());
                        theReplSet->mgr->send(f);
                    }
                }
                else {
                    down(mem, info.getStringField("errmsg"));
                }
            }
            catch(DBException& e) {
                down(mem, e.what());
            }
            catch(...) {
                down(mem, "replSet unexpected exception in ReplSetHealthPollTask");
            }
            m = mem;

            theReplSet->mgr->send( boost::bind(&ReplSet::msgUpdateHBInfo, theReplSet, mem) );

            static time_t last = 0;
            time_t now = time(0);
            bool changed = mem.changed(old);
            if( changed ) {
                if( old.hbstate != mem.hbstate )
                    log() << "replSet member " << h.toString() << " is now in state " << mem.hbstate.toString() << rsLog;
            }
            if( changed || now-last>4 ) {
                last = now;
                theReplSet->mgr->send( boost::bind(&Manager::msgCheckNewState, theReplSet->mgr) );
            }
        }