summaryrefslogtreecommitdiff
path: root/db/repl
diff options
context:
space:
mode:
authorKristina Chodorow <kristina@10gen.com>2010-11-17 18:30:24 -0500
committerKristina Chodorow <kristina@10gen.com>2010-11-17 18:30:24 -0500
commit05218bfa2730d6c0aff8f84aeb46139b928703e5 (patch)
tree1846070e345faa8acc92fe2c740d48fa6e756f19 /db/repl
parent4c11954523aeac6f3036df8f2fe4e9348c295a7f (diff)
downloadmongo-05218bfa2730d6c0aff8f84aeb46139b928703e5.tar.gz
lots of options for initial sync SERVER-1829
Diffstat (limited to 'db/repl')
-rw-r--r--db/repl/rs_config.cpp35
-rw-r--r--db/repl/rs_config.h1
-rw-r--r--db/repl/rs_initialsync.cpp84
3 files changed, 100 insertions, 20 deletions
diff --git a/db/repl/rs_config.cpp b/db/repl/rs_config.cpp
index f454579c451..172d38ca4dc 100644
--- a/db/repl/rs_config.cpp
+++ b/db/repl/rs_config.cpp
@@ -138,6 +138,32 @@ namespace mongo {
uassert(13438, "bad slaveDelay value", slaveDelay >= 0 && slaveDelay <= 3600 * 24 * 366);
uassert(13439, "priority must be 0 when hidden=true", priority == 0 || !hidden);
uassert(13477, "priority must be 0 when buildIndexes=false", buildIndexes || priority == 0);
+
+ if (!initialSync.isEmpty()) {
+ static const string legal[] = {"state", "name", "_id","optime"};
+ static const set<string> legals(legal, legal + 4);
+ assertOnlyHas(initialSync, legals);
+
+ if (initialSync.hasElement("state")) {
+ uassert(13525, "initialSync source state must be 1 or 2",
+ initialSync["state"].isNumber() &&
+ (initialSync["state"].Number() == 1 ||
+ initialSync["state"].Number() == 2));
+ }
+ if (initialSync.hasElement("name")) {
+ uassert(13526, "initialSync source name must be a string",
+ initialSync["name"].type() == mongo::String);
+ }
+ if (initialSync.hasElement("_id")) {
+ uassert(13527, "initialSync source _id must be a number",
+ initialSync["_id"].isNumber());
+ }
+ if (initialSync.hasElement("optime")) {
+ uassert(13528, "initialSync source optime must be a timestamp",
+ initialSync["optime"].type() == mongo::Timestamp ||
+ initialSync["optime"].type() == mongo::Date);
+ }
+ }
}
/** @param o old config
@@ -251,8 +277,10 @@ namespace mongo {
BSONObj mobj = members[i].Obj();
MemberCfg m;
try {
- static const string legal[] = {"_id","votes","priority","host","hidden","slaveDelay","arbiterOnly","buildIndexes","tags"};
- static const set<string> legals(legal, legal + 8);
+ static const string legal[] =
+ {"_id","votes","priority","host", "hidden","slaveDelay",
+ "arbiterOnly","buildIndexes","tags","initialSync"};
+ static const set<string> legals(legal, legal + 10);
assertOnlyHas(mobj, legals);
try {
@@ -286,6 +314,9 @@ namespace mongo {
for( unsigned i = 0; i < v.size(); i++ )
m.tags.insert( v[i].String() );
}
+ if( mobj.hasElement("initialSync")) {
+ m.initialSync = mobj["initialSync"].Obj();
+ }
m.check();
}
catch( const char * p ) {
diff --git a/db/repl/rs_config.h b/db/repl/rs_config.h
index 13b8c399c37..aef32389832 100644
--- a/db/repl/rs_config.h
+++ b/db/repl/rs_config.h
@@ -51,6 +51,7 @@ namespace mongo {
bool hidden; /* if set, don't advertise to drives in isMaster. for non-primaries (priority 0) */
bool buildIndexes; /* if false, do not create any non-_id indexes */
set<string> tags; /* tagging for data center, rack, etc. */
+ BSONObj initialSync; /* directions for initial sync source */
void check() const; /* check validity, assert if not. */
BSONObj asBson() const;
diff --git a/db/repl/rs_initialsync.cpp b/db/repl/rs_initialsync.cpp
index 92b6c6c9b97..46430bae004 100644
--- a/db/repl/rs_initialsync.cpp
+++ b/db/repl/rs_initialsync.cpp
@@ -104,32 +104,80 @@ namespace mongo {
}
/**
- * Choose a member to sync from. Prefers a secondary, if available.
+ * Choose a member to sync from.
*
- * TODO: make a config setting like "cloneFromPrimary" or something to force
- * machines to clone from the primary. We might want to integrate this with
- * tags functionality, if we only want it to be able to clone from certain
- * machines.
+ * The initalSync option is an object with 1 k/v pair:
+ *
+ * "state" : 1|2
+ * "name" : "host"
+ * "_id" : N
+ * "optime" : t
+ *
+ * All except optime are exact matches. "optime" will find a secondary with
+ * an optime >= to the optime given.
*/
const Member* ReplSetImpl::getMemberToSyncTo() {
- for( Member *m = head(); m; m = m->next() ) {
- if (m->hbinfo().up() && m->state() == MemberState::RS_SECONDARY) {
- sethbmsg( str::stream() << "syncing to secondary: " << m->fullName(), 0);
- return const_cast<Member*>(m);
- }
- }
+ BSONObj sync = myConfig().initialSync;
+ bool secondaryOnly = false, isOpTime = false;
+ char *name = 0;
+ int id = -1;
+ OpTime optime;
- // can't find secondary, try primary
StateBox::SP sp = box.get();
assert( !sp.state.primary() ); // wouldn't make sense if we were.
- // we just checked in _syncDoInitialSync, but we could have lost a
- // primary since then
- if (!sp.primary) {
- return 0;
+ // if it exists, we've already checked that these fields are valid in
+ // rs_config.cpp
+ if ( !sync.isEmpty() ) {
+ if (sync.hasElement("state")) {
+ if (sync["state"].Number() == 1) {
+ if (sp.primary) {
+ sethbmsg( str::stream() << "syncing to primary: " << sp.primary->fullName(), 0);
+ return const_cast<Member*>(sp.primary);
+ }
+ else {
+ sethbmsg("couldn't clone from primary");
+ return NULL;
+ }
+ }
+ else {
+ secondaryOnly = true;
+ }
+ }
+ if (sync.hasElement("name")) {
+ name = (char*)sync["name"].valuestr();
+ }
+ if (sync.hasElement("_id")) {
+ id = sync["_id"].Number();
+ }
+ if (sync.hasElement("optime")) {
+ isOpTime = true;
+ optime = sync["optime"]._opTime();
+ }
}
- sethbmsg( str::stream() << "syncing to primary: " << sp.primary->fullName(), 0);
- return const_cast<Member*>(sp.primary);
+
+ for( Member *m = head(); m; m = m->next() ) {
+ if (!m->hbinfo().up() ||
+ (m->state() != MemberState::RS_SECONDARY &&
+ m->state() != MemberState::RS_PRIMARY) ||
+ (secondaryOnly && m->state() != MemberState::RS_SECONDARY) ||
+ (id != -1 && (int)m->id() != id) ||
+ (name != 0 && strcmp(name, m->fullName().c_str()) != 0) ||
+ (isOpTime && optime >= m->hbinfo().opTime)) {
+ continue;
+ }
+
+ sethbmsg( str::stream() << "syncing to: " << m->fullName(), 0);
+ return const_cast<Member*>(m);
+ }
+
+ sethbmsg( str::stream() << "couldn't find a member matching the sync criteria: " <<
+ "\nstate? " << (secondaryOnly ? "2" : "none") <<
+ "\nname? " << (name ? name : "none") <<
+ "\n_id? " << id <<
+ "\noptime? " << optime.toStringPretty() );
+
+ return NULL;
}
/**