diff options
author | Kristina Chodorow <kristina@10gen.com> | 2010-11-17 18:30:24 -0500 |
---|---|---|
committer | Kristina Chodorow <kristina@10gen.com> | 2010-11-17 18:30:24 -0500 |
commit | 05218bfa2730d6c0aff8f84aeb46139b928703e5 (patch) | |
tree | 1846070e345faa8acc92fe2c740d48fa6e756f19 /db/repl | |
parent | 4c11954523aeac6f3036df8f2fe4e9348c295a7f (diff) | |
download | mongo-05218bfa2730d6c0aff8f84aeb46139b928703e5.tar.gz |
lots of options for initial sync SERVER-1829
Diffstat (limited to 'db/repl')
-rw-r--r-- | db/repl/rs_config.cpp | 35 | ||||
-rw-r--r-- | db/repl/rs_config.h | 1 | ||||
-rw-r--r-- | db/repl/rs_initialsync.cpp | 84 |
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; } /** |