0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00
mongodb/db/replset.h

189 lines
5.9 KiB
C
Raw Normal View History

/**
* Copyright (C) 2008 10gen Inc.
2008-12-29 02:28:49 +01:00
*
* 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.
2008-12-29 02:28:49 +01:00
*
* 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.
2008-12-29 02:28:49 +01:00
*
* 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/>.
*/
#pragma once
2008-12-05 22:03:35 +01:00
#include "db.h"
2008-12-29 04:01:18 +01:00
#include "dbhelpers.h"
#include "json.h"
2008-12-05 22:03:35 +01:00
#include "../client/dbclient.h"
2009-01-14 23:09:51 +01:00
namespace mongo {
extern int port;
extern const char *replAllDead;
/* ReplPair is a pair of db servers replicating to one another and cooperating.
Only one member of the pair is active at a time; so this is a smart master/slave
configuration basically.
You may read from the slave at anytime though (if you don't mind the slight lag).
todo: Could be extended to be more than a pair, thus the name 'Set' -- for example,
a set of 3...
*/
class ReplPair {
public:
enum ReplState {
State_CantArb = -3,
State_Confused = -2,
State_Negotiating = -1,
State_Slave = 0,
State_Master = 1
};
int state;
string info; // commentary about our current state
string arbHost; // "-" for no arbiter. "host[:port]"
int remotePort;
string remoteHost;
string remote; // host:port if port specified.
// int date; // -1 not yet set; 0=slave; 1=master
string getInfo() {
stringstream ss;
ss << " state: ";
if ( state == 1 ) ss << "1 State_Master ";
else if ( state == 0 ) ss << "0 State_Slave";
else
ss << "<b>" << state << "</b>";
ss << '\n';
ss << " info: " << info << '\n';
ss << " arbhost: " << arbHost << '\n';
ss << " remote: " << remoteHost << ':' << remotePort << '\n';
// ss << " date: " << date << '\n';
return ss.str();
}
2008-12-01 03:00:54 +01:00
ReplPair(const char *remoteEnd, const char *arbiter);
2009-02-18 19:42:32 +01:00
virtual ~ReplPair() {}
bool dominant(const string& myname) {
if ( myname == remoteHost )
return port > remotePort;
return myname > remoteHost;
}
void setMasterLocked( int n, const char *_comment = "" ) {
dblock p;
setMaster( n, _comment );
}
2008-12-29 02:28:49 +01:00
void setMaster(int n, const char *_comment = "");
/* negotiate with our peer who is master; returns state of peer */
int negotiate(DBClientConnection *conn, string method);
/* peer unreachable, try our arbitrator */
void arbitrate();
virtual
DBClientConnection *newClientConnection() const {
return new DBClientConnection();
}
};
2008-12-01 20:55:36 +01:00
extern ReplPair *replPair;
2008-12-01 20:55:36 +01:00
/* note we always return true for the "local" namespace.
2008-12-01 20:55:36 +01:00
we should not allow most operations when not the master
also we report not master if we are "dead".
2008-12-01 20:55:36 +01:00
See also CmdIsMaster.
2008-09-11 21:13:47 +02:00
2009-03-30 20:07:04 +02:00
If 'client' is not specified, the current client is used.
*/
2009-03-30 20:07:04 +02:00
inline bool isMaster( const char *client = 0 ) {
if ( !client )
client = database->name.c_str();
if ( replAllDead || slave ) {
2009-03-30 20:07:04 +02:00
return strcmp( client, "local" ) == 0;
}
2009-01-14 23:17:24 +01:00
if ( replPair == 0 || replPair->state == ReplPair::State_Master )
return true;
2009-01-14 23:17:24 +01:00
2009-03-30 20:07:04 +02:00
return strcmp( client, "local" ) == 0;
}
inline bool isMasterNs( const char *ns ) {
char cl[ 256 ];
nsToClient( ns, cl );
return isMaster( cl );
2008-12-29 04:01:18 +01:00
}
2009-01-14 23:17:24 +01:00
inline ReplPair::ReplPair(const char *remoteEnd, const char *arb) {
state = -1;
remote = remoteEnd;
remotePort = DBPort;
remoteHost = remoteEnd;
const char *p = strchr(remoteEnd, ':');
if ( p ) {
remoteHost = string(remoteEnd, p-remoteEnd);
remotePort = atoi(p+1);
uassert("bad port #", remotePort > 0 && remotePort < 0x10000 );
if ( remotePort == DBPort )
remote = remoteHost; // don't include ":27017" as it is default; in case ran in diff ways over time to normalizke the hostname format in sources collection
}
uassert("arbiter parm is missing, use '-' for none", arb);
arbHost = arb;
uassert("arbiter parm is empty", !arbHost.empty());
2008-12-29 04:01:18 +01:00
}
2009-01-14 23:17:24 +01:00
/* This is set to true if we have EVER been up to date -- this way a new pair member
which is a replacement won't go online as master until we have initially fully synced.
*/
class PairSync {
int initialsynccomplete;
public:
PairSync() {
initialsynccomplete = -1;
}
/* call before using the class. from dbmutex */
void init() {
BSONObj o;
initialsynccomplete = 0;
if ( Helpers::getSingleton("local.pair.sync", o) )
initialsynccomplete = 1;
}
bool initialSyncCompleted() {
return initialsynccomplete != 0;
}
void setInitialSyncCompleted() {
BSONObj o = fromjson("{\"initialsynccomplete\":1}");
Helpers::putSingleton("local.pair.sync", o);
initialsynccomplete = 1;
}
void setInitialSyncCompletedLocking() {
if ( initialsynccomplete == 1 )
return;
dblock lk;
BSONObj o = fromjson("{\"initialsynccomplete\":1}");
Helpers::putSingleton("local.pair.sync", o);
initialsynccomplete = 1;
}
};
2008-12-29 04:01:18 +01:00
2009-01-14 23:09:51 +01:00
} // namespace mongo