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

231 lines
7.3 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-08-17 22:45:34 +02:00
#include "repl.h"
2009-08-25 16:24:44 +02:00
#include "cmdline.h"
2010-04-22 03:19:37 +02:00
#include "repl/replset.h"
2008-12-05 22:03:35 +01:00
2009-01-14 23:09:51 +01:00
namespace mongo {
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;
2010-02-26 17:33:27 +01:00
ThreadSafeString 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
2010-02-26 17:33:27 +01:00
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 )
2009-08-25 16:24:44 +02:00
return cmdLine.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
2010-04-22 03:49:09 +02:00
inline void notMasterUnless(bool expr) {
uassert( 10107 , "not master" , expr );
}
/* 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 ) {
2010-04-22 03:19:37 +02:00
if( replSet ) {
if( theReplSet ) return theReplSet->isMaster(client);
return false;
}
if( ! replSettings.slave )
2009-08-18 03:46:18 +02:00
return true;
if ( !client ) {
Database *database = cc().database();
assert( database );
2009-03-30 20:07:04 +02:00
client = database->name.c_str();
}
2009-08-17 23:33:04 +02:00
if ( replAllDead )
2009-03-30 20:07:04 +02:00
return strcmp( client, "local" ) == 0;
2009-01-14 23:17:24 +01:00
2009-08-17 23:33:04 +02:00
if ( replPair ) {
if( replPair->state == ReplPair::State_Master )
return true;
}
2009-09-22 20:34:55 +02:00
else {
if( replSettings.master ) {
2009-09-22 20:34:55 +02:00
// if running with --master --slave, allow. note that master is also true
// for repl pairs so the check for replPair above is important.
return true;
}
}
if ( cc().isGod() )
return true;
2009-03-30 20:07:04 +02:00
return strcmp( client, "local" ) == 0;
}
2010-04-22 00:46:31 +02:00
2010-04-22 03:49:09 +02:00
/* we allow queries to SimpleSlave's -- but not to the slave (nonmaster) member of a replica pair
so that queries to a pair are realtime consistent as much as possible. use setSlaveOk() to
query the nonmaster member of a replica pair.
*/
inline void replVerifyReadsOk(ParsedQuery& pq) {
if( replSet ) {
2010-04-22 19:07:36 +02:00
uassert(13124, "not master - replSet still initializing", theReplSet); // during initialization, no queries allowed whatsover
2010-04-22 03:49:09 +02:00
notMasterUnless( theReplSet->isMaster("") || pq.hasOption( QueryOption_SlaveOk ) );
return;
}
notMasterUnless(isMaster() || pq.hasOption( QueryOption_SlaveOk ) || replSettings.slave == SimpleSlave);
}
2009-03-30 20:07:04 +02:00
inline bool isMasterNs( const char *ns ) {
char cl[ 256 ];
2009-12-31 22:31:07 +01:00
nsToDatabase( ns, cl );
2009-03-30 20:07:04 +02:00
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;
2009-08-25 16:24:44 +02:00
remotePort = CmdLine::DefaultDBPort;
remoteHost = remoteEnd;
const char *p = strchr(remoteEnd, ':');
if ( p ) {
remoteHost = string(remoteEnd, p-remoteEnd);
remotePort = atoi(p+1);
uassert( 10125 , "bad port #", remotePort > 0 && remotePort < 0x10000 );
2009-08-25 16:24:44 +02:00
if ( remotePort == CmdLine::DefaultDBPort )
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( 10126 , "arbiter parm is missing, use '-' for none", arb);
arbHost = arb;
uassert( 10127 , "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;
log() << "pair: initial sync complete" << endl;
}
void setInitialSyncCompletedLocking() {
if ( initialsynccomplete == 1 )
return;
dblock lk;
2010-03-30 23:18:34 +02:00
setInitialSyncCompleted();
}
};
2008-12-29 04:01:18 +01:00
2009-01-14 23:09:51 +01:00
} // namespace mongo