summaryrefslogtreecommitdiff
path: root/db/repl/rs.h
diff options
context:
space:
mode:
Diffstat (limited to 'db/repl/rs.h')
-rw-r--r--db/repl/rs.h115
1 files changed, 65 insertions, 50 deletions
diff --git a/db/repl/rs.h b/db/repl/rs.h
index 6c4d9a8..1419ad6 100644
--- a/db/repl/rs.h
+++ b/db/repl/rs.h
@@ -43,6 +43,7 @@ namespace mongo {
class Member : public List1<Member>::Base {
public:
Member(HostAndPort h, unsigned ord, const ReplSetConfig::MemberCfg *c, bool self);
+
string fullName() const { return h().toString(); }
const ReplSetConfig::MemberCfg& config() const { return _config; }
const HeartbeatInfo& hbinfo() const { return _hbinfo; }
@@ -51,10 +52,12 @@ namespace mongo {
MemberState state() const { return _hbinfo.hbstate; }
const HostAndPort& h() const { return _h; }
unsigned id() const { return _hbinfo.id(); }
+
bool potentiallyHot() const { return _config.potentiallyHot(); } // not arbiter, not priority 0
void summarizeMember(stringstream& s) const;
- friend class ReplSetImpl;
+
private:
+ friend class ReplSetImpl;
const ReplSetConfig::MemberCfg _config;
const HostAndPort _h;
HeartbeatInfo _hbinfo;
@@ -65,8 +68,8 @@ namespace mongo {
bool busyWithElectSelf;
int _primary;
- /** @param two - if true two primaries were seen. this can happen transiently, in addition to our
- polling being only occasional. in this case null is returned, but the caller should
+ /** @param two - if true two primaries were seen. this can happen transiently, in addition to our
+ polling being only occasional. in this case null is returned, but the caller should
not assume primary itself in that situation.
*/
const Member* findOtherPrimary(bool& two);
@@ -75,7 +78,7 @@ namespace mongo {
virtual void starting();
public:
Manager(ReplSetImpl *rs);
- ~Manager();
+ virtual ~Manager();
void msgReceivedNewConfig(BSONObj);
void msgCheckNewState();
};
@@ -84,7 +87,7 @@ namespace mongo {
class Consensus {
ReplSetImpl &rs;
- struct LastYea {
+ struct LastYea {
LastYea() : when(0), who(0xffffffff) { }
time_t when;
unsigned who;
@@ -96,12 +99,12 @@ namespace mongo {
bool weAreFreshest(bool& allUp, int& nTies);
bool sleptLast; // slept last elect() pass
public:
- Consensus(ReplSetImpl *t) : rs(*t) {
+ Consensus(ReplSetImpl *t) : rs(*t) {
sleptLast = false;
steppedDown = 0;
}
- /* if we've stepped down, this is when we are allowed to try to elect ourself again.
+ /* if we've stepped down, this is when we are allowed to try to elect ourself again.
todo: handle possible weirdnesses at clock skews etc.
*/
time_t steppedDown;
@@ -115,40 +118,40 @@ namespace mongo {
};
/** most operations on a ReplSet object should be done while locked. that logic implemented here. */
- class RSBase : boost::noncopyable {
+ class RSBase : boost::noncopyable {
public:
const unsigned magic;
void assertValid() { assert( magic == 0x12345677 ); }
private:
- mutex m;
+ mongo::mutex m;
int _locked;
ThreadLocalValue<bool> _lockedByMe;
protected:
RSBase() : magic(0x12345677), m("RSBase"), _locked(0) { }
- ~RSBase() {
+ ~RSBase() {
/* this can happen if we throw in the constructor; otherwise never happens. thus we log it as it is quite unusual. */
log() << "replSet ~RSBase called" << rsLog;
}
- class lock {
+ class lock {
RSBase& rsbase;
auto_ptr<scoped_lock> sl;
public:
- lock(RSBase* b) : rsbase(*b) {
+ lock(RSBase* b) : rsbase(*b) {
if( rsbase._lockedByMe.get() )
return; // recursive is ok...
sl.reset( new scoped_lock(rsbase.m) );
DEV assert(rsbase._locked == 0);
- rsbase._locked++;
+ rsbase._locked++;
rsbase._lockedByMe.set(true);
}
- ~lock() {
+ ~lock() {
if( sl.get() ) {
assert( rsbase._lockedByMe.get() );
DEV assert(rsbase._locked == 1);
rsbase._lockedByMe.set(false);
- rsbase._locked--;
+ rsbase._locked--;
}
}
};
@@ -157,11 +160,11 @@ namespace mongo {
/* for asserts */
bool locked() const { return _locked != 0; }
- /* if true, is locked, and was locked by this thread. note if false, it could be in the lock or not for another
+ /* if true, is locked, and was locked by this thread. note if false, it could be in the lock or not for another
just for asserts & such so we can make the contracts clear on who locks what when.
we don't use these locks that frequently, so the little bit of overhead is fine.
*/
- bool lockedByMe() { return _lockedByMe.get(); }
+ bool lockedByMe() { return _lockedByMe.get(); }
};
class ReplSetHealthPollTask;
@@ -174,19 +177,19 @@ namespace mongo {
MemberState state;
const Member *primary;
};
- const SP get() {
+ const SP get() {
scoped_lock lk(m);
return sp;
}
MemberState getState() const { return sp.state; }
const Member* getPrimary() const { return sp.primary; }
- void change(MemberState s, const Member *self) {
+ void change(MemberState s, const Member *self) {
scoped_lock lk(m);
- if( sp.state != s ) {
+ if( sp.state != s ) {
log() << "replSet " << s.toString() << rsLog;
}
sp.state = s;
- if( s.primary() ) {
+ if( s.primary() ) {
sp.primary = self;
}
else {
@@ -194,17 +197,17 @@ namespace mongo {
sp.primary = 0;
}
}
- void set(MemberState s, const Member *p) {
+ void set(MemberState s, const Member *p) {
scoped_lock lk(m);
sp.state = s; sp.primary = p;
}
void setSelfPrimary(const Member *self) { change(MemberState::RS_PRIMARY, self); }
- void setOtherPrimary(const Member *mem) {
+ void setOtherPrimary(const Member *mem) {
scoped_lock lk(m);
assert( !sp.state.primary() );
sp.primary = mem;
}
- void noteRemoteIsPrimary(const Member *remote) {
+ void noteRemoteIsPrimary(const Member *remote) {
scoped_lock lk(m);
if( !sp.state.secondary() && !sp.state.fatal() )
sp.state = MemberState::RS_RECOVERING;
@@ -212,10 +215,10 @@ namespace mongo {
}
StateBox() : m("StateBox") { }
private:
- mutex m;
+ mongo::mutex m;
SP sp;
};
-
+
void parseReplsetCmdLine(string cfgString, string& setname, vector<HostAndPort>& seeds, set<HostAndPort>& seedSet );
/** Parameter given to the --replSet command line option (parsed).
@@ -230,15 +233,15 @@ namespace mongo {
};
/* information about the entire repl set, such as the various servers in the set, and their state */
- /* note: We currently do not free mem when the set goes away - it is assumed the replset is a
+ /* note: We currently do not free mem when the set goes away - it is assumed the replset is a
singleton and long lived.
*/
class ReplSetImpl : protected RSBase {
public:
/** info on our state if the replset isn't yet "up". for example, if we are pre-initiation. */
- enum StartupStatus {
- PRESTART=0, LOADINGCONFIG=1, BADCONFIG=2, EMPTYCONFIG=3,
- EMPTYUNREACHABLE=4, STARTED=5, SOON=6
+ enum StartupStatus {
+ PRESTART=0, LOADINGCONFIG=1, BADCONFIG=2, EMPTYCONFIG=3,
+ EMPTYUNREACHABLE=4, STARTED=5, SOON=6
};
static StartupStatus startupStatus;
static string startupStatusMsg;
@@ -260,18 +263,21 @@ namespace mongo {
void relinquish();
void forgetPrimary();
protected:
- bool _stepDown();
+ bool _stepDown(int secs);
+ bool _freeze(int secs);
private:
void assumePrimary();
void loadLastOpTimeWritten();
void changeState(MemberState s);
+ const Member* getMemberToSyncTo();
+ void _changeArbiterState();
protected:
// "heartbeat message"
- // sent in requestHeartbeat respond in field "hbm"
+ // sent in requestHeartbeat respond in field "hbm"
char _hbmsg[256]; // we change this unlocked, thus not an stl::string
time_t _hbmsgTime; // when it was logged
public:
- void sethbmsg(string s, int logLevel = 0);
+ void sethbmsg(string s, int logLevel = 0);
protected:
bool initFromConfig(ReplSetConfig& c, bool reconf=false); // true if ok; throws if config really bad; false if config doesn't include self
void _fillIsMaster(BSONObjBuilder&);
@@ -281,7 +287,7 @@ namespace mongo {
MemberState state() const { return box.getState(); }
void _fatal();
void _getOplogDiagsAsHtml(unsigned server_id, stringstream& ss) const;
- void _summarizeAsHtml(stringstream&) const;
+ void _summarizeAsHtml(stringstream&) const;
void _summarizeStatus(BSONObjBuilder&) const; // for replSetGetStatus command
/* throws exception if a problem initializing. */
@@ -295,7 +301,7 @@ namespace mongo {
const vector<HostAndPort> *_seeds;
ReplSetConfig *_cfg;
- /** load our configuration from admin.replset. try seed machines too.
+ /** load our configuration from admin.replset. try seed machines too.
@return true if ok; throws if config really bad; false if config doesn't include self
*/
bool _loadConfigFinish(vector<ReplSetConfig>& v);
@@ -306,7 +312,9 @@ namespace mongo {
bool iAmArbiterOnly() const { return myConfig().arbiterOnly; }
bool iAmPotentiallyHot() const { return myConfig().potentiallyHot(); }
protected:
- Member *_self;
+ Member *_self;
+ bool _buildIndexes; // = _self->config().buildIndexes
+ void setSelfTo(Member *); // use this as it sets buildIndexes var
private:
List1<Member> _members; /* all members of the set EXCEPT self. */
@@ -330,7 +338,7 @@ namespace mongo {
private:
/* pulling data from primary related - see rs_sync.cpp */
- bool initialSyncOplogApplication(string hn, const Member *primary, OpTime applyGTE, OpTime minValid);
+ bool initialSyncOplogApplication(const Member *primary, OpTime applyGTE, OpTime minValid);
void _syncDoInitialSync();
void syncDoInitialSync();
void _syncThread();
@@ -340,21 +348,29 @@ namespace mongo {
unsigned _syncRollback(OplogReader& r);
void syncRollback(OplogReader& r);
void syncFixUp(HowToFixUp& h, OplogReader& r);
+ bool _getOplogReader(OplogReader& r, string& hn);
+ bool _isStale(OplogReader& r, const string& hn);
public:
void syncThread();
};
- class ReplSet : public ReplSetImpl {
+ class ReplSet : public ReplSetImpl {
public:
ReplSet(ReplSetCmdline& replSetCmdline) : ReplSetImpl(replSetCmdline) { }
- bool stepDown() { return _stepDown(); }
+ // for the replSetStepDown command
+ bool stepDown(int secs) { return _stepDown(secs); }
- string selfFullName() {
+ // for the replSetFreeze command
+ bool freeze(int secs) { return _freeze(secs); }
+
+ string selfFullName() {
lock lk(this);
return _self->fullName();
}
+ bool buildIndexes() const { return _buildIndexes; }
+
/* call after constructing to start - returns fairly quickly after la[unching its threads */
void go() { _go(); }
@@ -369,7 +385,7 @@ namespace mongo {
void summarizeStatus(BSONObjBuilder& b) const { _summarizeStatus(b); }
void fillIsMaster(BSONObjBuilder& b) { _fillIsMaster(b); }
- /* we have a new config (reconfig) - apply it.
+ /* we have a new config (reconfig) - apply it.
@param comment write a no-op comment to the oplog about it. only makes sense if one is primary and initiating the reconf.
*/
void haveNewConfig(ReplSetConfig& c, bool comment);
@@ -380,16 +396,16 @@ namespace mongo {
bool lockedByMe() { return RSBase::lockedByMe(); }
// heartbeat msg to send to others; descriptive diagnostic info
- string hbmsg() const {
+ string hbmsg() const {
if( time(0)-_hbmsgTime > 120 ) return "";
- return _hbmsg;
+ return _hbmsg;
}
};
- /** base class for repl set commands. checks basic things such as in rs mode before the command
+ /** base class for repl set commands. checks basic things such as in rs mode before the command
does its real work
*/
- class ReplSetCommand : public Command {
+ class ReplSetCommand : public Command {
protected:
ReplSetCommand(const char * s, bool show=false) : Command(s, show) { }
virtual bool slaveOk() const { return true; }
@@ -398,14 +414,14 @@ namespace mongo {
virtual LockType locktype() const { return NONE; }
virtual void help( stringstream &help ) const { help << "internal"; }
bool check(string& errmsg, BSONObjBuilder& result) {
- if( !replSet ) {
+ if( !replSet ) {
errmsg = "not running with --replSet";
return false;
}
if( theReplSet == 0 ) {
result.append("startupStatus", ReplSet::startupStatus);
errmsg = ReplSet::startupStatusMsg.empty() ? "replset unknown error 2" : ReplSet::startupStatusMsg;
- if( ReplSet::startupStatus == 3 )
+ if( ReplSet::startupStatus == 3 )
result.append("info", "run rs.initiate(...) if not yet done for the set");
return false;
}
@@ -415,9 +431,8 @@ namespace mongo {
/** inlines ----------------- */
- inline Member::Member(HostAndPort h, unsigned ord, const ReplSetConfig::MemberCfg *c, bool self) :
- _config(*c), _h(h), _hbinfo(ord)
- {
+ inline Member::Member(HostAndPort h, unsigned ord, const ReplSetConfig::MemberCfg *c, bool self) :
+ _config(*c), _h(h), _hbinfo(ord) {
if( self )
_hbinfo.health = 1.0;
}