diff options
author | Kristina <kristina@10gen.com> | 2011-09-13 17:58:02 -0400 |
---|---|---|
committer | Eliot Horowitz <eliot@10gen.com> | 2011-12-22 11:54:35 -0500 |
commit | 843bc2c58ec03d00479e5d7e20ad86e5e60b7078 (patch) | |
tree | 4b99f4408f35136f4491704e8d1adff0a492334a | |
parent | d88037845bd73589a55441765a1fe6b2e6da9cfa (diff) | |
download | mongo-843bc2c58ec03d00479e5d7e20ad86e5e60b7078.tar.gz |
allow majority to be all nodes SERVER-3672
-rw-r--r-- | db/repl/rs_config.cpp | 23 | ||||
-rw-r--r-- | db/repl/rs_config.h | 11 | ||||
-rw-r--r-- | db/repl_block.cpp | 2 | ||||
-rw-r--r-- | jstests/replsets/majority.js | 60 |
4 files changed, 83 insertions, 13 deletions
diff --git a/db/repl/rs_config.cpp b/db/repl/rs_config.cpp index 13352b19783..c451d468105 100644 --- a/db/repl/rs_config.cpp +++ b/db/repl/rs_config.cpp @@ -296,6 +296,26 @@ namespace mongo { _ok = false; } + void ReplSetConfig::setMajority() { + int total = members.size(); + int nonArbiters = total; + int strictMajority = total/2+1; + + for (vector<MemberCfg>::iterator it = members.begin(); it < members.end(); it++) { + if ((*it).arbiterOnly) { + nonArbiters--; + } + } + + // majority should be all "normal" members if we have something like 4 + // arbiters & 3 normal members + _majority = (strictMajority > nonArbiters) ? nonArbiters : strictMajority; + } + + int ReplSetConfig::getMajority() const { + return _majority; + } + void ReplSetConfig::checkRsConfig() const { uassert(13132, "nonmatching repl set name in _id field; check --replSet command line", @@ -533,6 +553,9 @@ namespace mongo { try { getLastErrorDefaults = settings["getLastErrorDefaults"].Obj().copy(); } catch(...) { } } + + // figure out the majority for this config + setMajority(); } static inline void configAssert(bool expr) { diff --git a/db/repl/rs_config.h b/db/repl/rs_config.h index b22b61e5318..da6552a0d27 100644 --- a/db/repl/rs_config.h +++ b/db/repl/rs_config.h @@ -135,9 +135,20 @@ namespace mongo { BSONObj asBson() const; + /** + * Getter and setter for _majority. This is almost always + * members.size()/2+1, but can be the number of non-arbiter members if + * there are more arbiters than non-arbiters (writing to 3 out of 7 + * servers is safe if 4 of the servers are arbiters). + */ + void setMajority(); + int getMajority() const; + bool _constructed; private: bool _ok; + int _majority; + void from(BSONObj); void clear(); diff --git a/db/repl_block.cpp b/db/repl_block.cpp index dcac1218199..840bbb2730e 100644 --- a/db/repl_block.cpp +++ b/db/repl_block.cpp @@ -175,7 +175,7 @@ namespace mongo { if (wStr == "majority") { // use the entire set, including arbiters, to prevent writing // to a majority of the set but not a majority of voters - return replicatedToNum(op, theReplSet->config().members.size()/2+1); + return replicatedToNum(op, theReplSet->config().getMajority()); } map<string,ReplSetConfig::TagRule*>::const_iterator it = theReplSet->config().rules.find(wStr); diff --git a/jstests/replsets/majority.js b/jstests/replsets/majority.js index 6df1a41c694..5bb3cde33f0 100644 --- a/jstests/replsets/majority.js +++ b/jstests/replsets/majority.js @@ -1,4 +1,11 @@ -var num = 5; +var testInsert = function() { + master.getDB("foo").bar.insert({x:1}); + var result = master.getDB("foo").runCommand({getLastError:1, w:"majority", wtimeout:timeout}); + printjson(result); + return result; +}; + +var num = 7; var host = getHostName(); var name = "tags"; var timeout = 10000; @@ -6,28 +13,57 @@ var timeout = 10000; var replTest = new ReplSetTest( {name: name, nodes: num, startPort:31000} ); var nodes = replTest.startSet(); var port = replTest.ports; -replTest.initiate({_id : name, members : +var config = {_id : name, members : [ {_id:0, host : host+":"+port[0], priority : 2}, - {_id:1, host : host+":"+port[1]}, + {_id:1, host : host+":"+port[1], votes : 3}, {_id:2, host : host+":"+port[2]}, {_id:3, host : host+":"+port[3], arbiterOnly : true}, {_id:4, host : host+":"+port[4], arbiterOnly : true}, + {_id:5, host : host+":"+port[5], arbiterOnly : true}, + {_id:6, host : host+":"+port[6], arbiterOnly : true}, ], - }); + }; +replTest.initiate(config); replTest.awaitReplication(); -replTest.bridge(); - -var testInsert = function() { - master.getDB("foo").bar.insert({x:1}); - var result = master.getDB("foo").runCommand({getLastError:1, w:"majority", wtimeout:timeout}); - printjson(result); - return result; -}; var master = replTest.getMaster(); +print("try taking down 4 arbiters"); +replTest.stop(3); +replTest.stop(4); + +replTest.stop(6); +replTest.remove(6); +replTest.stop(5); +replTest.remove(5); + +print("should still be able to write to a majority"); +assert.eq(testInsert().err, null); + +print("start up some of the arbiters again"); +replTest.restart(3); +replTest.restart(4); + +print("remove 2 of the arbiters"); +config.version = 2; +config.members.pop(); +config.members.pop(); + +try { + master.getDB("admin").runCommand({replSetReconfig : config}); +} +catch (e) { + print("reconfig error: "+e); +} + +replTest.awaitReplication(); + +replTest.bridge(); + +master = replTest.getMaster(); + print("get back in the groove"); testInsert(); replTest.awaitReplication(); |