summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristina <kristina@10gen.com>2011-09-13 17:58:02 -0400
committerEliot Horowitz <eliot@10gen.com>2011-12-22 11:54:35 -0500
commit843bc2c58ec03d00479e5d7e20ad86e5e60b7078 (patch)
tree4b99f4408f35136f4491704e8d1adff0a492334a
parentd88037845bd73589a55441765a1fe6b2e6da9cfa (diff)
downloadmongo-843bc2c58ec03d00479e5d7e20ad86e5e60b7078.tar.gz
allow majority to be all nodes SERVER-3672
-rw-r--r--db/repl/rs_config.cpp23
-rw-r--r--db/repl/rs_config.h11
-rw-r--r--db/repl_block.cpp2
-rw-r--r--jstests/replsets/majority.js60
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();