341 lines
10 KiB
JavaScript
341 lines
10 KiB
JavaScript
//
|
|
// Utilities related to background operations while other operations are working
|
|
//
|
|
|
|
/**
|
|
* Allows synchronization between background ops and the test operations
|
|
*/
|
|
var waitForLock = function( mongo, name ){
|
|
|
|
var ts = new ObjectId()
|
|
var lockColl = mongo.getCollection( "config.testLocks" )
|
|
|
|
lockColl.update({ _id : name, state : 0 }, { $set : { state : 0 } }, true)
|
|
|
|
//
|
|
// Wait until we can set the state to 1 with our id
|
|
//
|
|
|
|
var startTime = new Date().getTime()
|
|
|
|
assert.soon( function() {
|
|
lockColl.update({ _id : name, state : 0 }, { $set : { ts : ts, state : 1 } })
|
|
var gleObj = lockColl.getDB().getLastErrorObj()
|
|
|
|
if( new Date().getTime() - startTime > 20 * 1000 ){
|
|
print( "Waiting for..." )
|
|
printjson( gleObj )
|
|
printjson( lockColl.findOne() )
|
|
printjson( ts )
|
|
}
|
|
|
|
return gleObj.n == 1 || gleObj.updatedExisting
|
|
}, "could not acquire lock", 30 * 1000, 100 )
|
|
|
|
print( "Acquired lock " + tojson( { _id : name, ts : ts } ) + " curr : " +
|
|
tojson( lockColl.findOne({ _id : name }) ) )
|
|
|
|
// Set the state back to 0
|
|
var unlock = function(){
|
|
print( "Releasing lock " + tojson( { _id : name, ts : ts } ) + " curr : " +
|
|
tojson( lockColl.findOne({ _id : name }) ) )
|
|
lockColl.update({ _id : name, ts : ts }, { $set : { state : 0 } })
|
|
}
|
|
|
|
// Return an object we can invoke unlock on
|
|
return { unlock : unlock }
|
|
}
|
|
|
|
/**
|
|
* Allows a test or background op to say it's finished
|
|
*/
|
|
var setFinished = function( mongo, name, finished ){
|
|
if( finished || finished == undefined )
|
|
mongo.getCollection( "config.testFinished" ).update({ _id : name }, { _id : name }, true )
|
|
else
|
|
mongo.getCollection( "config.testFinished" ).remove({ _id : name })
|
|
}
|
|
|
|
/**
|
|
* Checks whether a test or background op is finished
|
|
*/
|
|
var isFinished = function( mongo, name ){
|
|
return mongo.getCollection( "config.testFinished" ).findOne({ _id : name }) != null
|
|
}
|
|
|
|
/**
|
|
* Sets the result of a background op
|
|
*/
|
|
var setResult = function( mongo, name, result, err ){
|
|
mongo.getCollection( "config.testResult" ).update({ _id : name }, { _id : name, result : result, err : err }, true )
|
|
}
|
|
|
|
/**
|
|
* Gets the result for a background op
|
|
*/
|
|
var getResult = function( mongo, name ){
|
|
return mongo.getCollection( "config.testResult" ).findOne({ _id : name })
|
|
}
|
|
|
|
/**
|
|
* Overrides the parallel shell code in mongo
|
|
*/
|
|
function startParallelShell( jsCode, port ){
|
|
|
|
var x;
|
|
if ( port ) {
|
|
x = startMongoProgramNoConnect( "mongo" , "--port" , port , "--eval" , jsCode );
|
|
} else {
|
|
x = startMongoProgramNoConnect( "mongo" , "--eval" , jsCode , db ? db.getMongo().host : null );
|
|
}
|
|
|
|
return function(){
|
|
jsTestLog( "Waiting for shell " + x + "..." )
|
|
waitProgram( x );
|
|
jsTestLog( "Shell " + x + " finished." )
|
|
};
|
|
}
|
|
|
|
startParallelOps = function( mongo, proc, args, context ){
|
|
|
|
var procName = proc.name + "-" + new ObjectId()
|
|
var seed = new ObjectId( new ObjectId().valueOf().split("").reverse().join("") )
|
|
.getTimestamp().getTime()
|
|
|
|
// Make sure we aren't finished before we start
|
|
setFinished( mongo, procName, false )
|
|
setResult( mongo, procName, undefined, undefined )
|
|
|
|
// TODO: Make this a context of its own
|
|
var procContext = { procName : procName,
|
|
seed : seed,
|
|
waitForLock : waitForLock,
|
|
setFinished : setFinished,
|
|
isFinished : isFinished,
|
|
setResult : setResult,
|
|
|
|
setup : function( context, stored ){
|
|
|
|
waitForLock = function(){
|
|
return context.waitForLock( db.getMongo(), context.procName )
|
|
}
|
|
setFinished = function( finished ){
|
|
return context.setFinished( db.getMongo(), context.procName, finished )
|
|
}
|
|
isFinished = function(){
|
|
return context.isFinished( db.getMongo(), context.procName )
|
|
}
|
|
setResult = function( result, err ){
|
|
return context.setResult( db.getMongo(), context.procName, result, err )
|
|
}
|
|
}}
|
|
|
|
var bootstrapper = function( stored ){
|
|
|
|
var procContext = stored.procContext
|
|
procContext.setup( procContext, stored )
|
|
|
|
var contexts = stored.contexts
|
|
eval( "contexts = " + contexts )
|
|
|
|
for( var i = 0; i < contexts.length; i++ ){
|
|
if( typeof( contexts[i] ) != "undefined" ){
|
|
// Evaluate all contexts
|
|
contexts[i]( procContext )
|
|
}
|
|
}
|
|
|
|
var operation = stored.operation
|
|
eval( "operation = " + operation )
|
|
|
|
var args = stored.args
|
|
eval( "args = " + args )
|
|
|
|
result = undefined
|
|
err = undefined
|
|
|
|
try{
|
|
result = operation.apply( null, args )
|
|
}
|
|
catch( e ){
|
|
err = e
|
|
}
|
|
|
|
setResult( result, err )
|
|
}
|
|
|
|
var contexts = [ RandomFunctionContext, context ]
|
|
|
|
var testDataColl = mongo.getCollection( "config.parallelTest" )
|
|
|
|
testDataColl.insert({ _id : procName,
|
|
bootstrapper : tojson( bootstrapper ),
|
|
operation : tojson( proc ),
|
|
args : tojson( args ),
|
|
procContext : procContext,
|
|
contexts : tojson( contexts ) })
|
|
|
|
assert.eq( null, testDataColl.getDB().getLastError() )
|
|
|
|
var bootstrapStartup =
|
|
"{ var procName = '" + procName + "'; " +
|
|
"var stored = db.getMongo().getCollection( '" + testDataColl + "' )" +
|
|
".findOne({ _id : procName }); " +
|
|
"var bootstrapper = stored.bootstrapper; " +
|
|
"eval( 'bootstrapper = ' + bootstrapper ); " +
|
|
"bootstrapper( stored ); " +
|
|
"}"
|
|
|
|
|
|
var oldDB = db
|
|
db = mongo.getDB( "test" )
|
|
|
|
jsTest.log( "Starting " + proc.name + " operations..." )
|
|
|
|
var rawJoin = startParallelShell( bootstrapStartup )
|
|
|
|
db = oldDB
|
|
|
|
|
|
var join = function(){
|
|
setFinished( mongo, procName, true )
|
|
|
|
rawJoin();
|
|
result = getResult( mongo, procName )
|
|
|
|
assert.neq( result, null )
|
|
|
|
if( result.err ) throw "Error in parallel ops " + procName + " : "
|
|
+ tojson( result.err )
|
|
|
|
else return result.result
|
|
}
|
|
|
|
join.isFinished = function(){
|
|
return isFinished( mongo, procName )
|
|
}
|
|
|
|
join.setFinished = function( finished ){
|
|
return setFinished( mongo, procName, finished )
|
|
}
|
|
|
|
join.waitForLock = function( name ){
|
|
return waitForLock( mongo, name )
|
|
}
|
|
|
|
return join
|
|
}
|
|
|
|
var RandomFunctionContext = function( context ){
|
|
|
|
Random.srand( context.seed );
|
|
|
|
Random.randBool = function(){ return Random.rand() > 0.5 }
|
|
|
|
Random.randInt = function( min, max ){
|
|
|
|
if( max == undefined ){
|
|
max = min
|
|
min = 0
|
|
}
|
|
|
|
return min + Math.floor( Random.rand() * max )
|
|
}
|
|
|
|
Random.randShardKey = function(){
|
|
|
|
var numFields = 2 //Random.randInt(1, 3)
|
|
|
|
var key = {}
|
|
for( var i = 0; i < numFields; i++ ){
|
|
var field = String.fromCharCode( "a".charCodeAt() + i )
|
|
key[ field ] = 1
|
|
}
|
|
|
|
return key
|
|
}
|
|
|
|
Random.randShardKeyValue = function( shardKey ){
|
|
|
|
var keyValue = {}
|
|
for( field in shardKey ){
|
|
keyValue[ field ] = Random.randInt(1, 100)
|
|
}
|
|
|
|
return keyValue
|
|
}
|
|
|
|
Random.randCluster = function(){
|
|
|
|
var numShards = 2 //Random.randInt( 1, 10 )
|
|
var rs = false //Random.randBool()
|
|
var st = new ShardingTest({ shards : numShards,
|
|
mongos : 4,
|
|
other : { separateConfig : true, rs : rs } })
|
|
|
|
return st
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Some utility operations
|
|
//
|
|
|
|
function moveOps( collName, options ){
|
|
|
|
options = options || {}
|
|
|
|
var admin = db.getMongo().getDB( "admin" )
|
|
var config = db.getMongo().getDB( "config" )
|
|
var shards = config.shards.find().toArray()
|
|
var shardKey = config.collections.findOne({ _id : collName }).key
|
|
|
|
while( ! isFinished() ){
|
|
|
|
var findKey = Random.randShardKeyValue( shardKey )
|
|
var toShard = shards[ Random.randInt( shards.length ) ]._id
|
|
|
|
try {
|
|
printjson( admin.runCommand({ moveChunk : collName,
|
|
find : findKey,
|
|
to : toShard }) )
|
|
}
|
|
catch( e ){
|
|
printjson( e )
|
|
}
|
|
|
|
sleep( 1000 )
|
|
}
|
|
|
|
jsTest.log( "Stopping moveOps..." )
|
|
}
|
|
|
|
function splitOps( collName, options ){
|
|
|
|
options = options || {}
|
|
|
|
var admin = db.getMongo().getDB( "admin" )
|
|
var config = db.getMongo().getDB( "config" )
|
|
var shards = config.shards.find().toArray()
|
|
var shardKey = config.collections.findOne({ _id : collName }).key
|
|
|
|
while( ! isFinished() ){
|
|
|
|
var middleKey = Random.randShardKeyValue( shardKey )
|
|
|
|
try {
|
|
printjson( admin.runCommand({ split : collName,
|
|
middle : middleKey }) )
|
|
}
|
|
catch( e ){
|
|
printjson( e )
|
|
}
|
|
|
|
sleep( 1000 )
|
|
}
|
|
|
|
jsTest.log( "Stopping splitOps..." )
|
|
}
|
|
|