140 lines
3.8 KiB
JavaScript
140 lines
3.8 KiB
JavaScript
/* NOTE: This test requires mongo shell to be built with V8 javascript engines so
|
|
fork() is available */
|
|
|
|
/*
|
|
1. Starts up a replica set with 2 servers and 1 arbiter, all with --dur option.
|
|
2. Loads 10000 1K docs into a collection
|
|
3. Forks 5 client threads, each $pushes then $pulls its own id to/from the same array in all document (multi-update)
|
|
5. A 6th thread kills a random server in the replica set every 0-60 secs then restarts it 0-30 secs later.
|
|
-Tony */
|
|
|
|
load('jstests/libs/fun.js')
|
|
load('jstests/libs/concurrent.js')
|
|
|
|
function random(n) {
|
|
return Math.floor(Math.random() * n)
|
|
}
|
|
|
|
function makeText(size) {
|
|
var text = ''
|
|
for (var i = 0; i < size; i++) text += 'a'
|
|
return text
|
|
}
|
|
|
|
function checkEqual (value, expected) {
|
|
if (value != expected) throw ('expected ' + expected + ' got ' + value)
|
|
}
|
|
|
|
function deploy() {
|
|
var rs = new ReplSetTest({nodes: 3, oplogSize: 1000})
|
|
rs.startSet({dur: null})
|
|
var cfg = rs.getReplSetConfig()
|
|
cfg.members[2]['arbiterOnly'] = true
|
|
rs.initiate(cfg)
|
|
rs.awaitReplication()
|
|
return rs
|
|
}
|
|
|
|
function confirmWrite(db) {
|
|
var cmd = {getlasterror: 1, fsync: true, w: 2}
|
|
var res = db.runCommand(cmd)
|
|
if (! res.ok) throw (tojson(cmd) + 'failed: ' + tojson(res))
|
|
}
|
|
|
|
N = 10000
|
|
Text = makeText(1000)
|
|
|
|
function loadInitialData(rs) {
|
|
var db = rs.getMaster().getDB('test')
|
|
for (var i = 0; i < N; i++) db['col'].insert({x: i, text: Text})
|
|
confirmWrite(db)
|
|
}
|
|
|
|
function newMasterConnection(ports) {
|
|
for (var i = 0; i < ports.length; i++) {
|
|
try {
|
|
print ('Try connect to '+ i)
|
|
var conn = new Mongo("127.0.0.1:" + ports[i])
|
|
var rec = conn.getDB('admin').runCommand({ismaster: 1})
|
|
if (rec && rec.ok && rec['ismaster']) {
|
|
print ('Connected ' + i)
|
|
return conn }
|
|
// else close conn
|
|
} catch(e) {}
|
|
}
|
|
throw 'no master: ' + ports
|
|
}
|
|
|
|
function rsMaster(ports, oldConn) {
|
|
try {
|
|
var rec = oldConn.getDB('admin').runCommand({ismaster: 1})
|
|
if (rec['ismaster']) return oldConn
|
|
} catch (e) {}
|
|
return newMasterConnection(ports)
|
|
}
|
|
|
|
function queryAndUpdateData(ports) {return function(z) {
|
|
var conn = null
|
|
return function(i) {
|
|
function printFailure(e) {print ('Q&U' + z + '-' + i + ': ' + e)}
|
|
try {
|
|
sleep(1000 + (z * 500))
|
|
print('update ' + z + ' round ' + i)
|
|
var db
|
|
try {
|
|
conn = rsMaster(ports, conn)
|
|
db = conn.getDB('test')
|
|
} catch (e) {
|
|
printFailure(e)
|
|
return
|
|
}
|
|
var n
|
|
try {
|
|
db['col'].update({}, {$push: {'z': z}}, false, true)
|
|
n = db['col'].count({'z': z})
|
|
} catch (e) {
|
|
printFailure(e)
|
|
return
|
|
}
|
|
checkEqual (n, N)
|
|
sleep(1000)
|
|
try {
|
|
db['col'].update({}, {$pull: {'z': z}}, false, true)
|
|
n = db['col'].count({'z': z})
|
|
} catch (e) {
|
|
printFailure(e)
|
|
return
|
|
}
|
|
checkEqual (n, 0)
|
|
} catch (e) {throw ('(Q&U' + z + '-' + i + ') ' + e)}
|
|
}
|
|
}}
|
|
|
|
function killer(rs) {return function(i) {
|
|
try {
|
|
sleep(random(30) * 1000)
|
|
var r = random(rs.ports.length - 1)
|
|
print('Killing ' + r)
|
|
stopMongod(rs.getPort(r), 9) // hard kill
|
|
sleep(random(30) * 1000)
|
|
print('Restarting ' + r)
|
|
rs.restart(r, {dur: null})
|
|
} catch (e) {throw ('(Killer-' + i + ') ' + e)}
|
|
}}
|
|
|
|
function rsPorts(rs) {
|
|
ports = new Array()
|
|
for (var i = 0; i < rs.ports.length; i++) ports[i] = rs.getPort(i)
|
|
return ports
|
|
}
|
|
|
|
function go(numRounds) {
|
|
var rs = deploy()
|
|
loadInitialData(rs)
|
|
var jobs = map(queryAndUpdateData(rsPorts(rs)), [1,2,3,4,5])
|
|
parallel (numRounds, jobs, [killer(rs)])
|
|
sleep (2000)
|
|
rs.stopSet()
|
|
print("rsDurKillRestart1.js SUCCESS")
|
|
}
|