2008-09-03 22:43:00 +02:00
/**
* Copyright ( C ) 2008 10 gen Inc .
2008-12-29 02:28:49 +01:00
*
2008-09-03 22:43:00 +02: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
*
2008-09-03 22:43:00 +02: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
*
2008-09-03 22:43:00 +02: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 {
2009-02-04 19:22:02 +01:00
extern const char * replAllDead ;
2009-01-15 16:17:11 +01:00
/* 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 :
2009-04-06 23:57:16 +02:00
enum ReplState {
2009-01-15 16:17:11 +01:00
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
2009-01-15 16:17:11 +01:00
string arbHost ; // "-" for no arbiter. "host[:port]"
int remotePort ;
string remoteHost ;
string remote ; // host:port if port specified.
2008-12-02 20:24:45 +01:00
// int date; // -1 not yet set; 0=slave; 1=master
2010-02-26 17:33:27 +01:00
2009-01-15 16:17:11 +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 ' ;
2008-12-02 20:24:45 +01:00
// ss << " date: " << date << '\n';
2009-01-15 16:17:11 +01:00
return ss . str ( ) ;
}
2008-12-01 03:00:54 +01:00
2009-01-15 16:17:11 +01:00
ReplPair ( const char * remoteEnd , const char * arbiter ) ;
2009-02-18 19:42:32 +01:00
virtual ~ ReplPair ( ) { }
2008-09-03 22:43:00 +02:00
2009-01-15 16:17:11 +01:00
bool dominant ( const string & myname ) {
if ( myname = = remoteHost )
2009-08-25 16:24:44 +02:00
return cmdLine . port > remotePort ;
2009-01-15 16:17:11 +01:00
return myname > remoteHost ;
}
2008-09-11 15:15:34 +02:00
2009-01-15 16:17:11 +01:00
void setMasterLocked ( int n , const char * _comment = " " ) {
dblock p ;
setMaster ( n , _comment ) ;
}
2008-12-29 02:28:49 +01:00
2009-01-15 16:17:11 +01:00
void setMaster ( int n , const char * _comment = " " ) ;
2008-09-11 15:15:34 +02:00
2009-04-10 23:03:45 +02:00
/* negotiate with our peer who is master; returns state of peer */
int negotiate ( DBClientConnection * conn , string method ) ;
2008-09-03 22:43:00 +02:00
2009-01-15 16:17:11 +01:00
/* peer unreachable, try our arbitrator */
void arbitrate ( ) ;
2008-09-11 16:45:57 +02:00
2009-01-15 16:17:11 +01:00
virtual
DBClientConnection * newClientConnection ( ) const {
return new DBClientConnection ( ) ;
}
} ;
2008-12-01 20:55:36 +01:00
2009-01-15 16:17:11 +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 ) ;
}
2009-01-15 16:17:11 +01:00
/* note we always return true for the "local" namespace.
2008-12-01 20:55:36 +01:00
2009-01-15 16:17:11 +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
2009-01-15 16:17:11 +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-01-15 16:17:11 +01:00
*/
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 ;
}
2010-02-09 03:04:09 +01:00
if ( ! replSettings . slave )
2009-08-18 03:46:18 +02:00
return true ;
2009-09-22 19:45:42 +02:00
if ( ! client ) {
2009-10-14 20:34:38 +02:00
Database * database = cc ( ) . database ( ) ;
2009-09-22 19:45:42 +02:00
assert ( database ) ;
2009-03-30 20:07:04 +02:00
client = database - > name . c_str ( ) ;
2009-09-22 19:45:42 +02:00
}
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 {
2010-02-09 03:04:09 +01:00
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 ;
}
}
2009-10-23 05:47:39 +02:00
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
2009-01-15 16:17:11 +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 ;
2009-01-15 16:17:11 +01:00
remoteHost = remoteEnd ;
const char * p = strchr ( remoteEnd , ' : ' ) ;
if ( p ) {
remoteHost = string ( remoteEnd , p - remoteEnd ) ;
remotePort = atoi ( p + 1 ) ;
2009-12-28 22:43:43 +01:00
uassert ( 10125 , " bad port # " , remotePort > 0 & & remotePort < 0x10000 ) ;
2009-08-25 16:24:44 +02:00
if ( remotePort = = CmdLine : : DefaultDBPort )
2009-01-15 16:17:11 +01:00
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
}
2009-12-28 22:43:43 +01:00
uassert ( 10126 , " arbiter parm is missing, use '-' for none " , arb ) ;
2009-01-15 16:17:11 +01:00
arbHost = arb ;
2009-12-28 22:43:43 +01:00
uassert ( 10127 , " arbiter parm is empty " , ! arbHost . empty ( ) ) ;
2008-12-29 04:01:18 +01:00
}
2009-01-14 23:17:24 +01:00
2009-01-15 16:17:11 +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 ;
2009-01-18 23:48:44 +01:00
if ( Helpers : : getSingleton ( " local.pair.sync " , o ) )
2009-01-15 16:17:11 +01:00
initialsynccomplete = 1 ;
}
bool initialSyncCompleted ( ) {
return initialsynccomplete ! = 0 ;
}
void setInitialSyncCompleted ( ) {
BSONObj o = fromjson ( " { \" initialsynccomplete \" :1} " ) ;
2009-01-18 23:48:44 +01:00
Helpers : : putSingleton ( " local.pair.sync " , o ) ;
2009-01-15 16:17:11 +01:00
initialsynccomplete = 1 ;
2010-03-30 22:48:15 +02:00
log ( ) < < " pair: initial sync complete " < < endl ;
2009-01-15 16:17:11 +01:00
}
void setInitialSyncCompletedLocking ( ) {
if ( initialsynccomplete = = 1 )
return ;
dblock lk ;
2010-03-30 23:18:34 +02:00
setInitialSyncCompleted ( ) ;
2009-01-15 16:17:11 +01:00
}
} ;
2008-12-29 04:01:18 +01:00
2009-01-14 23:09:51 +01:00
} // namespace mongo