From 4308df6f3b8a4e0fa962fa01c3bf73ca9ceca527 Mon Sep 17 00:00:00 2001 From: Eliot Horowitz Date: Thu, 22 Jul 2010 17:24:51 -0400 Subject: [PATCH] don't delete old chunk data until there aren't cursors iterating it SERVER-937 --- db/client.cpp | 2 +- db/clientcursor.cpp | 10 +++++++ db/clientcursor.h | 2 ++ jstests/sharding/cursor1.js | 8 +++--- s/d_migrate.cpp | 56 +++++++++++++++++++++++++++++++------ 5 files changed, 64 insertions(+), 14 deletions(-) diff --git a/db/client.cpp b/db/client.cpp index 442626f0930..f6ae695934a 100644 --- a/db/client.cpp +++ b/db/client.cpp @@ -193,7 +193,7 @@ namespace mongo { if ( doauth ) _auth( lockState ); - { + if ( _client->_curOp->getOp() != dbGetMore ){ // getMore's are special and should be handled else where string errmsg; if ( ! shardVersionOk( _ns , errmsg ) ){ msgasserted( StaleConfigInContextCode , (string)"shard version not ok in Client::Context: " + errmsg ); diff --git a/db/clientcursor.cpp b/db/clientcursor.cpp index 30b2ee88ca1..38e40fcb729 100644 --- a/db/clientcursor.cpp +++ b/db/clientcursor.cpp @@ -357,6 +357,16 @@ namespace mongo { client.shutdown(); } + void ClientCursor::find( const string& ns , set& all ){ + recursive_scoped_lock lock(ccmutex); + + for ( CCById::iterator i=clientCursorsById.begin(); i!=clientCursorsById.end(); ++i ){ + if ( i->second->ns == ns ) + all.insert( i->first ); + } + } + + ClientCursorMonitor clientCursorMonitor; } // namespace mongo diff --git a/db/clientcursor.h b/db/clientcursor.h index 2c5c52e3faf..46f3a2eb70b 100644 --- a/db/clientcursor.h +++ b/db/clientcursor.h @@ -338,6 +338,8 @@ public: static void informAboutToDeleteBucket(const DiskLoc& b); static void aboutToDelete(const DiskLoc& dl); + + static void find( const string& ns , set& all ); }; class ClientCursorMonitor : public BackgroundJob { diff --git a/jstests/sharding/cursor1.js b/jstests/sharding/cursor1.js index b0dcf714ab2..6b3b3bba51e 100644 --- a/jstests/sharding/cursor1.js +++ b/jstests/sharding/cursor1.js @@ -38,8 +38,8 @@ s.adminCommand( { movechunk : "test.foo" , find : { _id : 5 } , to : secondary.g assert.eq( 2, s.config.chunks.count() ); // the cursors should not have been affected -assert.eq( numObjs , cursor1.itcount() ); -assert.eq( numObjs , cursor2.itcount() ); -assert.eq( numObjs , cursor3.itcount() ); +assert.eq( numObjs , cursor1.itcount() , "c1" ); +assert.eq( numObjs , cursor2.itcount() , "c2" ); +assert.eq( numObjs , cursor3.itcount() , "c3" ); -s.stop() \ No newline at end of file +s.stop() diff --git a/s/d_migrate.cpp b/s/d_migrate.cpp index 6c1e05340f2..0701871e474 100644 --- a/s/d_migrate.cpp +++ b/s/d_migrate.cpp @@ -133,7 +133,47 @@ namespace mongo { ofstream* _out; }; + + struct OldDataCleanup { + string ns; + BSONObj min; + BSONObj max; + }; + + void cleanupOldData( OldDataCleanup cleanup ){ + Client::initThread( "moveChunkPostClean" ); + + set initial; + ClientCursor::find( cleanup.ns , initial ); + + Timer t; + while ( t.seconds() < 600 ){ // 10 minutes + sleepmillis( 20 ); + set now; + ClientCursor::find( cleanup.ns , now ); + + set left; + for ( set::iterator i=initial.begin(); i!=initial.end(); ++i ){ + CursorId id = *i; + if ( now.count(id) ) + left.insert( id ); + } + + if ( left.size() == 0 ) + break; + initial = left; + } + + ShardForceModeBlock sf; + writelock lk(cleanup.ns); + RemoveSaver rs(cleanup.ns,"post-cleanup"); + long long num = Helpers::removeRange( cleanup.ns , cleanup.min , cleanup.max , true , false , &rs ); + log() << "moveChunk deleted: " << num << endl; + + cc().shutdown(); + } + class ChunkCommandHelper : public Command { public: ChunkCommandHelper( const char * name ) @@ -598,17 +638,15 @@ namespace mongo { log( LL_WARNING ) << " deleting data before ensuring no more cursors TODO" << endl; timing.done(6); - // 7 - { - ShardForceModeBlock sf; - writelock lk(ns); - RemoveSaver rs(ns,"post-cleanup"); - long long num = Helpers::removeRange( ns , min , max , true , false , &rs ); - log() << "moveChunk deleted: " << num << endl; - result.appendNumber( "numDeleted" , num ); + + { // 7. + OldDataCleanup c; + c.ns = ns; + c.min = min.getOwned(); + c.max = max.getOwned(); + boost::thread t( boost::bind( &cleanupOldData , c ) ); } - timing.done(7); return true;