Permalink
Browse files

SERVER-4621 noBalance flag for sharded collections

  • Loading branch information...
Greg Studer
Greg Studer committed Jan 6, 2012
1 parent aa853ed commit 218fea2e18f4f22104ad531e6cabcd34c3304245
@@ -0,0 +1,77 @@
+// Tests whether the noBalance flag disables balancing for collections
+
+var st = new ShardingTest({ shards : 2, mongos : 1, verbose : 1 })
+
+// Initially stop balancing
+st.stopBalancer()
+
+var shardAName = st._shardNames[0]
+var shardBName = st._shardNames[1]
+
+var collA = st.s.getCollection( jsTest.name() + ".collA" )
+var collB = st.s.getCollection( jsTest.name() + ".collB" )
+
+// Shard two collections
+st.shardColl( collA, { _id : 1 }, false )
+st.shardColl( collB, { _id : 1 }, false )
+
+// Split into a lot of chunks so balancing can occur
+for( var i = 0; i < 10 - 1; i++ ){ // 10 chunks total
+ collA.getMongo().getDB("admin").runCommand({ split : collA + "", middle : { _id : i } })
+ collA.getMongo().getDB("admin").runCommand({ split : collB + "", middle : { _id : i } })
+}
+
+// Disable balancing on one collection
+sh.disableBalancing( collB )
+
+jsTest.log( "Balancing disabled on " + collB )
+printjson( collA.getDB().getSisterDB( "config" ).collections.find().toArray() )
+
+st.startBalancer()
+
+// Make sure collA gets balanced
+assert.soon( function(){
+ var shardAChunks = st.s.getDB( "config" ).chunks.find({ _id : sh._collRE( collA ), shard : shardAName }).itcount()
+ var shardBChunks = st.s.getDB( "config" ).chunks.find({ _id : sh._collRE( collA ), shard : shardBName }).itcount()
+ printjson({ shardA : shardAChunks, shardB : shardBChunks })
+ return shardAChunks == shardBChunks
+}, "" + collA + " chunks not balanced!", 5 * 60 * 1000 )
+
+jsTest.log( "Chunks for " + collA + " are balanced." )
+
+// Check that the collB chunks were not moved
+var shardAChunks = st.s.getDB( "config" ).chunks.find({ _id : sh._collRE( collB ), shard : shardAName }).itcount()
+var shardBChunks = st.s.getDB( "config" ).chunks.find({ _id : sh._collRE( collB ), shard : shardBName }).itcount()
+printjson({ shardA : shardAChunks, shardB : shardBChunks })
+assert( shardAChunks == 0 || shardBChunks == 0 )
+
+// Re-enable balancing for collB
+sh.enableBalancing( collB )
+
+// Make sure that collB is now balanced
+assert.soon( function(){
+ var shardAChunks = st.s.getDB( "config" ).chunks.find({ _id : sh._collRE( collB ), shard : shardAName }).itcount()
+ var shardBChunks = st.s.getDB( "config" ).chunks.find({ _id : sh._collRE( collB ), shard : shardBName }).itcount()
+ printjson({ shardA : shardAChunks, shardB : shardBChunks })
+ return shardAChunks == shardBChunks
+}, "" + collB + " chunks not balanced!", 5 * 60 * 1000 )
+
+jsTest.log( "Chunks for " + collB + " are balanced." )
+
+// Re-disable balancing for collB
+sh.disableBalancing( collB )
+
+// Make sure auto-migrates on insert don't move chunks
+var lastMigration = sh._lastMigration( collB )
+
+for( var i = 0; i < 1000000; i++ ){
+ collB.insert({ _id : i, hello : "world" })
+}
+
+printjson( lastMigration )
+printjson( sh._lastMigration( collB ) )
+
+if( lastMigration == null ) assert.eq( null, sh._lastMigration( collB ) )
+else assert.eq( lastMigration.time, sh._lastMigration( collB ).time )
+
+st.stop()
View
@@ -156,8 +156,13 @@ namespace mongo {
BSONObj col = cursor->nextSafe();
// sharded collections will have a shard "key".
- if ( ! col["key"].eoo() )
+ if ( ! col["key"].eoo() && ! col["noBalance"].trueValue() ){
collections.push_back( col["_id"].String() );
+ }
+ else if( col["noBalance"].trueValue() ){
+ LOG(1) << "not balancing collection " << col["_id"].String() << ", explicitly disabled" << endl;
+ }
+
}
cursor.reset();
View
@@ -375,17 +375,18 @@ namespace mongo {
_dataWritten = 0; // we're splitting, so should wait a bit
}
-
+ bool shouldBalance = grid.shouldBalance( _manager->getns() );
log() << "autosplitted " << _manager->getns() << " shard: " << toString()
<< " on: " << splitPoint << " (splitThreshold " << splitThreshold << ")"
#ifdef _DEBUG
<< " size: " << getPhysicalSize() // slow - but can be useful when debugging
#endif
- << ( res["shouldMigrate"].eoo() ? "" : " (migrate suggested)" ) << endl;
+ << ( res["shouldMigrate"].eoo() ? "" : (string)" (migrate suggested" +
+ ( shouldBalance ? ")" : ", but no migrations allowed)" ) ) << endl;
BSONElement shouldMigrate = res["shouldMigrate"]; // not in mongod < 1.9.1 but that is ok
- if (!shouldMigrate.eoo() && grid.shouldBalance()){
+ if ( ! shouldMigrate.eoo() && shouldBalance ){
BSONObj range = shouldMigrate.embeddedObject();
BSONObj min = range["min"].embeddedObject();
BSONObj max = range["max"].embeddedObject();
View
@@ -378,18 +378,35 @@ namespace mongo {
return ok;
}
- bool Grid::shouldBalance() const {
+ /*
+ * Returns whether balancing is enabled, with optional namespace "ns" parameter for balancing on a particular
+ * collection.
+ */
+ bool Grid::shouldBalance( const string& ns ) const {
+
ShardConnection conn( configServer.getPrimary() , "" );
+ BSONObj balancerDoc;
+ BSONObj collDoc;
- // look for the stop balancer marker
- BSONObj balancerDoc = conn->findOne( ShardNS::settings, BSON( "_id" << "balancer" ) );
- conn.done();
+ try {
+ // look for the stop balancer marker
+ balancerDoc = conn->findOne( ShardNS::settings, BSON( "_id" << "balancer" ) );
+ if( ns.size() > 0 ) collDoc = conn->findOne( ShardNS::collection, BSON( "_id" << ns ) );
+ conn.done();
+ }
+ catch( DBException& e ){
+ conn.kill();
+ warning() << "could not determine whether balancer should be running, error getting config data from " << conn.getHost() << causedBy( e ) << endl;
+ // if anything goes wrong, we shouldn't try balancing
+ return false;
+ }
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
if ( _balancerStopped( balancerDoc ) || ! _inBalancingWindow( balancerDoc , now ) ) {
return false;
}
+ if( collDoc["noBalance"].trueValue() ) return false;
return true;
}
View
@@ -80,7 +80,7 @@ namespace mongo {
/**
* @return true if the chunk balancing functionality is enabled
*/
- bool shouldBalance() const;
+ bool shouldBalance( const string& ns = "" ) const;
/**
*
@@ -257,3 +257,63 @@ sh.waitForBalancer = function( onOrNot, timeout, interval ){
}
+sh.disableBalancing = function( coll ){
+ var dbase = db
+ if( coll instanceof DBCollection ) dbase = coll.getDB()
+ dbase.getSisterDB( "config" ).collections.update({ _id : coll + "" }, { $set : { "noBalance" : true } })
+}
+
+sh.enableBalancing = function( coll ){
+ var dbase = db
+ if( coll instanceof DBCollection ) dbase = coll.getDB()
+ dbase.getSisterDB( "config" ).collections.update({ _id : coll + "" }, { $set : { "noBalance" : false } })
+}
+
+/*
+ * Can call _lastMigration( coll ), _lastMigration( db ), _lastMigration( st ), _lastMigration( mongos )
+ */
+sh._lastMigration = function( ns ){
+
+ var coll = null
+ var dbase = null
+ var config = null
+
+ if( ! ns ){
+ config = db.getSisterDB( "config" )
+ }
+ else if( ns instanceof DBCollection ){
+ coll = ns
+ config = coll.getDB().getSisterDB( "config" )
+ }
+ else if( ns instanceof DB ){
+ dbase = ns
+ config = dbase.getSisterDB( "config" )
+ }
+ else if( ns instanceof ShardingTest ){
+ config = ns.s.getDB( "config" )
+ }
+ else if( ns instanceof Mongo ){
+ config = ns.getDB( "config" )
+ }
+ else {
+ // String namespace
+ ns = ns + ""
+ if( ns.indexOf( "." ) > 0 ){
+ config = db.getSisterDB( "config" )
+ coll = db.getMongo().getCollection( ns )
+ }
+ else{
+ config = db.getSisterDB( "config" )
+ dbase = db.getSisterDB( ns )
+ }
+ }
+
+ var searchDoc = { what : /^moveChunk/ }
+ if( coll ) searchDoc.ns = coll + ""
+ if( dbase ) searchDoc.ns = new RegExp( "^" + dbase + "\\." )
+
+ var cursor = config.changelog.find( searchDoc ).sort({ time : -1 }).limit( 1 )
+ if( cursor.hasNext() ) return cursor.next()
+ else return null
+}
+

0 comments on commit 218fea2

Please sign in to comment.