2008-07-28 19:51:39 +02:00
|
|
|
// repl.h - replication
|
|
|
|
|
2008-07-28 00:36:47 +02:00
|
|
|
/**
|
|
|
|
* Copyright (C) 2008 10gen Inc.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-07-28 00:36:47 +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-07-28 00:36:47 +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-07-28 00:36:47 +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/>.
|
|
|
|
*/
|
2008-07-28 19:51:39 +02:00
|
|
|
|
|
|
|
/* replication data overview
|
|
|
|
|
2008-12-29 02:28:49 +01:00
|
|
|
at the slave:
|
2008-07-29 23:54:54 +02:00
|
|
|
local.sources { host: ..., source: ..., syncedTo: ..., dbs: { ... } }
|
2008-07-28 23:52:44 +02:00
|
|
|
|
|
|
|
at the master:
|
|
|
|
local.oplog.$<source>
|
|
|
|
local.oplog.$main is the default
|
2008-07-28 19:51:39 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2009-04-24 00:01:24 +02:00
|
|
|
#include "pdfile.h"
|
|
|
|
#include "db.h"
|
|
|
|
#include "dbhelpers.h"
|
|
|
|
#include "query.h"
|
|
|
|
|
2008-12-01 03:00:54 +01:00
|
|
|
#include "../client/dbclient.h"
|
|
|
|
|
2009-04-24 00:01:24 +02:00
|
|
|
#include "../util/optime.h"
|
|
|
|
|
2009-01-14 23:09:51 +01:00
|
|
|
namespace mongo {
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
class DBClientConnection;
|
|
|
|
class DBClientCursor;
|
|
|
|
extern bool slave;
|
|
|
|
extern bool master;
|
2009-02-02 17:15:24 +01:00
|
|
|
|
2009-01-24 00:24:15 +01:00
|
|
|
bool cloneFrom(const char *masterHost, string& errmsg, const string& fromdb, bool logForReplication,
|
|
|
|
bool slaveOk, bool useReplAuth);
|
2008-08-15 19:59:22 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
/* A replication exception */
|
2009-02-06 22:21:49 +01:00
|
|
|
class SyncException : public DBException {
|
|
|
|
public:
|
|
|
|
virtual const char* what() const throw() { return "sync exception"; }
|
2009-01-15 16:17:11 +01:00
|
|
|
};
|
2009-04-23 20:44:05 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
/* A Source is a source from which we can pull (replicate) data.
|
|
|
|
stored in collection local.sources.
|
2008-07-28 19:51:39 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
Can be a group of things to replicate for several databases.
|
2008-07-29 23:54:54 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
{ host: ..., source: ..., syncedTo: ..., dbs: { ... } }
|
2008-10-10 22:55:21 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
'source' defaults to 'main'; support for multiple source names is
|
|
|
|
not done (always use main for now).
|
2008-12-29 02:28:49 +01:00
|
|
|
*/
|
2009-01-15 16:17:11 +01:00
|
|
|
class ReplSource {
|
|
|
|
bool resync(string db);
|
|
|
|
bool sync_pullOpLog();
|
2009-04-23 20:44:05 +02:00
|
|
|
void sync_pullOpLog_applyOperation(BSONObj& op, OpTime *localLogTail);
|
2009-01-23 16:17:29 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
auto_ptr<DBClientConnection> conn;
|
|
|
|
auto_ptr<DBClientCursor> cursor;
|
|
|
|
|
|
|
|
set<string> addDbNextPass;
|
2009-04-16 17:36:06 +02:00
|
|
|
set<string> incompleteCloneDbs;
|
2009-01-15 16:17:11 +01:00
|
|
|
|
|
|
|
ReplSource();
|
2009-03-18 18:45:32 +01:00
|
|
|
|
|
|
|
// returns the dummy ns used to do the drop
|
|
|
|
string resyncDrop( const char *db, const char *requester );
|
|
|
|
// returns true if connected on return
|
|
|
|
bool connect();
|
2009-04-10 00:50:29 +02:00
|
|
|
// returns possibly unowned id spec for the operation.
|
|
|
|
static BSONObj idForOp( const BSONObj &op, bool &mod );
|
2009-04-23 20:44:05 +02:00
|
|
|
static void updateSetsWithOp( const BSONObj &op );
|
2009-04-22 23:44:23 +02:00
|
|
|
// call without the db mutex
|
|
|
|
void syncToTailOfRemoteLog();
|
|
|
|
// call with the db mutex
|
|
|
|
void updateLastSavedLocalTs();
|
|
|
|
// call without the db mutex
|
|
|
|
void resetSlave();
|
|
|
|
// call with the db mutex
|
|
|
|
// returns false if the slave has been reset
|
2009-04-23 20:44:05 +02:00
|
|
|
bool updateSetsWithLocalOps( OpTime &localLogTail, bool unlock );
|
2009-04-22 23:44:23 +02:00
|
|
|
string ns() const { return string( "local.oplog.$" ) + sourceName(); }
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
public:
|
2009-03-04 21:57:35 +01:00
|
|
|
static void applyOperation(const BSONObj& op);
|
2009-01-15 16:17:11 +01:00
|
|
|
bool replacing; // in "replace mode" -- see CmdReplacePeer
|
|
|
|
bool paired; // --pair in use
|
|
|
|
string hostName; // ip addr or hostname plus optionally, ":<port>"
|
|
|
|
string _sourceName; // a logical source name.
|
|
|
|
string sourceName() const {
|
|
|
|
return _sourceName.empty() ? "main" : _sourceName;
|
|
|
|
}
|
|
|
|
string only; // only a certain db. note that in the sources collection, this may not be changed once you start replicating.
|
|
|
|
|
|
|
|
/* the last time point we have already synced up to. */
|
|
|
|
OpTime syncedTo;
|
2009-04-10 00:50:29 +02:00
|
|
|
OpTime lastSavedLocalTs_;
|
2009-01-15 16:17:11 +01:00
|
|
|
|
|
|
|
int nClonedThisPass;
|
|
|
|
|
2009-04-01 22:00:56 +02:00
|
|
|
typedef vector< shared_ptr< ReplSource > > SourceVector;
|
|
|
|
static void loadAll(SourceVector&);
|
2009-03-04 00:09:03 +01:00
|
|
|
explicit ReplSource(BSONObj);
|
2009-01-15 16:17:11 +01:00
|
|
|
bool sync();
|
|
|
|
void save(); // write ourself to local.sources
|
|
|
|
void resetConnection() {
|
|
|
|
cursor = auto_ptr<DBClientCursor>(0);
|
2009-01-23 20:25:16 +01:00
|
|
|
conn = auto_ptr<DBClientConnection>(0);
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// make a jsobj from our member fields of the form
|
|
|
|
// { host: ..., source: ..., syncedTo: ... }
|
|
|
|
BSONObj jsobj();
|
|
|
|
|
|
|
|
bool operator==(const ReplSource&r) const {
|
|
|
|
return hostName == r.hostName && sourceName() == r.sourceName();
|
|
|
|
}
|
2009-04-16 17:36:06 +02:00
|
|
|
operator string() const { return sourceName() + "@" + hostName; }
|
|
|
|
|
2009-02-04 19:22:02 +01:00
|
|
|
bool haveMoreDbsToSync() const { return !addDbNextPass.empty(); }
|
|
|
|
|
2009-02-02 17:15:24 +01:00
|
|
|
static bool throttledForceResyncDead( const char *requester );
|
|
|
|
static void forceResyncDead( const char *requester );
|
|
|
|
void forceResync( const char *requester );
|
2009-01-15 16:17:11 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Write operation to the log (local.oplog.$main)
|
|
|
|
"i" insert
|
|
|
|
"u" update
|
|
|
|
"d" delete
|
|
|
|
"c" db cmd
|
|
|
|
"db" declares presence of a database (ns is set to the db name + '.')
|
|
|
|
*/
|
2009-04-10 00:50:29 +02:00
|
|
|
void _logOp(const char *opstr, const char *ns, const char *logNs, const BSONObj& obj, BSONObj *patt, bool *b, const OpTime &ts);
|
2009-03-19 21:23:04 +01:00
|
|
|
void logOp(const char *opstr, const char *ns, const BSONObj& obj, BSONObj *patt = 0, bool *b = 0);
|
2009-01-14 23:09:51 +01:00
|
|
|
|
2009-04-24 00:01:24 +02:00
|
|
|
class MemIds {
|
|
|
|
public:
|
|
|
|
MemIds( const char *name ) {}
|
|
|
|
void reset() { imp_.clear(); }
|
|
|
|
bool get( const char *ns, const BSONObj &id ) { return imp_[ ns ].count( id ); }
|
|
|
|
void set( const char *ns, const BSONObj &id, bool val ) {
|
|
|
|
if ( val )
|
|
|
|
imp_[ ns ].insert( id );
|
|
|
|
else
|
|
|
|
imp_[ ns ].erase( id );
|
|
|
|
}
|
2009-04-24 00:26:42 +02:00
|
|
|
long long roughSize() const {
|
|
|
|
long long size = 0;
|
|
|
|
for( map< string, BSONObjSetDefaultOrder >::const_iterator i = imp_.begin();
|
|
|
|
i != imp_.end(); ++i )
|
|
|
|
for( BSONObjSetDefaultOrder::const_iterator j = i->second.begin();
|
|
|
|
j != i->second.end(); ++j )
|
|
|
|
size += sizeof( BSONObj );
|
|
|
|
return size;
|
|
|
|
}
|
2009-04-24 00:01:24 +02:00
|
|
|
private:
|
|
|
|
typedef map< string, BSONObjSetDefaultOrder > IdSets;
|
|
|
|
IdSets imp_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class DbIds {
|
|
|
|
public:
|
|
|
|
DbIds( const char * name ) : name_( name ) {}
|
|
|
|
void reset() {
|
|
|
|
dbcache c;
|
|
|
|
setClientTempNs( name_ );
|
|
|
|
Helpers::emptyCollection( name_ );
|
|
|
|
Helpers::ensureIndex( name_, BSON( "ns" << 1 << "id" << 1 ), "setIdx" );
|
|
|
|
}
|
|
|
|
bool get( const char *ns, const BSONObj &id ) {
|
|
|
|
dbcache c;
|
|
|
|
setClientTempNs( name_ );
|
|
|
|
BSONObj temp;
|
|
|
|
return Helpers::findOne( name_, key( ns, id ), temp );
|
|
|
|
}
|
|
|
|
void set( const char *ns, const BSONObj &id, bool val ) {
|
|
|
|
dbcache c;
|
|
|
|
setClientTempNs( name_ );
|
|
|
|
if ( val ) {
|
|
|
|
BSONObj temp;
|
|
|
|
if ( !Helpers::findOne( name_, key( ns, id ), temp ) ) {
|
|
|
|
BSONObj k = key( ns, id );
|
|
|
|
theDataFileMgr.insert( name_, k );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
deleteObjects( name_, key( ns, id ), true, false, false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
struct dbcache {
|
|
|
|
Database *database_;
|
|
|
|
const char *curNs_;
|
|
|
|
dbcache() : database_( database ), curNs_( curNs ) {}
|
|
|
|
~dbcache() {
|
|
|
|
database = database_;
|
|
|
|
curNs = curNs_;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
static BSONObj key( const char *ns, const BSONObj &id ) {
|
|
|
|
BSONObjBuilder b;
|
|
|
|
b << "ns" << ns;
|
|
|
|
b.appendAs( id.firstElement(), "id" );
|
|
|
|
return b.obj();
|
|
|
|
}
|
|
|
|
const char * name_;
|
|
|
|
};
|
|
|
|
|
|
|
|
class IdTracker {
|
|
|
|
public:
|
|
|
|
IdTracker() :
|
|
|
|
ids_( "local.temp.replIds" ),
|
|
|
|
modIds_( "local.temp.replModIds" ) {
|
|
|
|
}
|
|
|
|
void reset() {
|
|
|
|
ids_.reset();
|
|
|
|
modIds_.reset();
|
|
|
|
}
|
|
|
|
bool haveId( const char *ns, const BSONObj &id ) {
|
|
|
|
return ids_.get( ns, id );
|
|
|
|
}
|
|
|
|
bool haveModId( const char *ns, const BSONObj &id ) {
|
|
|
|
return modIds_.get( ns, id );
|
|
|
|
}
|
|
|
|
void haveId( const char *ns, const BSONObj &id, bool val ) {
|
|
|
|
ids_.set( ns, id, val );
|
|
|
|
}
|
|
|
|
void haveModId( const char *ns, const BSONObj &id, bool val ) {
|
|
|
|
modIds_.set( ns, id, val );
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
DbIds ids_;
|
|
|
|
DbIds modIds_;
|
|
|
|
};
|
|
|
|
|
2009-01-14 23:09:51 +01:00
|
|
|
} // namespace mongo
|