Browse files

SERVER-7498 chainingAllowed option for replication

  • Loading branch information...
1 parent e1cb581 commit d7fe5dc2d8f0cf6a95064bfe1ec457e8c4f66a9f @kchodorow kchodorow committed Nov 6, 2012
View
68 jstests/replsets/no_chaining.js
@@ -0,0 +1,68 @@
+
+function myprint( x ) {
+ print( "chaining output: " + x );
+}
+
+var replTest = new ReplSetTest({name: 'testSet', nodes: 3});
+var nodes = replTest.startSet();
+var hostnames = replTest.nodeList();
+replTest.initiate(
+ {
+ "_id" : "testSet",
+ "members" : [
+ {"_id" : 0, "host" : hostnames[0], "priority" : 2},
+ {"_id" : 1, "host" : hostnames[1]},
+ {"_id" : 2, "host" : hostnames[2]}
+ ],
+ "settings" : {
+ "chainingAllowed" : false
+ }
+ }
+);
+
+var master = replTest.getMaster();
+replTest.awaitReplication();
+
+
+var breakNetwork = function() {
+ replTest.bridge();
+ replTest.partition(0, 2);
+ master = replTest.getMaster();
+};
+
+var checkNoChaining = function() {
+ master.getDB("test").foo.insert({x:1});
+
+ assert.soon(
+ function() {
+ return nodes[1].getDB("test").foo.findOne() != null;
+ }
+ );
+
+ var endTime = (new Date()).getTime()+10;
+ while ((new Date()).getTime() < endTime) {
+ assert(nodes[2].getDB("test").foo.findOne() == null,
+ 'Check that 2 does not catch up');
+ }
+};
+
+var forceSync = function() {
+ assert.soon(
+ function() {
+ nodes[2].getDB("admin").runCommand({replSetSyncFrom : hostnames[1]});
+ return nodes[2].getDB("test").foo.findOne() != null;
+ },
+ 'Check force sync still works'
+ );
+};
+
+if (!_isWindows()) {
+ print("break the network so that node 2 cannot replicate");
+ breakNetwork();
+
+ print("make sure chaining is not happening");
+ checkNoChaining();
+
+ print("check that forcing sync target still works");
+ forceSync();
+}
View
7 src/mongo/db/repl/rs.cpp
@@ -549,6 +549,13 @@ namespace mongo {
additive = false;
}
+ // If we are changing chaining rules, we don't want this to be an additive reconfig so that
+ // the primary can step down and the sync targets change.
+ // TODO: This can be removed once SERVER-5208 is fixed.
+ if (reconf && config().chainingAllowed() != c.chainingAllowed()) {
+ additive = false;
+ }
+
_cfg = new ReplSetConfig(c);
dassert( &config() == _cfg ); // config() is same thing but const, so we use that when we can for clarity below
verify( config().ok() );
View
19 src/mongo/db/repl/rs_config.cpp
@@ -130,6 +130,11 @@ namespace mongo {
}
if( !getLastErrorDefaults.isEmpty() )
settings << "getLastErrorDefaults" << getLastErrorDefaults;
+
+ if (!_chainingAllowed) {
+ settings << "chainingAllowed" << _chainingAllowed;
+ }
+
b << "settings" << settings.obj();
}
@@ -556,18 +561,28 @@ namespace mongo {
ho.check();
try { getLastErrorDefaults = settings["getLastErrorDefaults"].Obj().copy(); }
catch(...) { }
+
+ // If the config explicitly sets chaining to false, turn it off.
+ if (settings.hasField("chainingAllowed") &&
+ !settings["chainingAllowed"].trueValue()) {
+ _chainingAllowed = false;
+ }
}
// figure out the majority for this config
setMajority();
}
+ bool ReplSetConfig::chainingAllowed() const {
+ return _chainingAllowed;
+ }
+
static inline void configAssert(bool expr) {
uassert(13122, "bad repl set config?", expr);
}
ReplSetConfig::ReplSetConfig(BSONObj cfg, bool force) :
- _ok(false),_majority(-1)
+ _ok(false),_chainingAllowed(true),_majority(-1)
{
_constructed = false;
clear();
@@ -583,7 +598,7 @@ namespace mongo {
}
ReplSetConfig::ReplSetConfig(const HostAndPort& h) :
- _ok(false),_majority(-1)
+ _ok(false),_chainingAllowed(true),_majority(-1)
{
LOG(2) << "ReplSetConfig load " << h.toString() << rsLog;
View
12 src/mongo/db/repl/rs_config.h
@@ -153,8 +153,20 @@ namespace mongo {
int getMajority() const;
bool _constructed;
+
+ /**
+ * Returns if replication chaining is allowed.
+ */
+ bool chainingAllowed() const;
+
private:
bool _ok;
+
+ /**
+ * If replication can be chained. If chaining is disallowed, it can still be explicitly
+ * enabled via the replSetSyncFrom command, but it will not happen automatically.
+ */
+ bool _chainingAllowed;
int _majority;
void from(BSONObj);
View
11 src/mongo/db/repl/rs_initialsync.cpp
@@ -150,14 +150,21 @@ namespace mongo {
buildIndexes = myConfig().buildIndexes;
}
+ Member* primary = const_cast<Member*>(box.getPrimary());
+
+ // If we are only allowed to sync from the primary, return that
+ if (!config().chainingAllowed()) {
+ // Returns NULL if we cannot reach the primary
+ return primary;
+ }
+
// find the member with the lowest ping time that has more data than me
// Find primary's oplog time. Reject sync candidates that are more than
// MAX_SLACK_TIME seconds behind.
OpTime primaryOpTime;
static const unsigned maxSlackDurationSeconds = 10 * 60; // 10 minutes
- const Member* primary = box.getPrimary();
- if (primary)
+ if (primary)
primaryOpTime = primary->hbinfo().opTime;
else
// choose a time that will exclude no candidates, since we don't see a primary

0 comments on commit d7fe5dc

Please sign in to comment.