diff options
author | Antonin Kral <a.kral@bobek.cz> | 2011-03-17 00:07:52 +0100 |
---|---|---|
committer | Antonin Kral <a.kral@bobek.cz> | 2011-03-17 00:07:52 +0100 |
commit | 98b8b639326ab4c89eed73739d9903993c4c8959 (patch) | |
tree | 0462df078bf740093774d033b75f0ea24a31fa97 /jstests/replsets | |
parent | f5d6e97ca8d2f3e7c4cdd5c9afbf8e756ef65bc2 (diff) | |
parent | 582fc32574a3b158c81e49cb00e6ae59205e66ba (diff) | |
download | mongodb-98b8b639326ab4c89eed73739d9903993c4c8959.tar.gz |
Merge commit 'upstream/1.8.0
Diffstat (limited to 'jstests/replsets')
33 files changed, 2739 insertions, 580 deletions
diff --git a/jstests/replsets/auth1.js b/jstests/replsets/auth1.js new file mode 100644 index 0000000..4945869 --- /dev/null +++ b/jstests/replsets/auth1.js @@ -0,0 +1,184 @@ +// check replica set authentication + +load("jstests/replsets/rslib.js"); + +var name = "rs_auth1"; +var port = allocatePorts(4); +var path = "jstests/replsets/"; + + +print("reset permissions"); +run("chmod", "644", path+"key1"); +run("chmod", "644", path+"key2"); + + +print("try starting mongod"); +var m = runMongoProgram( "mongod", "--keyFile", path+"key1", "--port", port[0], "--dbpath", "/data/db/" + name); + + +print("should fail with wrong permissions"); +assert.eq(m, 2, "mongod should exit w/ 2: permissions too open"); +stopMongod(port[0]); + + +print("change permissions on #1 & #2"); +run("chmod", "600", path+"key1"); +run("chmod", "600", path+"key2"); + + +print("add a user to server0: foo"); +m = startMongodTest( port[0], name+"-0", 0 ); +m.getDB("admin").addUser("foo", "bar"); +m.getDB("test").addUser("bar", "baz"); +print("make sure user is written before shutting down"); +m.getDB("test").getLastError(); +stopMongod(port[0]); + + +print("start up rs"); +var rs = new ReplSetTest({"name" : name, "nodes" : 3, "startPort" : port[0]}); +m = rs.restart(0, {"keyFile" : path+"key1"}); +var s = rs.start(1, {"keyFile" : path+"key1"}); +var s2 = rs.start(2, {"keyFile" : path+"key1"}); + +var result = m.getDB("admin").auth("foo", "bar"); +assert.eq(result, 1, "login failed"); +result = m.getDB("admin").runCommand({replSetInitiate : rs.getReplSetConfig()}); +assert.eq(result.ok, 1, "couldn't initiate: "+tojson(result)); + +var master = rs.getMaster().getDB("test"); +wait(function() { + var status = master.adminCommand({replSetGetStatus:1}); + return status.members && status.members[1].state == 2 && status.members[2].state == 2; + }); + +master.foo.insert({x:1}); +master.runCommand({getlasterror:1, w:3, wtimeout:60000}); + + +print("try some legal and illegal reads"); +var r = master.foo.findOne(); +assert.eq(r.x, 1); + +s.setSlaveOk(); +slave = s.getDB("test"); + +function doQueryOn(p) { + var err = {}; + try { + r = p.foo.findOne(); + } + catch(e) { + if (typeof(JSON) != "undefined") { + err = JSON.parse(e.substring(6)); + } + else if (e.indexOf("10057") > 0) { + err.code = 10057; + } + } + assert.eq(err.code, 10057); +}; + +doQueryOn(slave); +master.adminCommand({logout:1}); +doQueryOn(master); + + +result = slave.auth("bar", "baz"); +assert.eq(result, 1); + +r = slave.foo.findOne(); +assert.eq(r.x, 1); + + +print("add some data"); +master.auth("bar", "baz"); +for (var i=0; i<1000; i++) { + master.foo.insert({x:i, foo : "bar"}); +} +master.runCommand({getlasterror:1, w:3, wtimeout:60000}); + + +print("fail over"); +rs.stop(0); + +wait(function() { + function getMaster(s) { + var result = s.getDB("admin").runCommand({isMaster: 1}); + printjson(result); + if (result.ismaster) { + master = s.getDB("test"); + return true; + } + return false; + } + + if (getMaster(s) || getMaster(s2)) { + return true; + } + return false; + }); + + +print("add some more data 1"); +master.auth("bar", "baz"); +for (var i=0; i<1000; i++) { + master.foo.insert({x:i, foo : "bar"}); +} +master.runCommand({getlasterror:1, w:3, wtimeout:60000}); + + +print("resync"); +rs.restart(0); + + +print("add some more data 2"); +for (var i=0; i<1000; i++) { + master.foo.insert({x:i, foo : "bar"}); +} +master.runCommand({getlasterror:1, w:3, wtimeout:60000}); + + +print("add member with wrong key"); +var conn = new MongodRunner(port[3], "/data/db/"+name+"-3", null, null, ["--replSet","rs_auth1","--rest","--oplogSize","2", "--keyFile", path+"key2"], {no_bind : true}); +conn.start(); + + +master.getSisterDB("admin").auth("foo", "bar"); +var config = master.getSisterDB("local").system.replset.findOne(); +config.members.push({_id : 3, host : getHostName()+":"+port[3]}); +config.version++; +try { + master.adminCommand({replSetReconfig:config}); +} +catch (e) { + print("error: "+e); +} +reconnect(master); +master.getSisterDB("admin").auth("foo", "bar"); + + +print("shouldn't ever sync"); +for (var i = 0; i<30; i++) { + print("iteration: " +i); + var results = master.adminCommand({replSetGetStatus:1}); + printjson(results); + assert(results.members[3].state != 2); + sleep(1000); +} + + +print("stop member"); +stopMongod(port[3]); + + +print("start back up with correct key"); +conn = new MongodRunner(port[3], "/data/db/"+name+"-3", null, null, ["--replSet","rs_auth1","--rest","--oplogSize","2", "--keyFile", path+"key1"], {no_bind : true}); +conn.start(); + +wait(function() { + var results = master.adminCommand({replSetGetStatus:1}); + printjson(results); + return results.members[3].state == 2; + }); + diff --git a/jstests/replsets/buildindexes.js b/jstests/replsets/buildindexes.js new file mode 100644 index 0000000..76de797 --- /dev/null +++ b/jstests/replsets/buildindexes.js @@ -0,0 +1,86 @@ +doTest = function( signal ) { + + var name = "buildIndexes"; + var host = getHostName(); + + var replTest = new ReplSetTest( {name: name, nodes: 3} ); + + var nodes = replTest.startSet(); + + var config = replTest.getReplSetConfig(); + config.members[2].priority = 0; + config.members[2].buildIndexes = false; + + replTest.initiate(config); + + var master = replTest.getMaster().getDB(name); + var slaveConns = replTest.liveNodes.slaves; + var slave = []; + for (var i in slaveConns) { + slaveConns[i].setSlaveOk(); + slave.push(slaveConns[i].getDB(name)); + } + replTest.awaitReplication(); + + print("creating an index on x"); + master.x.ensureIndex({y : 1}); + printjson(master.x.stats()); + + for (var i=0; i<100; i++) { + master.x.insert({x:1,y:"abc",c:1}); + } + + replTest.awaitReplication(); + + printjson(slave[0].runCommand({count: "x"})); + var ns = master.x+""; + print("namespace: "+ns); + + // can't query system.indexes from slave, so we'll look at coll.stats() + printjson(slave[0].adminCommand({replSetGetStatus:1})); + printjson(slave[0].getSisterDB("local").system.replset.findOne()); + printjson(master.stats()); + printjson(slave[0].stats()); + printjson(slave[1].stats()); + printjson(master.x.stats()); + printjson(slave[0].x.stats()); + printjson(slave[1].x.stats()); + print("sleeping"); + sleep(20000); + var indexes = slave[0].stats().indexes; + assert.eq(indexes, 2, 'number of indexes'); + + indexes = slave[1].stats().indexes; + assert.eq(indexes, 1); + + + indexes = slave[0].x.stats().indexSizes; + printjson(indexes); + + var count = 0; + for (var i in indexes) { + count++; + if (i == "_id_") { + continue; + } + print(i); + print(i.match(/y_/)); + assert(i.match(/y_/)); + } + + assert.eq(count, 2); + + indexes = slave[1].x.stats().indexSizes; + printjson(indexes); + + count = 0; + for (var i in indexes) { + count++; + } + + assert.eq(count, 1); + + replTest.stopSet(15); +} + +doTest(15); diff --git a/jstests/replsets/cloneDb.js b/jstests/replsets/cloneDb.js new file mode 100644 index 0000000..6d2d0f3 --- /dev/null +++ b/jstests/replsets/cloneDb.js @@ -0,0 +1,52 @@ +// Test for cloning a db from a replica set [SERVER-1643] -Tony + +load('jstests/libs/grid.js') + +doTest = function( signal ) { + + var N = 2000 + + // ~1KB string + var Text = '' + for (var i = 0; i < 40; i++) + Text += 'abcdefghijklmnopqrstuvwxyz' + + // Create replica set + var repset = new ReplicaSet ('testSet', 3) .begin() + var master = repset.getMaster() + var db1 = master.getDB('test') + + // Insert data + for (var i = 0; i < N; i++) { + db1['foo'].insert({x: i, text: Text}) + db1.getLastError(2) // wait to be copied to at least one secondary + } + + // Create single server + var solo = new Server ('singleTarget') + var soloConn = solo.begin() + var db2 = soloConn.getDB('test') + + // Clone db from replica set to single server + db2.cloneDatabase (repset.getURL()) + + // Confirm clone worked + assert.eq (Text, db2['foo'] .findOne({x: N-1}) ['text'], 'cloneDatabase failed (test1)') + + // Now test the reverse direction + db1 = master.getDB('test2') + db2 = soloConn.getDB('test2') + for (var i = 0; i < N; i++) { + db2['foo'].insert({x: i, text: Text}) + db2.getLastError() + } + db1.cloneDatabase (solo.host()) + assert.eq (Text, db2['foo'] .findOne({x: N-1}) ['text'], 'cloneDatabase failed (test2)') + + // Shut down replica set and single server + solo.end() + repset.stopSet( signal ) +} + +doTest( 15 );
+print("replsets/cloneDb.js SUCCESS");
diff --git a/jstests/replsets/config1.js b/jstests/replsets/config1.js new file mode 100644 index 0000000..748ce8f --- /dev/null +++ b/jstests/replsets/config1.js @@ -0,0 +1,21 @@ +doTest = function( signal ) { + var name = 'config1'; + + var replTest = new ReplSetTest( {name: name, nodes: 3} ); + var nodes = replTest.startSet(); + + var config = replTest.getReplSetConfig(); + config.settings = {"heartbeatSleep" : .5, heartbeatTimeout : .8}; + + replTest.initiate(config); + + // Call getMaster to return a reference to the node that's been + // elected master. + var master = replTest.getMaster(); + + config = master.getDB("local").system.replset.findOne(); + assert.eq(config.settings.heartbeatSleep, .5); + assert.eq(config.settings.heartbeatTimeout, .8); +}; + +doTest(15); diff --git a/jstests/replsets/fastsync.js b/jstests/replsets/fastsync.js new file mode 100644 index 0000000..d7c3905 --- /dev/null +++ b/jstests/replsets/fastsync.js @@ -0,0 +1,117 @@ +/* + * 1. insert 100000 objects + * 2. export to two dbpaths + * 3. add one node w/fastsync + * 4. check that we never get "errmsg" : "initial sync cloning db: whatever" + * 5. check writes are replicated + */ + +var w = 0; +var wait = function(f) { + w++; + var n = 0; + while (!f()) { + if( n % 4 == 0 ) + print("toostale.js waiting " + w); + if (++n == 4) { + print("" + f); + } + assert(n < 200, 'tried 200 times, giving up'); + sleep(1000); + } +} + +var reconnect = function(a) { + wait(function() { + try { + a.getDB("foo").bar.stats(); + return true; + } catch(e) { + print(e); + return false; + } + }); +}; + +ports = allocatePorts( 3 ); + +var basename = "jstests_fastsync"; +var basePath = "/data/db/" + basename; +var hostname = getHostName(); + +var pargs = new MongodRunner( ports[ 0 ], basePath + "-p", false, false, + ["--replSet", basename, "--oplogSize", 2], + {no_bind : true} ); +p = pargs.start(); + +var admin = p.getDB("admin"); +var foo = p.getDB("foo"); +var local = p.getDB("local"); + +var config = {_id : basename, members : [{_id : 0, host : hostname+":"+ports[0]}]}; +printjson(config); +var result = admin.runCommand({replSetInitiate : config}); +print("result:"); +printjson(result); + +var count = 0; +while (count < 10 && result.ok != 1) { + count++; + sleep(2000); + result = admin.runCommand({replSetInitiate : config}); +} + +assert(result.ok, tojson(result)); +assert.soon(function() { return admin.runCommand({isMaster:1}).ismaster; }); + +print("1"); +for (var i=0; i<100000; i++) { + foo.bar.insert({date : new Date(), x : i, str : "all the talk on the market"}); +} +print("total in foo: "+foo.bar.count()); + + +print("2"); +admin.runCommand( {fsync:1,lock:1} ); +copyDbpath( basePath + "-p", basePath + "-s" ); +admin.$cmd.sys.unlock.findOne(); + + +print("3"); +var sargs = new MongodRunner( ports[ 1 ], basePath + "-s", false, false, + ["--replSet", basename, "--fastsync", + "--oplogSize", 2], {no_bind : true} ); +var reuseData = true; +sargs.start(reuseData); + +config = local.system.replset.findOne(); +config.version++; +config.members.push({_id:1, host:hostname+":"+ports[1]}); + +result = admin.runCommand({replSetReconfig : config}); +assert(result.ok, "reconfig worked"); +reconnect(p); + +print("4"); +var status = admin.runCommand({replSetGetStatus : 1}); +var count = 0; +while (status.members[1].state != 2 && count < 200) { + print("not a secondary yet"); + if (count % 10 == 0) { + printjson(status); + } + assert(!status.members[1].errmsg || !status.members[1].errmsg.match("^initial sync cloning db")); + + sleep(1000); + + // disconnection could happen here + try { + status = admin.runCommand({replSetGetStatus : 1}); + } + catch (e) { + print(e); + } + count++; +} + +assert.eq(status.members[1].state, 2); diff --git a/jstests/replsets/getlasterror_w2.js b/jstests/replsets/getlasterror_w2.js new file mode 100644 index 0000000..795e667 --- /dev/null +++ b/jstests/replsets/getlasterror_w2.js @@ -0,0 +1,36 @@ +// BUG: [SERVER-1768] replica set getlasterror {w: 2} after 2000 +// inserts hangs while secondary servers log "replSet error RS102 too stale to catch up" every once in a while + +function newReplicaSet (name, numServers) { + var rs = new ReplSetTest({name: name, nodes: numServers}) + rs.startSet() + rs.initiate() + rs.awaitReplication() + return rs +} + +function go() { +var N = 2000 + +// ~1KB string +var Text = '' +for (var i = 0; i < 40; i++) + Text += 'abcdefghijklmnopqrstuvwxyz' + +// Create replica set of 3 servers +var repset = newReplicaSet('repset', 3) +var conn = repset.getMaster() +var db = conn.getDB('test') + +// Add data to it +for (var i = 0; i < N; i++) + db['foo'].insert({x: i, text: Text}) + +// wait to be copied to at least one secondary (BUG hangs here) +db.getLastError(2) + +print('getlasterror_w2.js SUCCESS') +} + +// turn off until fixed +//go(); diff --git a/jstests/replsets/groupAndMapReduce.js b/jstests/replsets/groupAndMapReduce.js new file mode 100644 index 0000000..539fe44 --- /dev/null +++ b/jstests/replsets/groupAndMapReduce.js @@ -0,0 +1,105 @@ +doTest = function( signal ) { + + // Test basic replica set functionality. + // -- Replication + // -- Failover + + // Replica set testing API + // Create a new replica set test. Specify set name and the number of nodes you want. + var replTest = new ReplSetTest( {name: 'testSet', nodes: 3} ); + + // call startSet() to start each mongod in the replica set + // this returns a list of nodes + var nodes = replTest.startSet(); + + // Call initiate() to send the replSetInitiate command + // This will wait for initiation + replTest.initiate(); + + // Call getMaster to return a reference to the node that's been + // elected master. + var master = replTest.getMaster(); + + // save some records + var len = 100 + for (var i = 0; i < len; ++i) { + master.getDB("foo").foo.save({a: i}); + } + + // This method will check the oplogs of the master + // and slaves in the set and wait until the change has replicated. + replTest.awaitReplication(); + print("Sleeping 10s for slaves to go to secondary state"); + sleep(10000); + + slaves = replTest.liveNodes.slaves; + assert( slaves.length == 2, "Expected 2 slaves but length was " + slaves.length ); + slaves.forEach(function(slave) { + // try to read from slave + slave.slaveOk = true; + var count = slave.getDB("foo").foo.count(); + printjson( count ); + assert.eq( len , count , "slave count wrong: " + slave ); + + print("Doing a findOne to verify we can get a row"); + var one = slave.getDB("foo").foo.findOne(); + printjson(one); + +// stats = slave.getDB("foo").adminCommand({replSetGetStatus:1}); +// printjson(stats); + + print("Calling group() with slaveOk=true, must succeed"); + slave.slaveOk = true; + count = slave.getDB("foo").foo.group({initial: {n:0}, reduce: function(obj,out){out.n++;}}); + printjson( count ); + assert.eq( len , count[0].n , "slave group count wrong: " + slave ); + + print("Calling group() with slaveOk=false, must fail"); + slave.slaveOk = false; + try { + count = slave.getDB("foo").foo.group({initial: {n:0}, reduce: function(obj,out){out.n++;}}); + assert(false, "group() succeeded with slaveOk=false"); + } catch (e) { + print("Received exception: " + e); + } + + print("Calling inline mr() with slaveOk=true, must succeed"); + slave.slaveOk = true; + map = function() { emit(this.a, 1); }; + reduce = function(key, vals) { var sum = 0; for (var i = 0; i < vals.length; ++i) { sum += vals[i]; } return sum; }; + slave.getDB("foo").foo.mapReduce(map, reduce, {out: { "inline" : 1}}); + + print("Calling mr() to collection with slaveOk=true, must fail"); + try { + slave.getDB("foo").foo.mapReduce(map, reduce, "output"); + assert(false, "mapReduce() to collection succeeded on slave"); + } catch (e) { + print("Received exception: " + e); + } + + print("Calling inline mr() with slaveOk=false, must fail"); + slave.slaveOk = false; + try { + slave.getDB("foo").foo.mapReduce(map, reduce, {out: { "inline" : 1}}); + assert(false, "mapReduce() succeeded on slave with slaveOk=false"); + } catch (e) { + print("Received exception: " + e); + } + print("Calling mr() to collection with slaveOk=false, must fail"); + try { + slave.getDB("foo").foo.mapReduce(map, reduce, "output"); + assert(false, "mapReduce() to collection succeeded on slave with slaveOk=false"); + } catch (e) { + print("Received exception: " + e); + } + + }); + + + + // Shut down the set and finish the test. + replTest.stopSet( signal ); +} + +doTest( 15 );
+print("SUCCESS");
diff --git a/jstests/replsets/initial_sync1.js b/jstests/replsets/initial_sync1.js new file mode 100644 index 0000000..ee30b4e --- /dev/null +++ b/jstests/replsets/initial_sync1.js @@ -0,0 +1,129 @@ +/** + * Test killing the secondary during initially sync + * + * 1. Bring up set + * 2. Insert some data + * 4. Make sure synced + * 5. Freeze #2 + * 6. Bring up #3 + * 7. Kill #2 in the middle of syncing + * 8. Eventually it should become a secondary + * 9. Bring #2 back up + * 10. Insert some stuff + * 11. Everyone happy eventually + */ + +load("jstests/replsets/rslib.js"); +var basename = "jstests_initsync1"; + + +print("1. Bring up set"); +var replTest = new ReplSetTest( {name: basename, nodes: 2} ); +var conns = replTest.startSet(); +replTest.initiate(); + +var master = replTest.getMaster(); +var foo = master.getDB("foo"); +var admin = master.getDB("admin"); + +var slave1 = replTest.liveNodes.slaves[0]; +var admin_s1 = slave1.getDB("admin"); +var local_s1 = slave1.getDB("local"); + +print("2. Insert some data"); +for (var i=0; i<10000; i++) { + foo.bar.insert({date : new Date(), x : i, str : "all the talk on the market"}); +} +print("total in foo: "+foo.bar.count()); + + +print("4. Make sure synced"); +replTest.awaitReplication(); + + +print("5. Freeze #2"); +admin_s1.runCommand({replSetFreeze:999999}); + + +print("6. Bring up #3"); +var ports = allocatePorts( 3 ); +var basePath = "/data/db/" + basename; +var hostname = getHostName(); + +var sargs = new MongodRunner( ports[ 2 ], basePath, false, false, + ["--replSet", basename, "--oplogSize", 2], + {no_bind : true} ); +var slave2 = sargs.start(); +var local_s2 = slave2.getDB("local"); +var admin_s2 = slave2.getDB("admin"); + +var config = replTest.getReplSetConfig(); +config.version = 2; +config.members.push({_id:2, host:hostname+":"+ports[2]}); + +try { + admin.runCommand({replSetReconfig:config}); +} +catch(e) { + print(e); +} +reconnect(slave1); +reconnect(slave2); + +wait(function() { + var config2 = local_s1.system.replset.findOne(); + var config3 = local_s2.system.replset.findOne(); + + printjson(config2); + printjson(config3); + + return config2.version == config.version && + (config3 && config3.version == config.version); + }); + +wait(function() { + var status = admin_s2.runCommand({replSetGetStatus:1}); + printjson(status); + return status.members && + (status.members[2].state == 3 || status.members[2].state == 2); + }); + + +print("7. Kill #2 in the middle of syncing"); +replTest.stop(1); + + +print("8. Eventually it should become a secondary"); +print("if initial sync has started, this will cause it to fail and sleep for 5 minutes"); +sleep(5*60*1000); +wait(function() { + var status = admin_s2.runCommand({replSetGetStatus:1}); + occasionally(function() { printjson(status); }); + return status.members[2].state == 2; + }); + + +print("9. Bring #2 back up"); +replTest.start(1, {}, true); +reconnect(slave1); +wait(function() { + var status = admin_s1.runCommand({replSetGetStatus:1}); + printjson(status); + return status.ok == 1 && status.members && + status.members[1].state == 2 || status.members[1].state == 1; + }); + + +/** + * TODO: this fails on buildbot + * see SERVER-2550 +print("10. Insert some stuff"); +master = replTest.getMaster(); +for (var i=0; i<10000; i++) { + foo.bar.insert({date : new Date(), x : i, str : "all the talk on the market"}); +} + + +print("11. Everyone happy eventually"); +replTest.awaitReplication(); +*/ diff --git a/jstests/replsets/initial_sync2.js b/jstests/replsets/initial_sync2.js new file mode 100644 index 0000000..3ad3972 --- /dev/null +++ b/jstests/replsets/initial_sync2.js @@ -0,0 +1,179 @@ +/** + * Test killing the primary during initial sync + * and don't allow the other secondary to become primary + * + * 1. Bring up set + * 2. Insert some data + * 4. Make sure synced + * 5. Freeze #2 + * 6. Bring up #3 + * 7. Kill #1 in the middle of syncing + * 8. Check that #3 makes it into secondary state + * 9. Bring #1 back up + * 10. Initial sync should succeed + * 11. Insert some stuff + * 12. Everyone happy eventually + */ + +load("jstests/replsets/rslib.js"); +var basename = "jstests_initsync2"; + +var doTest = function() { + +print("1. Bring up set"); +var replTest = new ReplSetTest( {name: basename, nodes: 2} ); +var conns = replTest.startSet(); +replTest.initiate(); + +var master = replTest.getMaster(); +var origMaster = master; +var foo = master.getDB("foo"); +var admin = master.getDB("admin"); + +var slave1 = replTest.liveNodes.slaves[0]; +var admin_s1 = slave1.getDB("admin"); +var local_s1 = slave1.getDB("local"); + +print("2. Insert some data"); +for (var i=0; i<10000; i++) { + foo.bar.insert({date : new Date(), x : i, str : "all the talk on the market"}); +} +print("total in foo: "+foo.bar.count()); + + +print("4. Make sure synced"); +replTest.awaitReplication(); + + +print("5. Freeze #2"); +admin_s1.runCommand({replSetFreeze:999999}); + + +print("6. Bring up #3"); +var ports = allocatePorts( 3 ); +var basePath = "/data/db/" + basename; +var hostname = getHostName(); + +var sargs = new MongodRunner( ports[ 2 ], basePath, false, false, + ["--replSet", basename, "--oplogSize", 2], + {no_bind : true} ); +var slave2 = sargs.start(); +var local_s2 = slave2.getDB("local"); +var admin_s2 = slave2.getDB("admin"); + +var config = replTest.getReplSetConfig(); +config.version = 2; +config.members.push({_id:2, host:hostname+":"+ports[2]}); + +try { + admin.runCommand({replSetReconfig:config}); +} +catch(e) { + print(e); +} +reconnect(slave1); +reconnect(slave2); + +wait(function() { + var config2 = local_s1.system.replset.findOne(); + var config3 = local_s2.system.replset.findOne(); + + printjson(config2); + printjson(config3); + + return config2.version == config.version && + (config3 && config3.version == config.version); + }); +admin_s2.runCommand({replSetFreeze:999999}); + + +wait(function() { + var status = admin_s2.runCommand({replSetGetStatus:1}); + printjson(status); + return status.members && + (status.members[2].state == 3 || status.members[2].state == 2); + }); + + +print("7. Kill #1 in the middle of syncing"); +replTest.stop(0); + + +print("8. Check that #3 makes it into secondary state"); +wait(function() { + var status = admin_s2.runCommand({replSetGetStatus:1}); + occasionally(function() { printjson(status);}, 10); + if (status.members[2].state == 2 || status.members[2].state == 1) { + return true; + } + return false; + }); + + +print("9. Bring #1 back up"); +replTest.start(0, {}, true); +reconnect(master); +wait(function() { + var status = admin.runCommand({replSetGetStatus:1}); + printjson(status); + return status.members && + (status.members[0].state == 1 || status.members[0].state == 2); + }); + + +print("10. Initial sync should succeed"); +wait(function() { + var status = admin_s2.runCommand({replSetGetStatus:1}); + printjson(status); + return status.members && + status.members[2].state == 2 || status.members[2].state == 1; + }); + + +print("11. Insert some stuff"); +// ReplSetTest doesn't find master correctly unless all nodes are defined by +// ReplSetTest +for (var i = 0; i<30; i++) { + var result = admin.runCommand({isMaster : 1}); + if (result.ismaster) { + break; + } + else if (result.primary) { + master = connect(result.primary+"/admin").getMongo(); + break; + } + sleep(1000); +} + +for (var i=0; i<10000; i++) { + foo.bar.insert({date : new Date(), x : i, str : "all the talk on the market"}); +} + + +print("12. Everyone happy eventually"); +// if 3 is master... +if (master+"" != origMaster+"") { + print("3 is master"); + slave2 = origMaster; +} + +wait(function() { + var op1 = getLatestOp(master); + var op2 = getLatestOp(slave1); + var op3 = getLatestOp(slave2); + + occasionally(function() { + print("latest ops:"); + printjson(op1); + printjson(op2); + printjson(op3); + }); + + return friendlyEqual(getLatestOp(master), getLatestOp(slave1)) && + friendlyEqual(getLatestOp(master), getLatestOp(slave2)); + }); + +replTest.stopSet(); +}; + +doTest(); diff --git a/jstests/replsets/initial_sync3.js b/jstests/replsets/initial_sync3.js new file mode 100644 index 0000000..471aa16 --- /dev/null +++ b/jstests/replsets/initial_sync3.js @@ -0,0 +1,87 @@ +/* test initial sync options + * + * {state : 1} + * {state : 2} + * {name : host+":"+port} + * {_id : 2} + * {optime : now} + * {optime : 1970} + */ + +load("jstests/replsets/rslib.js"); +var name = "initialsync3"; +var host = getHostName(); +var port = allocatePorts(7); + +print("Start set with three nodes"); +var replTest = new ReplSetTest( {name: name, nodes: 7} ); +var nodes = replTest.startSet(); +replTest.initiate({ + _id : name, + members : [ + {_id:0, host : host+":"+port[0]}, + {_id:1, host : host+":"+port[1], initialSync : {state : 1}}, + {_id:2, host : host+":"+port[2], initialSync : {state : 2}}, + {_id:3, host : host+":"+port[3], initialSync : {name : host+":"+port[2]}}, + {_id:4, host : host+":"+port[4], initialSync : {_id : 2}}, + {_id:5, host : host+":"+port[5], initialSync : {optime : new Date()}}, + {_id:6, host : host+":"+port[6], initialSync : {optime : new Date(0)}} + ]}); + +var master = replTest.getMaster(); + +print("Initial sync"); +master.getDB("foo").bar.baz.insert({x:1}); + +print("Make sure everyone's secondary"); +wait(function() { + var status = master.getDB("admin").runCommand({replSetGetStatus:1}); + occasionally(function() { + printjson(status); + }); + + if (!status.members) { + return false; + } + + for (i=0; i<7; i++) { + if (status.members[i].state != 1 && status.members[i].state != 2) { + return false; + } + } + return true; + + }); + +replTest.awaitReplication(); + +replTest.stopSet(); + +print("reconfig"); + +var rs2 = new ReplSetTest( {name: 'reconfig-isync3', nodes: 3} ); +rs2.startSet(); +rs2.initiate(); + +master = rs2.getMaster(); +var config = master.getDB("local").system.replset.findOne(); +config.version++; +config.members[0].initialSync = {state : 2}; +config.members[1].initialSync = {state : 1}; +try { + master.getDB("admin").runCommand({replSetReconfig : config}); +} +catch(e) { + print("trying to reconfigure: "+e); +} + +master = rs2.getMaster(); +config = master.getDB("local").system.replset.findOne(); + +assert(typeof(config.members[0].initialSync) == "object"); +assert.eq(config.members[0].initialSync.state, 2); +assert.eq(config.members[1].initialSync.state, 1); + +rs2.stopSet(); + +print("initialSync3 success!"); diff --git a/jstests/replsets/ismaster1.js b/jstests/replsets/ismaster1.js new file mode 100644 index 0000000..22865e5 --- /dev/null +++ b/jstests/replsets/ismaster1.js @@ -0,0 +1,36 @@ +/** + * 1. Check passive field in isMaster + */ + +load("jstests/replsets/rslib.js"); + +var name = "ismaster"; +var host = getHostName(); + +var replTest = new ReplSetTest( {name: name, nodes: 3} ); + +var nodes = replTest.startSet(); + +var config = replTest.getReplSetConfig(); +config.members[1].priority = 0; +config.members[2].priority = 0; + +replTest.initiate(config); + +var master = replTest.getMaster(); +wait(function() { + var result = master.getDB("admin").runCommand({replSetGetStatus:1}); + return result.members && result.members[0].state == 1 && + result.members[1].state == 2 && result.members[2].state == 2; + }); + +var result = master.getDB("admin").runCommand({isMaster:1}); +assert(!('passive' in result), tojson(result)); + +result = replTest.liveNodes.slaves[0].getDB("admin").runCommand({isMaster:1}); +assert('passive' in result, tojson(result)); + +result = replTest.liveNodes.slaves[1].getDB("admin").runCommand({isMaster:1}); +assert('passive' in result, tojson(result)); + +replTest.stopSet(); diff --git a/jstests/replsets/key1 b/jstests/replsets/key1 new file mode 100644 index 0000000..b5c19e4 --- /dev/null +++ b/jstests/replsets/key1 @@ -0,0 +1 @@ +foop de doop diff --git a/jstests/replsets/key2 b/jstests/replsets/key2 new file mode 100644 index 0000000..cbde821 --- /dev/null +++ b/jstests/replsets/key2 @@ -0,0 +1 @@ +other key diff --git a/jstests/replsets/remove1.js b/jstests/replsets/remove1.js new file mode 100644 index 0000000..ebd17d6 --- /dev/null +++ b/jstests/replsets/remove1.js @@ -0,0 +1,132 @@ +/* test removing a node from a replica set + * + * Start set with three nodes + * Initial sync + * Remove slave1 + * Remove slave2 + * Bring slave1 back up + * Bring slave2 back up + * Add them back as slave + * Make sure everyone's secondary + */ + +load("jstests/replsets/rslib.js"); +var name = "removeNodes"; +var host = getHostName(); + + +print("Start set with three nodes"); +var replTest = new ReplSetTest( {name: name, nodes: 3} ); +var nodes = replTest.startSet(); +replTest.initiate(); +var master = replTest.getMaster(); + + +print("Initial sync"); +master.getDB("foo").bar.baz.insert({x:1}); + +replTest.awaitReplication(); + + +print("Remove slave2"); +var config = replTest.getReplSetConfig(); + +config.members.pop(); +config.version = 2; +try { + master.getDB("admin").runCommand({replSetReconfig:config}); +} +catch(e) { + print(e); +} +reconnect(master); + + +print("Remove slave1"); +config.members.pop(); +config.version = 3; +try { + master.getDB("admin").runCommand({replSetReconfig:config}); +} +catch(e) { + print(e); +} +reconnect(master); + +print("sleeping 1"); +sleep(10000); +// these are already down, but this clears their ports from memory so that they +// can be restarted later +stopMongod(replTest.getPort(1)); +stopMongod(replTest.getPort(2)); + + +print("Bring slave1 back up"); +var paths = [ replTest.getPath(1), replTest.getPath(2) ]; +var ports = allocatePorts(2, replTest.getPort(2)+1); +var args = ["mongod", "--port", ports[0], "--dbpath", paths[0], "--noprealloc", "--smallfiles", "--rest"]; +var conn = startMongoProgram.apply( null, args ); +conn.getDB("local").system.replset.remove(); +printjson(conn.getDB("local").runCommand({getlasterror:1})); +print(conn); +print("sleeping 2"); +sleep(10000); +stopMongod(ports[0]); + +replTest.restart(1); + + +print("Bring slave2 back up"); +args[2] = ports[1]; +args[4] = paths[1]; +conn = startMongoProgram.apply( null, args ); +conn.getDB("local").system.replset.remove(); +print("path: "+paths[1]); +print("sleeping 3"); +sleep(10000); +stopMongod(ports[1]); + +replTest.restart(2); +sleep(10000); + + +print("Add them back as slaves"); +config.members.push({_id:1, host : host+":"+replTest.getPort(1)}); +config.members.push({_id:2, host : host+":"+replTest.getPort(2)}); +config.version = 4; +wait(function() { + try { + master.getDB("admin").runCommand({replSetReconfig:config}); + } + catch(e) { + print(e); + } + reconnect(master); + + master.setSlaveOk(); + var newConfig = master.getDB("local").system.replset.findOne(); + return newConfig.version == 4; + }); + + +print("Make sure everyone's secondary"); +wait(function() { + var status = master.getDB("admin").runCommand({replSetGetStatus:1}); + occasionally(function() { + printjson(status); + }); + + if (!status.members || status.members.length != 3) { + return false; + } + + for (var i = 0; i<3; i++) { + if (status.members[i].state != 1 && status.members[i].state != 2) { + return false; + } + } + return true; + }); + +replTest.stopSet(); + diff --git a/jstests/replsets/replset2.js b/jstests/replsets/replset2.js index f18b467..4849620 100644 --- a/jstests/replsets/replset2.js +++ b/jstests/replsets/replset2.js @@ -1,126 +1,126 @@ -print("\n\nreplset2.js BEGIN");
-
-doTest = function (signal) {
-
- // FAILING TEST
- // See below:
-
- // Test replication with getLastError
-
- // Replica set testing API
- // Create a new replica set test. Specify set name and the number of nodes you want.
- var replTest = new ReplSetTest({ name: 'testSet', nodes: 3, oplogSize: 5 });
-
- // call startSet() to start each mongod in the replica set
- // this returns a list of nodes
- var nodes = replTest.startSet();
-
- // Call initiate() to send the replSetInitiate command
- // This will wait for initiation
- replTest.initiate();
-
- var testDB = "repl-test";
-
- // Call getMaster to return a reference to the node that's been
- // elected master.
- var master = replTest.getMaster();
-
- // Wait for replication to a single node
- master.getDB(testDB).bar.insert({ n: 1 });
-
- // Wait for initial sync
- replTest.awaitReplication();
-
- var slaves = replTest.liveNodes.slaves;
- slaves.forEach(function (slave) { slave.setSlaveOk(); });
-
- var failed = false;
- var callGetLastError = function (w, timeout, db) {
- try {
- var result = master.getDB(db).getLastErrorObj(w, timeout);
- print("replset2.js getLastError result: " + tojson(result));
- if (result['ok'] != 1) {
- print("replset2.js FAILURE getlasterror not ok");
- failed = true;
- }
- }
- catch (e) {
- print("\nreplset2.js exception in getLastError: " + e + '\n');
- throw e;
- }
- }
-
- // Test getlasterror with multiple inserts
- // TEST FAILS HEREg
- print("\n\nreplset2.js **** Try inserting a multiple records -- first insert ****")
-
- printjson(master.getDB("admin").runCommand("replSetGetStatus"));
-
- master.getDB(testDB).foo.insert({ n: 1 });
- master.getDB(testDB).foo.insert({ n: 2 });
- master.getDB(testDB).foo.insert({ n: 3 });
-
- print("\nreplset2.js **** TEMP 1 ****")
-
- printjson(master.getDB("admin").runCommand("replSetGetStatus"));
-
- callGetLastError(3, 25000, testDB);
-
- print("replset2.js **** TEMP 1a ****")
-
- m1 = master.getDB(testDB).foo.findOne({ n: 1 });
- printjson(m1);
- assert(m1['n'] == 1, "replset2.js Failed to save to master on multiple inserts");
-
- print("replset2.js **** TEMP 1b ****")
-
- var s0 = slaves[0].getDB(testDB).foo.findOne({ n: 1 });
- assert(s0['n'] == 1, "replset2.js Failed to replicate to slave 0 on multiple inserts");
-
- var s1 = slaves[1].getDB(testDB).foo.findOne({ n: 1 });
- assert(s1['n'] == 1, "replset2.js Failed to replicate to slave 1 on multiple inserts");
-
- // Test getlasterror with a simple insert
- print("replset2.js **** Try inserting a single record ****")
- master.getDB(testDB).dropDatabase();
- master.getDB(testDB).foo.insert({ n: 1 });
- callGetLastError(3, 10000, testDB);
-
- m1 = master.getDB(testDB).foo.findOne({ n: 1 });
- printjson(m1);
- assert(m1['n'] == 1, "replset2.js Failed to save to master");
-
- s0 = slaves[0].getDB(testDB).foo.findOne({ n: 1 });
- assert(s0['n'] == 1, "replset2.js Failed to replicate to slave 0");
-
- s1 = slaves[1].getDB(testDB).foo.findOne({ n: 1 });
- assert(s1['n'] == 1, "replset2.js Failed to replicate to slave 1");
-
- // Test getlasterror with large insert
- print("replset2.js **** Try inserting many records ****")
+print("\n\nreplset2.js BEGIN"); + +doTest = function (signal) { + + // FAILING TEST + // See below: + + // Test replication with getLastError + + // Replica set testing API + // Create a new replica set test. Specify set name and the number of nodes you want. + var replTest = new ReplSetTest({ name: 'testSet', nodes: 3, oplogSize: 5 }); + + // call startSet() to start each mongod in the replica set + // this returns a list of nodes + var nodes = replTest.startSet(); + + // Call initiate() to send the replSetInitiate command + // This will wait for initiation + replTest.initiate(); + + var testDB = "repl-test"; + + // Call getMaster to return a reference to the node that's been + // elected master. + var master = replTest.getMaster(); + + // Wait for replication to a single node + master.getDB(testDB).bar.insert({ n: 1 }); + + // Wait for initial sync + replTest.awaitReplication(); + + var slaves = replTest.liveNodes.slaves; + slaves.forEach(function (slave) { slave.setSlaveOk(); }); + + var failed = false; + var callGetLastError = function (w, timeout, db) { + try { + var result = master.getDB(db).getLastErrorObj(w, timeout); + print("replset2.js getLastError result: " + tojson(result)); + if (result['ok'] != 1) { + print("replset2.js FAILURE getlasterror not ok"); + failed = true; + } + } + catch (e) { + print("\nreplset2.js exception in getLastError: " + e + '\n'); + throw e; + } + } + + // Test getlasterror with multiple inserts + // TEST FAILS HEREg + print("\n\nreplset2.js **** Try inserting a multiple records -- first insert ****") + + printjson(master.getDB("admin").runCommand("replSetGetStatus")); + + master.getDB(testDB).foo.insert({ n: 1 }); + master.getDB(testDB).foo.insert({ n: 2 }); + master.getDB(testDB).foo.insert({ n: 3 }); + + print("\nreplset2.js **** TEMP 1 ****") + + printjson(master.getDB("admin").runCommand("replSetGetStatus")); + + callGetLastError(3, 25000, testDB); + + print("replset2.js **** TEMP 1a ****") + + m1 = master.getDB(testDB).foo.findOne({ n: 1 }); + printjson(m1); + assert(m1['n'] == 1, "replset2.js Failed to save to master on multiple inserts"); + + print("replset2.js **** TEMP 1b ****") + + var s0 = slaves[0].getDB(testDB).foo.findOne({ n: 1 }); + assert(s0['n'] == 1, "replset2.js Failed to replicate to slave 0 on multiple inserts"); + + var s1 = slaves[1].getDB(testDB).foo.findOne({ n: 1 }); + assert(s1['n'] == 1, "replset2.js Failed to replicate to slave 1 on multiple inserts"); + + // Test getlasterror with a simple insert + print("replset2.js **** Try inserting a single record ****") + master.getDB(testDB).dropDatabase(); + master.getDB(testDB).foo.insert({ n: 1 }); + callGetLastError(3, 10000, testDB); + + m1 = master.getDB(testDB).foo.findOne({ n: 1 }); + printjson(m1); + assert(m1['n'] == 1, "replset2.js Failed to save to master"); + + s0 = slaves[0].getDB(testDB).foo.findOne({ n: 1 }); + assert(s0['n'] == 1, "replset2.js Failed to replicate to slave 0"); + + s1 = slaves[1].getDB(testDB).foo.findOne({ n: 1 }); + assert(s1['n'] == 1, "replset2.js Failed to replicate to slave 1"); + + // Test getlasterror with large insert + print("replset2.js **** Try inserting many records ****") try { - bigData = new Array(2000).toString()
- for (var n = 0; n < 1000; n++) {
- master.getDB(testDB).baz.insert({ n: n, data: bigData });
- }
- callGetLastError(3, 60000, testDB);
-
- print("replset2.js **** V1 ")
-
- var verifyReplication = function (nodeName, collection) {
- data = collection.findOne({ n: 1 });
- assert(data['n'] == 1, "replset2.js Failed to save to " + nodeName);
- data = collection.findOne({ n: 999 });
- assert(data['n'] == 999, "replset2.js Failed to save to " + nodeName);
- }
-
- print("replset2.js **** V2 ")
-
- verifyReplication("master", master.getDB(testDB).baz);
- verifyReplication("slave 0", slaves[0].getDB(testDB).baz);
- verifyReplication("slave 1", slaves[1].getDB(testDB).baz);
-
- assert(failed == false, "replset2.js Replication with getLastError failed. See errors.");
+ bigData = new Array(2000).toString() + for (var n = 0; n < 1000; n++) { + master.getDB(testDB).baz.insert({ n: n, data: bigData }); + } + callGetLastError(3, 60000, testDB); + + print("replset2.js **** V1 ") + + var verifyReplication = function (nodeName, collection) { + data = collection.findOne({ n: 1 }); + assert(data['n'] == 1, "replset2.js Failed to save to " + nodeName); + data = collection.findOne({ n: 999 }); + assert(data['n'] == 999, "replset2.js Failed to save to " + nodeName); + } + + print("replset2.js **** V2 ") + + verifyReplication("master", master.getDB(testDB).baz); + verifyReplication("slave 0", slaves[0].getDB(testDB).baz); + verifyReplication("slave 1", slaves[1].getDB(testDB).baz); + + assert(failed == false, "replset2.js Replication with getLastError failed. See errors."); } catch(e) { print("ERROR: " + e); @@ -132,10 +132,10 @@ doTest = function (signal) { printjson(slaves[1].getDB("local").oplog.rs.find().sort({"$natural": -1}).limit(1).next()); } -
- replTest.stopSet(signal);
+ + replTest.stopSet(signal); } -doTest( 15 );
-
+doTest( 15 ); + print("\nreplset2.js SUCCESS\n"); diff --git a/jstests/replsets/replset3.js b/jstests/replsets/replset3.js index 8126b9d..faa0627 100644 --- a/jstests/replsets/replset3.js +++ b/jstests/replsets/replset3.js @@ -1,56 +1,80 @@ - -doTest = function( signal ) { - - // Test replica set step down - - // Replica set testing API - // Create a new replica set test. Specify set name and the number of nodes you want. - var replTest = new ReplSetTest( {name: 'testSet', nodes: 3} ); - - // call startSet() to start each mongod in the replica set - // this returns a list of nodes - var nodes = replTest.startSet(); - - // Call initiate() to send the replSetInitiate command - // This will wait for initiation - replTest.initiate(); - - // Get master node - var master = replTest.getMaster(); - - // Write some data to master - // NOTE: this test fails unless we write some data. - master.getDB("foo").foo.save({a: 1}); - master.getDB("foo").runCommand({getlasterror: 1, w:3, wtimeout: 20000}); - - // Step down master - master.getDB("admin").runCommand({replSetStepDown: true}); - - try { - var new_master = replTest.getMaster(); - } - catch( err ) { - throw( "Could not elect new master before timeout." ); - } - - assert( master != new_master, "Old master shouldn't be equal to new master." ); - - // Make sure that slaves are still up - var result = new_master.getDB("admin").runCommand({replSetGetStatus: 1}); - assert( result['ok'] == 1, "Could not verify that slaves were still up:" + result ); - - slaves = replTest.liveNodes.slaves; - assert.soon(function() { - res = slaves[0].getDB("admin").runCommand({replSetGetStatus: 1}) - return res.myState == 2; - }, "Slave 0 state not ready."); - - assert.soon(function() { - res = slaves[1].getDB("admin").runCommand({replSetGetStatus: 1}) - return res.myState == 2; - }, "Slave 1 state not ready."); - - replTest.stopSet( 15 ); +
+doTest = function (signal) {
+
+ // Test replica set step down
+
+ // Replica set testing API
+ // Create a new replica set test. Specify set name and the number of nodes you want.
+ var replTest = new ReplSetTest({ name: 'testSet', nodes: 3 });
+
+ // call startSet() to start each mongod in the replica set
+ // this returns a list of nodes
+ var nodes = replTest.startSet();
+
+ // Call initiate() to send the replSetInitiate command
+ // This will wait for initiation
+ replTest.initiate();
+
+ // Get master node
+ var master = replTest.getMaster();
+
+ // Write some data to master
+ // NOTE: this test fails unless we write some data.
+ master.getDB("foo").foo.save({ a: 1 });
+ master.getDB("foo").runCommand({ getlasterror: 1, w: 3, wtimeout: 20000 });
+
+ var phase = 1;
+
+ print(phase++);
+
+ // Step down master. Note: this may close our connection!
+ try {
+ master.getDB("admin").runCommand({ replSetStepDown: true });
+ } catch (err) {
+ print("caught: " + err + " on stepdown");
+ }
+
+ print(phase++);
+
+ try {
+ var new_master = replTest.getMaster();
+ }
+ catch (err) {
+ throw ("Could not elect new master before timeout.");
+ }
+
+ print(phase++);
+
+ assert(master != new_master, "Old master shouldn't be equal to new master.");
+
+ print(phase++);
+
+ // Make sure that slaves are still up
+ var result = new_master.getDB("admin").runCommand({ replSetGetStatus: 1 });
+ assert(result['ok'] == 1, "Could not verify that slaves were still up:" + result);
+
+ print(phase++);
+
+ slaves = replTest.liveNodes.slaves;
+ assert.soon(function () {
+ try {
+ res = slaves[0].getDB("admin").runCommand({ replSetGetStatus: 1 })
+ } catch (err) { }
+ return res.myState == 2;
+ }, "Slave 0 state not ready.");
+
+ print(phase++);
+
+ assert.soon(function () {
+ try {
+ res = slaves[1].getDB("admin").runCommand({ replSetGetStatus: 1 })
+ } catch (err) { }
+ return res.myState == 2;
+ }, "Slave 1 state not ready.");
+
+ print("replset3.js SUCCESS");
+
+ replTest.stopSet(15);
} doTest( 15 ); diff --git a/jstests/replsets/replset5.js b/jstests/replsets/replset5.js index fe1761e..13ee5c9 100644 --- a/jstests/replsets/replset5.js +++ b/jstests/replsets/replset5.js @@ -23,15 +23,15 @@ doTest = function (signal) { master.getDB("barDB").bar.save({ a: 1 });
replTest.awaitReplication();
- // These writes should be replicated immediately
- master.getDB(testDB).foo.insert({ n: 1 });
- master.getDB(testDB).foo.insert({ n: 2 });
- master.getDB(testDB).foo.insert({ n: 3 });
-
- // *** NOTE ***: The default doesn't seem to be propogating. - // When I run getlasterror with no defaults, the slaves don't have the data:
- // These getlasterror commands can be run individually to verify this. - //master.getDB("admin").runCommand({ getlasterror: 1, w: 3, wtimeout: 20000 });
+ // These writes should be replicated immediately + var docNum = 5000; + for(var n=0; n<docNum; n++) { + master.getDB(testDB).foo.insert({ n: n });
+ } +
+ // If you want to test failure, just add values for w and wtimeout + // to the following command. This will override the default set above and + // prevent replication from happening in time for the count tests below. master.getDB("admin").runCommand({getlasterror: 1});
var slaves = replTest.liveNodes.slaves;
@@ -40,31 +40,15 @@ doTest = function (signal) { print("Testing slave counts");
- // These should all have 3 documents, but they don't always. - var master1count = master.getDB(testDB).foo.count(); - assert( master1count == 3, "Master has " + master1count + " of 3 documents!"); - var slave0count = slaves[0].getDB(testDB).foo.count(); - assert( slave0count == 3, "Slave 0 has " + slave0count + " of 3 documents!"); + assert( slave0count == docNum, "Slave 0 has " + slave0count + " of " + docNum + " documents!"); var slave1count = slaves[1].getDB(testDB).foo.count(); - assert( slave1count == 3, "Slave 1 has " + slave1count + " of 3 documents!"); + assert( slave1count == docNum, "Slave 1 has " + slave1count + " of " + docNum + " documents!"); - print("Testing slave 0");
+ var master1count = master.getDB(testDB).foo.count(); + assert( master1count == docNum, "Master has " + master1count + " of " + docNum + " documents!"); - var s0 = slaves[0].getDB(testDB).foo.find();
- assert(s0.next()['n']);
- assert(s0.next()['n']);
- assert(s0.next()['n']);
-
- print("Testing slave 1");
-
- var s1 = slaves[1].getDB(testDB).foo.find();
- assert(s1.next()['n']);
- assert(s1.next()['n']);
- assert(s1.next()['n']);
-
- // End test
replTest.stopSet(signal);
} diff --git a/jstests/replsets/replset_remove_node.js b/jstests/replsets/replset_remove_node.js index fcb754c..9fef721 100644 --- a/jstests/replsets/replset_remove_node.js +++ b/jstests/replsets/replset_remove_node.js @@ -33,8 +33,15 @@ doTest = function( signal ) { config.version = c.version + 1; config.members = [ { "_id" : 0, "host" : replTest.host + ":31000" }, { "_id" : 2, "host" : replTest.host + ":31002" } ] - replTest.initiate( config , 'replSetReconfig' ); + try { + replTest.initiate( config , 'replSetReconfig' ); + } + catch(e) { + print(e); + } + + // Make sure that a new master comes up master = replTest.getMaster(); slaves = replTest.liveNodes.slaves; diff --git a/jstests/replsets/replsetarb2.js b/jstests/replsets/replsetarb2.js index 0dd8a3d..0e4c791 100644 --- a/jstests/replsets/replsetarb2.js +++ b/jstests/replsets/replsetarb2.js @@ -29,6 +29,8 @@ doTest = function( signal ) { master.getDB("foo").foo.insert({a: "foo"}); replTest.awaitReplication(); + assert( ! conns[1].getDB( "admin" ).runCommand( "ismaster" ).secondary , "arbiter shouldn't be secondary" ) + // Now kill the original master mId = replTest.getNodeId( master ); replTest.stop( mId ); diff --git a/jstests/replsets/replsetarb3.js b/jstests/replsets/replsetarb3.js new file mode 100644 index 0000000..1193cf2 --- /dev/null +++ b/jstests/replsets/replsetarb3.js @@ -0,0 +1,144 @@ +// @file replsetarb3.js +// try turning arbiters into non-arbiters and vice versa + +/* + * 1: initialize set + * 2: check m3.state == 7 + * 3: reconfig + * 4: check m3.state == 2 + * 5: reconfig + * 6: check m3.state == 7 + * 7: reconfig + * 8: check m3.state == 2 + * 9: insert 10000 + * 10: reconfig + * 11: check m3.state == 7 + */ + +var debug = false; + +var statusSoon = function(s) { + assert.soon(function() { + var status = master.getDB("admin").runCommand({ replSetGetStatus: 1 }); + if (debug) + printjson(status); + return status.members[2].state == s; + }); +}; + +var w = 0; +var wait = function(f) { + w++; + var n = 0; + while (!f()) { + if( n % 4 == 0 ) + print("toostale.js waiting " + w); + if (++n == 4) { + print("" + f); + } + assert(n < 200, 'tried 200 times, giving up'); + sleep(1000); + } +} + +var reconnect = function(a) { + wait(function() { + try { + a.getDB("foo").bar.stats(); + return true; + } catch(e) { + print(e); + return false; + } + }); +}; + +var reconfig = function() { + config.version++; + try { + var result = master.getDB("admin").runCommand({replSetReconfig : config}); + } + catch(e) { + print(e); + } + reconnect(master); + reconnect(replTest.liveNodes.slaves[1]); + sleep(20000); +}; + +var replTest = new ReplSetTest( {name: 'unicomplex', nodes: 3} ); +var nodes = replTest.nodeList(); + +print(tojson(nodes)); + + +var conns = replTest.startSet(); + +print("1"); +var config = {"_id" : "unicomplex", "members" : [ + {"_id" : 0, "host" : nodes[0] }, + {"_id" : 1, "host" : nodes[1] }, + {"_id" : 2, "host" : nodes[2], "arbiterOnly" : true}]}; +var r = replTest.initiate(config); +config.version = 1; + +var master = replTest.getMaster(); + +// Wait for initial replication +master.getDB("foo").foo.insert({a: "foo"}); +replTest.awaitReplication(); + + +print("2"); +statusSoon(7); +assert.eq(replTest.liveNodes.slaves[1].getDB("local").oplog.rs.count(), 0); + +/* +print("3"); +delete config.members[2].arbiterOnly; +reconfig(); + + +print("4"); +statusSoon(2); +assert(replTest.liveNodes.slaves[1].getDB("local").oplog.rs.count() > 0); + + +print("5"); +config.members[2].arbiterOnly = true; +reconfig(); + + +print("6"); +statusSoon(7); +assert.eq(replTest.liveNodes.slaves[1].getDB("local").oplog.rs.count(), 0); + + +print("7"); +delete config.members[2].arbiterOnly; +reconfig(); + + +print("8"); +statusSoon(2); +assert(replTest.liveNodes.slaves[1].getDB("local").oplog.rs.count() > 0); + + +print("9"); +for (var i = 0; i < 10000; i++) { + master.getDB("foo").bar.insert({increment : i, c : 0, foo : "kasdlfjaklsdfalksdfakldfmalksdfmaklmfalkfmkafmdsaklfma", date : new Date(), d : Date()}); +} + + +print("10"); +config.members[2].arbiterOnly = true; +reconfig(); + + +print("11"); +statusSoon(7); +assert.eq(replTest.liveNodes.slaves[1].getDB("local").oplog.rs.count(), 0); +*/ + +replTest.stopSet( 15 ); + diff --git a/jstests/replsets/replsetfreeze.js b/jstests/replsets/replsetfreeze.js new file mode 100644 index 0000000..3721ba5 --- /dev/null +++ b/jstests/replsets/replsetfreeze.js @@ -0,0 +1,105 @@ +/* + * 1: initialize set + * 2: step down m1 + * 3: freeze set for 30 seconds + * 4: check no one is master for 30 seconds + * 5: check for new master + * 6: step down new master + * 7: freeze for 30 seconds + * 8: unfreeze + * 9: check we get a new master within 30 seconds + */ + + +var w = 0; +var wait = function(f) { + w++; + var n = 0; + while (!f()) { + if( n % 4 == 0 ) + print("toostale.js waiting " + w); + if (++n == 4) { + print("" + f); + } + assert(n < 200, 'tried 200 times, giving up'); + sleep(1000); + } +} + +var reconnect = function(a) { + wait(function() { + try { + a.getDB("foo").bar.stats(); + return true; + } catch(e) { + print(e); + return false; + } + }); +}; + + +print("1: initialize set"); +var replTest = new ReplSetTest( {name: 'unicomplex', nodes: 3} ); +var nodes = replTest.nodeList(); +var conns = replTest.startSet(); +var config = {"_id" : "unicomplex", "members" : [ + {"_id" : 0, "host" : nodes[0] }, + {"_id" : 1, "host" : nodes[1] }, + {"_id" : 2, "host" : nodes[2], "arbiterOnly" : true}]}; +var r = replTest.initiate(config); +var master = replTest.getMaster(); + + +print("2: step down m1"); +try { + master.getDB("admin").runCommand({replSetStepDown : 1}); +} +catch(e) { + print(e); +} +reconnect(master); + +print("3: freeze set for 30 seconds"); +master.getDB("admin").runCommand({replSetFreeze : 30}); + + +print("4: check no one is master for 30 seconds"); +var start = (new Date()).getTime(); +while ((new Date()).getTime() - start < 30000) { + var result = master.getDB("admin").runCommand({isMaster:1}); + assert.eq(result.ismaster, false); + assert.eq(result.primary, undefined); + sleep(1000); +} + + +print("5: check for new master"); +master = replTest.getMaster(); + + +print("6: step down new master"); +try { + master.getDB("admin").runCommand({replSetStepDown : 1}); +} +catch(e) { + print(e); +} +reconnect(master); + + +print("7: freeze for 30 seconds"); +master.getDB("admin").runCommand({replSetFreeze : 30}); +sleep(1000); + + +print("8: unfreeze"); +master.getDB("admin").runCommand({replSetFreeze : 0}); + + +print("9: check we get a new master within 30 seconds"); +master = replTest.getMaster(); + + +replTest.stopSet( 15 ); + diff --git a/jstests/replsets/rollback.js b/jstests/replsets/rollback.js index 8840371..6370e41 100644 --- a/jstests/replsets/rollback.js +++ b/jstests/replsets/rollback.js @@ -1,155 +1,186 @@ -// test rollback in replica sets
-
-// try running as :
-//
-// mongo --nodb rollback.js | tee out | grep -v ^m31
-//
-
-var debugging = 0;
-
-function pause(s) {
- print(s);
- while (debugging) {
- sleep(3000);
- print(s);
- }
-}
-
-function deb(obj) {
- if( debugging ) {
- print("\n\n\n" + obj + "\n\n");
- }
-}
-
-w = 0;
-
-function wait(f) {
- w++;
- var n = 0;
- while (!f()) {
- if( n % 4 == 0 )
- print("rollback.js waiting " + w);
- if (++n == 4) {
- print("" + f);
- }
- sleep(1000);
- }
-}
-
-doTest = function (signal) {
-
- var replTest = new ReplSetTest({ name: 'unicomplex', nodes: 3 });
- var nodes = replTest.nodeList();
- //print(tojson(nodes));
-
- var conns = replTest.startSet();
- var r = replTest.initiate({ "_id": "unicomplex",
- "members": [
- { "_id": 0, "host": nodes[0] },
- { "_id": 1, "host": nodes[1] },
- { "_id": 2, "host": nodes[2], arbiterOnly: true}]
- });
-
- // Make sure we have a master
- var master = replTest.getMaster();
- a_conn = conns[0];
- A = a_conn.getDB("admin");
- b_conn = conns[1];
- a_conn.setSlaveOk();
- b_conn.setSlaveOk();
- B = b_conn.getDB("admin");
- assert(master == conns[0], "conns[0] assumed to be master");
- assert(a_conn == master);
-
- //deb(master);
-
- // Make sure we have an arbiter
- assert.soon(function () {
- res = conns[2].getDB("admin").runCommand({ replSetGetStatus: 1 });
- return res.myState == 7;
- }, "Arbiter failed to initialize.");
-
- // Wait for initial replication
- var a = a_conn.getDB("foo");
- var b = b_conn.getDB("foo");
-
- /* force the oplog to roll */
- if (new Date() % 2 == 0) {
- print("ROLLING OPLOG AS PART OF TEST (we only do this sometimes)");
- var pass = 1;
- var first = a.getSisterDB("local").oplog.rs.find().sort({ $natural: 1 }).limit(1)[0];
- a.roll.insert({ x: 1 });
- while (1) {
- for (var i = 0; i < 10000; i++)
- a.roll.update({}, { $inc: { x: 1} });
- var op = a.getSisterDB("local").oplog.rs.find().sort({ $natural: 1 }).limit(1)[0];
- if (tojson(op.h) != tojson(first.h)) {
- printjson(op);
- printjson(first);
- break;
- }
- pass++;
- a.getLastError(2); // unlikely secondary isn't keeping up, but let's avoid possible intermittent issues with that.
- }
- print("PASSES FOR OPLOG ROLL: " + pass);
- }
- else {
- print("NO ROLL");
- }
-
- a.bar.insert({ q: 1, a: "foo" });
- a.bar.insert({ q: 2, a: "foo", x: 1 });
- a.bar.insert({ q: 3, bb: 9, a: "foo" });
-
- assert(a.bar.count() == 3, "t.count");
-
- // wait for secondary to get this data
- wait(function () { return b.bar.count() == 3; });
-
- A.runCommand({ replSetTest: 1, blind: true });
- wait(function () { return B.isMaster().ismaster; });
-
- b.bar.insert({ q: 4 });
- b.bar.insert({ q: 5 });
- b.bar.insert({ q: 6 });
- assert(b.bar.count() == 6, "u.count");
-
- // a should not have the new data as it was in blind state.
- B.runCommand({ replSetTest: 1, blind: true });
- A.runCommand({ replSetTest: 1, blind: false });
- wait(function () { return !B.isMaster().ismaster; });
- wait(function () { return A.isMaster().ismaster; });
-
- assert(a.bar.count() == 3, "t is 3");
- a.bar.insert({ q: 7 });
- a.bar.insert({ q: 8 });
- {
- assert(a.bar.count() == 5);
- var x = a.bar.find().toArray();
- assert(x[0].q == 1, '1');
- assert(x[1].q == 2, '2');
- assert(x[2].q == 3, '3');
- assert(x[3].q == 7, '7');
- assert(x[4].q == 8, '8');
- }
-
- // A is 1 2 3 7 8
- // B is 1 2 3 4 5 6
-
- // bring B back online
- B.runCommand({ replSetTest: 1, blind: false });
-
- wait(function () { return B.isMaster().ismaster || B.isMaster().secondary; });
-
- // everyone is up here...
- assert(A.isMaster().ismaster || A.isMaster().secondary, "A up");
- assert(B.isMaster().ismaster || B.isMaster().secondary, "B up");
-
- friendlyEqual(a.bar.find().sort({ _id: 1 }).toArray(), b.bar.find().sort({ _id: 1 }).toArray(), "server data sets do not match");
-
- pause("rollback.js SUCCESS");
- replTest.stopSet(signal);
+// test rollback in replica sets + +// try running as : +// +// mongo --nodb rollback.js | tee out | grep -v ^m31 +// + +var debugging = 0; + +function pause(s) { + print(s); + while (debugging) { + sleep(3000); + print(s); + } +} + +function deb(obj) { + if( debugging ) { + print("\n\n\n" + obj + "\n\n"); + } +} + +w = 0; + +function wait(f) { + w++; + var n = 0; + while (!f()) { + if( n % 4 == 0 ) + print("rollback.js waiting " + w); + if (++n == 4) { + print("" + f); + } + assert(n < 200, 'tried 200 times, giving up'); + sleep(1000); + } } +doTest = function (signal) { + + var replTest = new ReplSetTest({ name: 'unicomplex', nodes: 3 }); + var nodes = replTest.nodeList(); + //print(tojson(nodes)); + + var conns = replTest.startSet(); + var r = replTest.initiate({ "_id": "unicomplex", + "members": [ + { "_id": 0, "host": nodes[0] }, + { "_id": 1, "host": nodes[1] }, + { "_id": 2, "host": nodes[2], arbiterOnly: true}] + }); + + // Make sure we have a master + var master = replTest.getMaster(); + a_conn = conns[0]; + A = a_conn.getDB("admin"); + b_conn = conns[1]; + a_conn.setSlaveOk(); + b_conn.setSlaveOk(); + B = b_conn.getDB("admin"); + assert(master == conns[0], "conns[0] assumed to be master"); + assert(a_conn == master); + + //deb(master); + + // Make sure we have an arbiter + assert.soon(function () { + res = conns[2].getDB("admin").runCommand({ replSetGetStatus: 1 }); + return res.myState == 7; + }, "Arbiter failed to initialize."); + + // Wait for initial replication + var a = a_conn.getDB("foo"); + var b = b_conn.getDB("foo"); + + /* force the oplog to roll */ + if (new Date() % 2 == 0) { + print("ROLLING OPLOG AS PART OF TEST (we only do this sometimes)"); + var pass = 1; + var first = a.getSisterDB("local").oplog.rs.find().sort({ $natural: 1 }).limit(1)[0]; + a.roll.insert({ x: 1 }); + while (1) { + for (var i = 0; i < 10000; i++) + a.roll.update({}, { $inc: { x: 1} }); + var op = a.getSisterDB("local").oplog.rs.find().sort({ $natural: 1 }).limit(1)[0]; + if (tojson(op.h) != tojson(first.h)) { + printjson(op); + printjson(first); + break; + } + pass++; + a.getLastError(2); // unlikely secondary isn't keeping up, but let's avoid possible intermittent issues with that. + } + print("PASSES FOR OPLOG ROLL: " + pass); + } + else { + print("NO ROLL"); + } + + a.bar.insert({ q: 1, a: "foo" }); + a.bar.insert({ q: 2, a: "foo", x: 1 }); + a.bar.insert({ q: 3, bb: 9, a: "foo" }); + + assert(a.bar.count() == 3, "t.count"); + + // wait for secondary to get this data + wait(function () { return b.bar.count() == 3; }); + + A.runCommand({ replSetTest: 1, blind: true }); + reconnect(a,b); + wait(function () { return B.isMaster().ismaster; }); + + b.bar.insert({ q: 4 }); + b.bar.insert({ q: 5 }); + b.bar.insert({ q: 6 }); + assert(b.bar.count() == 6, "u.count"); + + // a should not have the new data as it was in blind state. + B.runCommand({ replSetTest: 1, blind: true }); + print("*************** wait for server to reconnect ****************"); + reconnect(a,b); + A.runCommand({ replSetTest: 1, blind: false }); + reconnect(a,b); + + print("*************** B ****************"); + wait(function () { try { return !B.isMaster().ismaster; } catch(e) { return false; } }); + print("*************** A ****************"); + reconnect(a,b); + wait(function () { + try { + return A.isMaster().ismaster; + } catch(e) { + return false; + } + }); + + assert(a.bar.count() == 3, "t is 3"); + a.bar.insert({ q: 7 }); + a.bar.insert({ q: 8 }); + { + assert(a.bar.count() == 5); + var x = a.bar.find().toArray(); + assert(x[0].q == 1, '1'); + assert(x[1].q == 2, '2'); + assert(x[2].q == 3, '3'); + assert(x[3].q == 7, '7'); + assert(x[4].q == 8, '8'); + } + + // A is 1 2 3 7 8 + // B is 1 2 3 4 5 6 + + // bring B back online + B.runCommand({ replSetTest: 1, blind: false }); + reconnect(a,b); + + wait(function () { return B.isMaster().ismaster || B.isMaster().secondary; }); + + // everyone is up here... + assert(A.isMaster().ismaster || A.isMaster().secondary, "A up"); + assert(B.isMaster().ismaster || B.isMaster().secondary, "B up"); + replTest.awaitReplication(); + + friendlyEqual(a.bar.find().sort({ _id: 1 }).toArray(), b.bar.find().sort({ _id: 1 }).toArray(), "server data sets do not match"); + + pause("rollback.js SUCCESS"); + replTest.stopSet(signal); +}; + + +var reconnect = function(a,b) { + wait(function() { + try { + a.bar.stats(); + b.bar.stats(); + return true; + } catch(e) { + print(e); + return false; + } + }); +}; + print("rollback.js"); doTest( 15 ); diff --git a/jstests/replsets/rollback2.js b/jstests/replsets/rollback2.js index 483d221..46fb548 100644 --- a/jstests/replsets/rollback2.js +++ b/jstests/replsets/rollback2.js @@ -1,201 +1,232 @@ -// test rollback in replica sets
-
-// try running as :
-//
-// mongo --nodb rollback.js | tee out | grep -v ^m31
-//
-
-var debugging = 0;
-
-function pause(s) {
- print(s);
- while (debugging) {
- sleep(3000);
- print(s);
- }
-}
-
-function deb(obj) {
- if( debugging ) {
- print("\n\n\n" + obj + "\n\n");
- }
-}
-
-w = 0;
-
-function wait(f) {
- w++;
- var n = 0;
- while (!f()) {
- if (n % 4 == 0)
- print("rollback2.js waiting " + w);
- if (++n == 4) {
- print("" + f);
- }
- sleep(1000);
- }
-}
-
-function dbs_match(a, b) {
- print("dbs_match");
-
- var ac = a.system.namespaces.find().sort({name:1}).toArray();
- var bc = b.system.namespaces.find().sort({name:1}).toArray();
- if (!friendlyEqual(ac, bc)) {
- print("dbs_match: namespaces don't match");
- print("\n\n");
- printjson(ac);
- print("\n\n");
- printjson(bc);
- print("\n\n");
- return false;
- }
-
- var c = a.getCollectionNames();
- for( var i in c ) {
- print("checking " + c[i]);
- if( !friendlyEqual( a[c[i]].find().sort({_id:1}).toArray(), b[c[i]].find().sort({_id:1}).toArray() ) ) {
- print("dbs_match: collections don't match " + c[i]);
- return false;
- }
- }
- return true;
-}
-
-/* these writes will be initial data and replicate everywhere. */
-function doInitialWrites(db) {
- t = db.bar;
- t.insert({ q:0});
- t.insert({ q: 1, a: "foo" });
- t.insert({ q: 2, a: "foo", x: 1 });
- t.insert({ q: 3, bb: 9, a: "foo" });
- t.insert({ q: 40, a: 1 });
- t.insert({ q: 40, a: 2 });
- t.insert({ q: 70, txt: 'willremove' });
-
- db.createCollection("kap", { capped: true, size: 5000 });
- db.kap.insert({ foo: 1 })
-
- // going back to empty on capped is a special case and must be tested
- db.createCollection("kap2", { capped: true, size: 5501 });
-}
-
-/* these writes on one primary only and will be rolled back. */
-function doItemsToRollBack(db) {
- t = db.bar;
- t.insert({ q: 4 });
- t.update({ q: 3 }, { q: 3, rb: true });
-
- t.remove({ q: 40 }); // multi remove test
-
- t.update({ q: 2 }, { q: 39, rb: true });
-
- // rolling back a delete will involve reinserting the item(s)
- t.remove({ q: 1 });
-
- t.update({ q: 0 }, { $inc: { y: 1} });
-
- db.kap.insert({ foo: 2 })
- db.kap2.insert({ foo: 2 })
-
- // create a collection (need to roll back the whole thing)
- db.newcoll.insert({ a: true });
-
- // create a new empty collection (need to roll back the whole thing)
- db.createCollection("abc");
-}
-
-function doWritesToKeep2(db) {
- t = db.bar;
- t.insert({ txt: 'foo' });
- t.remove({ q: 70 });
- t.update({ q: 0 }, { $inc: { y: 33} });
-}
-
-function verify(db) {
- print("verify");
- t = db.bar;
- assert(t.find({ q: 1 }).count() == 1);
- assert(t.find({ txt: 'foo' }).count() == 1);
- assert(t.find({ q: 4 }).count() == 0);
-}
-
-doTest = function (signal) {
-
- var replTest = new ReplSetTest({ name: 'unicomplex', nodes: 3 });
- var nodes = replTest.nodeList();
- //print(tojson(nodes));
-
- var conns = replTest.startSet();
- var r = replTest.initiate({ "_id": "unicomplex",
- "members": [
- { "_id": 0, "host": nodes[0] },
- { "_id": 1, "host": nodes[1] },
- { "_id": 2, "host": nodes[2], arbiterOnly: true}]
- });
-
- // Make sure we have a master
- var master = replTest.getMaster();
- a_conn = conns[0];
- A = a_conn.getDB("admin");
- b_conn = conns[1];
- a_conn.setSlaveOk();
- b_conn.setSlaveOk();
- B = b_conn.getDB("admin");
- assert(master == conns[0], "conns[0] assumed to be master");
- assert(a_conn == master);
-
- //deb(master);
-
- // Make sure we have an arbiter
- assert.soon(function () {
- res = conns[2].getDB("admin").runCommand({ replSetGetStatus: 1 });
- return res.myState == 7;
- }, "Arbiter failed to initialize.");
-
- // Wait for initial replication
- var a = a_conn.getDB("foo");
- var b = b_conn.getDB("foo");
- doInitialWrites(a);
-
- // wait for secondary to get this data
- wait(function () { return b.bar.count() == a.bar.count(); });
-
- A.runCommand({ replSetTest: 1, blind: true });
- wait(function () { return B.isMaster().ismaster; });
-
- doItemsToRollBack(b);
-
- // a should not have the new data as it was in blind state.
- B.runCommand({ replSetTest: 1, blind: true });
- A.runCommand({ replSetTest: 1, blind: false });
- wait(function () { return !B.isMaster().ismaster; });
- wait(function () { return A.isMaster().ismaster; });
-
- assert(a.bar.count() >= 1, "count check");
- doWritesToKeep2(a);
-
- // A is 1 2 3 7 8
- // B is 1 2 3 4 5 6
-
- // bring B back online
- // as A is primary, B will roll back and then catch up
- B.runCommand({ replSetTest: 1, blind: false });
-
- wait(function () { return B.isMaster().ismaster || B.isMaster().secondary; });
-
- // everyone is up here...
- assert(A.isMaster().ismaster || A.isMaster().secondary, "A up");
- assert(B.isMaster().ismaster || B.isMaster().secondary, "B up");
-
- verify(a);
-
- assert( dbs_match(a,b), "server data sets do not match after rollback, something is wrong");
-
- pause("rollback2.js SUCCESS");
- replTest.stopSet(signal);
+// a test of rollback in replica sets +// +// try running as : +// +// mongo --nodb rollback2.js | tee out | grep -v ^m31 +// + +var debugging = 0; + +function pause(s) { + print(s); + while (debugging) { + sleep(3000); + print(s); + } +} + +function deb(obj) { + if( debugging ) { + print("\n\n\n" + obj + "\n\n"); + } +} + +w = 0; + +function wait(f) { + w++; + var n = 0; + while (!f()) { + if (n % 4 == 0) + print("rollback2.js waiting " + w); + if (++n == 4) { + print("" + f); + } + assert(n < 200, 'tried 200 times, giving up'); + sleep(1000); + } +} + +function dbs_match(a, b) { + print("dbs_match"); + + var ac = a.system.namespaces.find().sort({name:1}).toArray(); + var bc = b.system.namespaces.find().sort({name:1}).toArray(); + if (!friendlyEqual(ac, bc)) { + print("dbs_match: namespaces don't match"); + print("\n\n"); + printjson(ac); + print("\n\n"); + printjson(bc); + print("\n\n"); + return false; + } + + var c = a.getCollectionNames(); + for( var i in c ) { + print("checking " + c[i]); + if( !friendlyEqual( a[c[i]].find().sort({_id:1}).toArray(), b[c[i]].find().sort({_id:1}).toArray() ) ) { + print("dbs_match: collections don't match " + c[i]); + return false; + } + } + return true; +} + +/* these writes will be initial data and replicate everywhere. */ +function doInitialWrites(db) { + t = db.bar; + t.insert({ q:0}); + t.insert({ q: 1, a: "foo" }); + t.insert({ q: 2, a: "foo", x: 1 }); + t.insert({ q: 3, bb: 9, a: "foo" }); + t.insert({ q: 40, a: 1 }); + t.insert({ q: 40, a: 2 }); + t.insert({ q: 70, txt: 'willremove' }); + + db.createCollection("kap", { capped: true, size: 5000 }); + db.kap.insert({ foo: 1 }) + + // going back to empty on capped is a special case and must be tested + db.createCollection("kap2", { capped: true, size: 5501 }); +} + +/* these writes on one primary only and will be rolled back. */ +function doItemsToRollBack(db) { + t = db.bar; + t.insert({ q: 4 }); + t.update({ q: 3 }, { q: 3, rb: true }); + + t.remove({ q: 40 }); // multi remove test + + t.update({ q: 2 }, { q: 39, rb: true }); + + // rolling back a delete will involve reinserting the item(s) + t.remove({ q: 1 }); + + t.update({ q: 0 }, { $inc: { y: 1} }); + + db.kap.insert({ foo: 2 }) + db.kap2.insert({ foo: 2 }) + + // create a collection (need to roll back the whole thing) + db.newcoll.insert({ a: true }); + + // create a new empty collection (need to roll back the whole thing) + db.createCollection("abc"); } +function doWritesToKeep2(db) { + t = db.bar; + t.insert({ txt: 'foo' }); + t.remove({ q: 70 }); + t.update({ q: 0 }, { $inc: { y: 33} }); +} + +function verify(db) { + print("verify"); + t = db.bar; + assert(t.find({ q: 1 }).count() == 1); + assert(t.find({ txt: 'foo' }).count() == 1); + assert(t.find({ q: 4 }).count() == 0); +} + +doTest = function (signal) { + + var replTest = new ReplSetTest({ name: 'unicomplex', nodes: 3 }); + var nodes = replTest.nodeList(); + //print(tojson(nodes)); + + var conns = replTest.startSet(); + var r = replTest.initiate({ "_id": "unicomplex", + "members": [ + { "_id": 0, "host": nodes[0] }, + { "_id": 1, "host": nodes[1] }, + { "_id": 2, "host": nodes[2], arbiterOnly: true}] + }); + + // Make sure we have a master + var master = replTest.getMaster(); + a_conn = conns[0]; + A = a_conn.getDB("admin"); + b_conn = conns[1]; + a_conn.setSlaveOk(); + b_conn.setSlaveOk(); + B = b_conn.getDB("admin"); + assert(master == conns[0], "conns[0] assumed to be master"); + assert(a_conn == master); + + //deb(master); + + // Make sure we have an arbiter + assert.soon(function () { + res = conns[2].getDB("admin").runCommand({ replSetGetStatus: 1 }); + return res.myState == 7; + }, "Arbiter failed to initialize."); + + // Wait for initial replication + var a = a_conn.getDB("foo"); + var b = b_conn.getDB("foo"); + wait(function () { + var status = A.runCommand({replSetGetStatus : 1}); + return status.members[1].state == 2; + }); + + doInitialWrites(a); + + // wait for secondary to get this data + wait(function () { return b.bar.count() == a.bar.count(); }); + wait(function () { + var status = A.runCommand({replSetGetStatus : 1}); + return status.members[1].state == 2; + }); + + + A.runCommand({ replSetTest: 1, blind: true }); + reconnect(a, b); + + wait(function () { return B.isMaster().ismaster; }); + + doItemsToRollBack(b); + + // a should not have the new data as it was in blind state. + B.runCommand({ replSetTest: 1, blind: true }); + reconnect(a, b); + A.runCommand({ replSetTest: 1, blind: false }); + reconnect(a,b); + + wait(function () { try { return !B.isMaster().ismaster; } catch(e) { return false; } }); + wait(function () { try { return A.isMaster().ismaster; } catch(e) { return false; } }); + + assert(a.bar.count() >= 1, "count check"); + doWritesToKeep2(a); + + // A is 1 2 3 7 8 + // B is 1 2 3 4 5 6 + + // bring B back online + // as A is primary, B will roll back and then catch up + B.runCommand({ replSetTest: 1, blind: false }); + reconnect(a,b); + + wait(function () { return B.isMaster().ismaster || B.isMaster().secondary; }); + + // everyone is up here... + assert(A.isMaster().ismaster || A.isMaster().secondary, "A up"); + assert(B.isMaster().ismaster || B.isMaster().secondary, "B up"); + replTest.awaitReplication(); + + verify(a); + + assert( dbs_match(a,b), "server data sets do not match after rollback, something is wrong"); + + pause("rollback2.js SUCCESS"); + replTest.stopSet(signal); +}; + +var reconnect = function(a,b) { + wait(function() { + try { + a.bar.stats(); + b.bar.stats(); + return true; + } catch(e) { + print(e); + return false; + } + }); +}; + print("rollback2.js"); doTest( 15 ); diff --git a/jstests/replsets/rollback3.js b/jstests/replsets/rollback3.js index 5c2f2f1..fa923d8 100755 --- a/jstests/replsets/rollback3.js +++ b/jstests/replsets/rollback3.js @@ -30,10 +30,10 @@ function wait(f) { if (n % 4 == 0) print("rollback3.js waiting " + w); if (++n == 4) { - print("" + f);
- }
- if (n == 200) {
- print("rollback3.js failing waited too long");
+ print("" + f); + } + if (n == 200) { + print("rollback3.js failing waited too long"); throw "wait error"; } sleep(1000); @@ -188,15 +188,20 @@ doTest = function (signal) { wait(function () { return b.bar.count() == a.bar.count(); }); A.runCommand({ replSetTest: 1, blind: true }); - wait(function () { return B.isMaster().ismaster; }); + reconnect(a,b); + wait(function () { try { return B.isMaster().ismaster; } catch(e) { return false; } }); doItemsToRollBack(b); // a should not have the new data as it was in blind state. B.runCommand({ replSetTest: 1, blind: true }); + reconnect(a,b); + A.runCommand({ replSetTest: 1, blind: false }); - wait(function () { return !B.isMaster().ismaster; }); - wait(function () { return A.isMaster().ismaster; }); + reconnect(a,b); + + wait(function () { try { return !B.isMaster().ismaster; } catch(e) { return false; } }); + wait(function () { try { return A.isMaster().ismaster; } catch(e) { return false; } }); assert(a.bar.count() >= 1, "count check"); doWritesToKeep2(a); @@ -207,18 +212,34 @@ doTest = function (signal) { // bring B back online // as A is primary, B will roll back and then catch up B.runCommand({ replSetTest: 1, blind: false }); + reconnect(a,b); wait(function () { return B.isMaster().ismaster || B.isMaster().secondary; }); // everyone is up here... assert(A.isMaster().ismaster || A.isMaster().secondary, "A up"); assert(B.isMaster().ismaster || B.isMaster().secondary, "B up"); - + replTest.awaitReplication(); + assert( dbs_match(a,b), "server data sets do not match after rollback, something is wrong"); pause("rollback3.js SUCCESS"); replTest.stopSet(signal); -} +}; + + +var reconnect = function(a,b) { + wait(function() { + try { + a.bar.stats(); + b.bar.stats(); + return true; + } catch(e) { + print(e); + return false; + } + }); +}; print("rollback3.js"); doTest( 15 ); diff --git a/jstests/replsets/rslib.js b/jstests/replsets/rslib.js new file mode 100644 index 0000000..c072829 --- /dev/null +++ b/jstests/replsets/rslib.js @@ -0,0 +1,63 @@ + +var count = 0; +var w = 0; + +var wait = function(f) { + w++; + var n = 0; + while (!f()) { + if( n % 4 == 0 ) + print("waiting " + w); + if (++n == 4) { + print("" + f); + } + assert(n < 200, 'tried 200 times, giving up'); + sleep(1000); + } +}; + +/** + * Use this to do something once every 4 iterations. + * + * <pre> + * for (i=0; i<1000; i++) { + * occasionally(function() { print("4 more iterations"); }); + * } + * </pre> + */ +var occasionally = function(f, n) { + var interval = n || 4; + if (count % interval == 0) { + f(); + } + count++; +}; + +var reconnect = function(a) { + wait(function() { + try { + // make this work with either dbs or connections + if (typeof(a.getDB) == "function") { + a.getDB("foo").bar.stats(); + } + else { + a.bar.stats(); + } + return true; + } catch(e) { + print(e); + return false; + } + }); +}; + + +var getLatestOp = function(server) { + server.getDB("admin").getMongo().setSlaveOk(); + var log = server.getDB("local")['oplog.rs']; + var cursor = log.find({}).sort({'$natural': -1}).limit(1); + if (cursor.hasNext()) { + return cursor.next(); + } + return null; +}; diff --git a/jstests/replsets/slaveDelay2.js b/jstests/replsets/slaveDelay2.js new file mode 100644 index 0000000..2d9dd1f --- /dev/null +++ b/jstests/replsets/slaveDelay2.js @@ -0,0 +1,104 @@ + +var name = "slaveDelay2"; +var host = getHostName(); + +var waitForAllMembers = function(master) { + var ready = false; + + outer: + while (true) { + var state = master.getSisterDB("admin").runCommand({replSetGetStatus:1}); + + for (var m in state.members) { + if (state.members[m].state != 2 && state.members[m].state != 1) { + sleep(10000); + continue outer; + } + } + + printjson(state); + print("okay, everyone is primary or secondary"); + return; + } +}; + + +var initialize = function() { + var replTest = new ReplSetTest( {name: name, nodes: 1} ); + + var nodes = replTest.startSet(); + + replTest.initiate(); + + var master = replTest.getMaster().getDB(name); + + waitForAllMembers(master); + + return replTest; +}; + +var populate = function(master) { + // insert records + for (var i =0; i<1000; i++) { + master.foo.insert({_id:1}); + } + + master.runCommand({getlasterror:1}); +} + +doTest = function( signal ) { + var replTest = initialize(); + var master = replTest.getMaster().getDB(name); + populate(master); + var admin = master.getSisterDB("admin"); + + /** + * start a slave with a long delay (1 hour) and do some writes while it is + * initializing. Make sure it syncs all of these writes before going into + * syncDelay. + */ + var conn = startMongodTest(31008, name + "-sd", 0, { useHostname: true, replSet: name }); + conn.setSlaveOk(); + + config = master.getSisterDB("local").system.replset.findOne(); + config.version++; + config.members.push({_id : 1, host : host+":31008",priority:0, slaveDelay:3600}); + var ok = admin.runCommand({replSetReconfig : config}); + assert.eq(ok.ok,1); + + // do inserts during initial sync + count = 0; + while (count < 10) { + for (var i = 100*count; i<100*(count+1); i++) { + master.foo.insert({x:i}); + } + + //check if initial sync is done + var state = master.getSisterDB("admin").runCommand({replSetGetStatus:1}); + printjson(state); + if (state.members[1].state == 2) { + break; + } + + count++; + } + + // throw out last 100 inserts, but make sure the others were applied + if (count == 0) { + print("NOTHING TO CHECK"); + replTest.stopSet(); + return; + } + + // wait a bit for the syncs to be applied + waitForAllMembers(master); + + for (var i=0; i<(100*count); i++) { + var obj = conn.getDB(name).foo.findOne({x : i}); + assert(obj); + } + + replTest.stopSet(); +} + +doTest(15); diff --git a/jstests/replsets/slavedelay1.js b/jstests/replsets/slavedelay1.js new file mode 100644 index 0000000..e549822 --- /dev/null +++ b/jstests/replsets/slavedelay1.js @@ -0,0 +1,127 @@ + +var waitForAllMembers = function(master) { + var ready = false; + + outer: + while (true) { + var state = master.getSisterDB("admin").runCommand({replSetGetStatus:1}); + printjson(state); + + for (var m in state.members) { + if (state.members[m].state != 2 && state.members[m].state != 1) { + sleep(10000); + continue outer; + } + } + return; + } +}; + + +doTest = function( signal ) { + + var name = "slaveDelay"; + var host = getHostName(); + + var replTest = new ReplSetTest( {name: name, nodes: 3} ); + + var nodes = replTest.startSet(); + + /* set slaveDelay to 30 seconds */ + var config = replTest.getReplSetConfig(); + config.members[2].priority = 0; + config.members[2].slaveDelay = 30; + + replTest.initiate(config); + + var master = replTest.getMaster().getDB(name); + var slaveConns = replTest.liveNodes.slaves; + var slave = []; + for (var i in slaveConns) { + var d = slaveConns[i].getDB(name); + d.getMongo().setSlaveOk(); + slave.push(d); + } + + waitForAllMembers(master); + + // insert a record + master.foo.insert({x:1}); + master.runCommand({getlasterror:1, w:2}); + + var doc = master.foo.findOne(); + assert.eq(doc.x, 1); + + // make sure slave has it + var doc = slave[0].foo.findOne(); + assert.eq(doc.x, 1); + + // make sure delayed slave doesn't have it + assert.eq(slave[1].foo.findOne(), null); + + // wait 35 seconds + sleep(35000); + + // now delayed slave should have it + assert.eq(slave[1].foo.findOne().x, 1); + + + /************* Part 2 *******************/ + + // how about non-initial sync? + + for (var i=0; i<100; i++) { + master.foo.insert({_id : i, "foo" : "bar"}); + } + master.runCommand({getlasterror:1,w:2}); + + assert.eq(master.foo.findOne({_id : 99}).foo, "bar"); + assert.eq(slave[0].foo.findOne({_id : 99}).foo, "bar"); + assert.eq(slave[1].foo.findOne({_id : 99}), null); + + sleep(35000); + + assert.eq(slave[1].foo.findOne({_id : 99}).foo, "bar"); + + /************* Part 3 *******************/ + + // how about if we add a new server? will it sync correctly? + + var conn = startMongodTest( 31007 , name+"-part3" , 0 , {useHostname : true, replSet : name} ); + + config = master.getSisterDB("local").system.replset.findOne(); + printjson(config); + config.version++; + config.members.push({_id : 3, host : host+":31007",priority:0, slaveDelay:10}); + + var admin = master.getSisterDB("admin"); + try { + var ok = admin.runCommand({replSetReconfig : config}); + assert.eq(ok.ok,1); + } + catch(e) { + print(e); + } + + master = replTest.getMaster().getDB(name); + + waitForAllMembers(master); + + sleep(15000); + + // it should be all caught up now + + master.foo.insert({_id : 123, "x" : "foo"}); + master.runCommand({getlasterror:1,w:2}); + + conn.setSlaveOk(); + assert.eq(conn.getDB(name).foo.findOne({_id:123}), null); + + sleep(15000); + + assert.eq(conn.getDB(name).foo.findOne({_id:123}).x, "foo"); + + replTest.stopSet(); +} + +doTest(15); diff --git a/jstests/replsets/sync1.js b/jstests/replsets/sync1.js index e60d128..af16044 100644 --- a/jstests/replsets/sync1.js +++ b/jstests/replsets/sync1.js @@ -1,5 +1,7 @@ // test rollback of replica sets +load("jstests/replsets/rslib.js"); + var debugging=0; w = 0; @@ -50,7 +52,7 @@ doTest = function (signal) { dbs[0].bar.ensureIndex({ w: 1 });
var ok = false;
- var inserts = 100000;
+ var inserts = 10000;
print("\nsync1.js ********************************************************************** part 5");
@@ -62,7 +64,7 @@ doTest = function (signal) { do {
sleep(1000);
status = dbs[0].getSisterDB("admin").runCommand({ replSetGetStatus: 1 });
- } while (status.members[1].state != 2 && status.members[2].state != 2);
+ } while (status.members[1].state != 2 || status.members[2].state != 2);
print("\nsync1.js ********************************************************************** part 6");
dbs[0].getSisterDB("admin").runCommand({ replSetTest: 1, blind: true });
@@ -125,12 +127,14 @@ doTest = function (signal) { try {
printjson(dbs[1].isMaster());
printjson(dbs[1].bar.count());
+ printjson(dbs[1].adminCommand({replSetGetStatus : 1})); }
catch (e) { print(e); }
print("dbs[2]:");
try {
printjson(dbs[2].isMaster());
printjson(dbs[2].bar.count());
+ printjson(dbs[2].adminCommand({replSetGetStatus : 1})); }
catch (e) { print(e); }
assert(false, "sync1.js too many exceptions, failing");
@@ -161,10 +165,22 @@ doTest = function (signal) { print("\nsync1.js ********************************************************************** part 10");
// now, let's see if rollback works
- var result = dbs[0].getSisterDB("admin").runCommand({ replSetTest: 1, blind: false });
+ wait(function() { + try { + dbs[0].adminCommand({ replSetTest: 1, blind: false }); + } + catch(e) { + print(e); + } + reconnect(dbs[0]); + reconnect(dbs[1]); + + var status = dbs[1].adminCommand({replSetGetStatus:1}); + return status.members[0].health == 1; + }); + + dbs[0].getMongo().setSlaveOk();
-
- printjson(result);
sleep(5000);
// now this should resync
@@ -192,6 +208,10 @@ doTest = function (signal) { count++;
if (count == 100) {
+ printjson(dbs[0].isMaster());
+ printjson(dbs[0].adminCommand({replSetGetStatus:1})); + printjson(dbs[1].isMaster());
+ printjson(dbs[1].adminCommand({replSetGetStatus:1})); pause("FAIL part 11");
assert(false, "replsets/\nsync1.js fails timing out");
replTest.stopSet(signal);
diff --git a/jstests/replsets/sync_passive.js b/jstests/replsets/sync_passive.js new file mode 100644 index 0000000..d3e8ef4 --- /dev/null +++ b/jstests/replsets/sync_passive.js @@ -0,0 +1,89 @@ +/** + * Test syncing from non-primaries. + * + * Start a set. + * Inital sync. + * Kill member 1. + * Add some data. + * Kill member 0. + * Restart member 1. + * Check that it syncs. + * Add some data. + * Kill member 1. + * Restart member 0. + * Check that it syncs. + */ + +load("jstests/replsets/rslib.js"); + +var name = "sync_passive"; +var host = getHostName(); + +var replTest = new ReplSetTest( {name: name, nodes: 3} ); + +var nodes = replTest.startSet(); + +/* set slaveDelay to 30 seconds */ +var config = replTest.getReplSetConfig(); +config.members[2].priority = 0; + +replTest.initiate(config); + +var master = replTest.getMaster().getDB("test"); +var server0 = master; +var server1 = replTest.liveNodes.slaves[0]; + +print("Initial sync"); +for (var i=0;i<100;i++) { + master.foo.insert({x:i}); +} +replTest.awaitReplication(); + + +print("stop #1"); +replTest.stop(1); + + +print("add some data"); +for (var i=0;i<1000;i++) { + master.bar.insert({x:i}); +} +replTest.awaitReplication(); + + +print("stop #0"); +replTest.stop(0); + + +print("restart #1"); +replTest.restart(1); + + +print("check sync"); +replTest.awaitReplication(); + + +print("add data"); +reconnect(server1); +master = replTest.getMaster().getDB("test"); +for (var i=0;i<1000;i++) { + master.bar.insert({x:i}); +} +replTest.awaitReplication(); + + +print("kill #1"); +replTest.stop(1); + + +print("restart #0"); +replTest.restart(0); +reconnect(server0); + + +print("wait for sync"); +replTest.awaitReplication(); + + +print("bring #1 back up, make sure everything's okay"); +replTest.restart(1); diff --git a/jstests/replsets/sync_passive2.js b/jstests/replsets/sync_passive2.js new file mode 100644 index 0000000..230d71c --- /dev/null +++ b/jstests/replsets/sync_passive2.js @@ -0,0 +1,120 @@ +/** + * Test syncing from non-primaries. + */ + +load("jstests/replsets/rslib.js"); + +var name = "sync_passive2"; +var host = getHostName(); + +var replTest = new ReplSetTest( {name: name, nodes: 5} ); +var nodes = replTest.startSet(); + +// 0: master +// 1: arbiter +// 2: slave a +// 3: slave b +// 4: slave c +var config = replTest.getReplSetConfig(); +config.members[1].arbiterOnly = true; +for (i=2; i<config.members.length; i++) { + config.members[i].priority = 0; +} +replTest.initiate(config); + +var master = replTest.getMaster().getDB("test"); + +print("Initial sync"); +for (var i=0;i<10000;i++) { + master.foo.insert({x:i, foo:"bar", msg : "all the talk on the market", date : [new Date(), new Date(), new Date()]}); +} +replTest.awaitReplication(); + + +print("stop c"); +replTest.stop(4); + + +print("add data"); +for (var i=0;i<10000;i++) { + master.foo.insert({x:i, foo:"bar", msg : "all the talk on the market", date : [new Date(), new Date(), new Date()]}); +} +replTest.awaitReplication(); + + +print("stop b"); +replTest.stop(3); + + +print("add data"); +for (var i=0;i<10000;i++) { + master.foo.insert({x:i, foo:"bar", msg : "all the talk on the market", date : [new Date(), new Date(), new Date()]}); +} +replTest.awaitReplication(); + + +print("kill master"); +replTest.stop(0); +replTest.stop(2); + + +// now we have just the arbiter up + +print("restart c"); +replTest.restart(4); +print("restart b"); +replTest.restart(3); + + +print("wait for sync"); +wait(function() { + var status = replTest.liveNodes.slaves[0].getDB("admin").runCommand({replSetGetStatus:1}); + occasionally(function() { + printjson(status); + print("1: " + status.members +" 2: "+(status.members[3].state == 2)+" 3: "+ (status.members[4].state == 2) + + " 4: "+friendlyEqual(status.members[3].optime, status.members[4].optime)); + }); + + return status.members && + status.members[3].state == 2 && + status.members[4].state == 2 && + friendlyEqual(status.members[3].optime, status.members[4].optime); + }); + + +print("restart a"); +replTest.restart(2); +print("wait for sync2"); +wait(function() { + var status = replTest.liveNodes.slaves[0].getDB("admin").runCommand({replSetGetStatus:1}); + occasionally(function() { + printjson(status); + print("1: " + status.members +" 2a: "+(status.members[3].state == 2)+" 2: "+ + (status.members[3].state == 2)+" 3: "+ (status.members[4].state == 2) + + " 4: "+friendlyEqual(status.members[3].optime, status.members[4].optime)); + }); + + return status.members && + status.members[2].state == 2 && + status.members[3].state == 2 && + status.members[4].state == 2 && + friendlyEqual(status.members[3].optime, status.members[4].optime) && + friendlyEqual(status.members[2].optime, status.members[4].optime); + }); + +print("bring master back up, make sure everything's okay"); +replTest.restart(0); + +print("wait for sync"); +wait(function() { + var status = replTest.liveNodes.slaves[0].getDB("admin").runCommand({replSetGetStatus:1}); + occasionally(function() { + printjson(status); + }); + return status.members && + status.members[2].state == 2 && + status.members[3].state == 2 && + status.members[4].state == 2 && + friendlyEqual(status.members[3].optime, status.members[4].optime) && + friendlyEqual(status.members[2].optime, status.members[4].optime); + }); diff --git a/jstests/replsets/toostale.js b/jstests/replsets/toostale.js new file mode 100644 index 0000000..0b8da0d --- /dev/null +++ b/jstests/replsets/toostale.js @@ -0,0 +1,121 @@ + +// this tests that: +// * stale members get into state 3 (recovering) +// * they stay in state 3 after restarting +// * they can recover and go into state 2 if someone less up-to-date becomes primary + +/* + * 1: initial insert + * 2: initial sync + * 3: blind s2 + * 4: overflow oplog + * 5: unblind s2 + * 6: check s2.state == 3 + * 7: restart s2 + * 8: check s2.state == 3 + */ + + +var w = 0; +var wait = function(f) { + w++; + var n = 0; + while (!f()) { + if( n % 4 == 0 ) + print("toostale.js waiting " + w); + if (++n == 4) { + print("" + f); + } + assert(n < 200, 'tried 200 times, giving up'); + sleep(1000); + } +} + +var reconnect = function(a) { + wait(function() { + try { + a.bar.stats(); + return true; + } catch(e) { + print(e); + return false; + } + }); +}; + + +var name = "toostale" +var replTest = new ReplSetTest( {name: name, nodes: 3}); + +var nodes = replTest.startSet(); +replTest.initiate(); +var master = replTest.getMaster(); +var mdb = master.getDB("foo"); + + +print("1: initial insert"); +mdb.foo.save({a: 1000}); + + +print("2: initial sync"); +replTest.awaitReplication(); + +print("3: blind s2"); +replTest.stop(2); +print("waiting until the master knows the slave is blind"); +assert.soon(function() { return master.getDB("admin").runCommand({replSetGetStatus:1}).members[2].health == 0 }); +print("okay"); + +print("4: overflow oplog"); +reconnect(master.getDB("local")); +var count = master.getDB("local").oplog.rs.count(); +var prevCount = -1; +while (count != prevCount) { + print("inserting 10000"); + for (var i = 0; i < 10000; i++) { + mdb.bar.insert({x:i, date : new Date(), str : "safkaldmfaksndfkjansfdjanfjkafa"}); + } + prevCount = count; + replTest.awaitReplication(); + count = master.getDB("local").oplog.rs.count(); + print("count: "+count+" prev: "+prevCount); +} + + +print("5: unblind s2"); +replTest.restart(2); +print("waiting until the master knows the slave is not blind"); +assert.soon(function() { return master.getDB("admin").runCommand({replSetGetStatus:1}).members[2].health != 0 }); +print("okay"); + + +print("6: check s2.state == 3"); +var goStale = function() { + wait(function() { + var status = master.getDB("admin").runCommand({replSetGetStatus:1}); + printjson(status); + return status.members[2].state == 3; + }); +}; +goStale(); + + +print("7: restart s2"); +replTest.stop(2); +replTest.restart(2); + + +print("8: check s2.state == 3"); +status = master.getDB("admin").runCommand({replSetGetStatus:1}); +while (status.state == 0) { + print("state is 0: "); + printjson(status); + sleep(1000); + status = master.getDB("admin").runCommand({replSetGetStatus:1}); +} + +printjson(status); +assert.eq(status.members[2].state, 3, 'recovering'); + + +replTest.stopSet(15); diff --git a/jstests/replsets/two_initsync.js b/jstests/replsets/two_initsync.js index 6ae8475..7d1442d 100755 --- a/jstests/replsets/two_initsync.js +++ b/jstests/replsets/two_initsync.js @@ -32,6 +32,7 @@ function wait(f) { if (++n == 4) { print("" + f); } + assert(n < 200, 'tried 200 times, giving up'); sleep(1000); } } diff --git a/jstests/replsets/twosets.js b/jstests/replsets/twosets.js index 7cf367b..aae1113 100644 --- a/jstests/replsets/twosets.js +++ b/jstests/replsets/twosets.js @@ -5,19 +5,13 @@ doTest = function( signal ) { var orig = new ReplSetTest( {name: 'testSet', nodes: 3} ); orig.startSet(); + orig.initiate(); + var master = orig.getMaster(); var interloper = new ReplSetTest( {name: 'testSet', nodes: 3, startPort : 31003} ); interloper.startSet(); - - sleep(5000); - - orig.initiate(); interloper.initiate(); - sleep(5000); - - var master = orig.getMaster(); - var conf = master.getDB("local").system.replset.findOne(); var nodes = interloper.nodeList(); @@ -26,8 +20,13 @@ doTest = function( signal ) { conf.members.push({_id : id, host : host}); conf.version++; - var result = master.getDB("admin").runCommand({replSetReconfig : conf}); - + try { + var result = master.getDB("admin").runCommand({replSetReconfig : conf}); + } + catch(e) { + print(e); + } + // now... stuff should blow up? sleep(10); |