[gparted/psusi/refactor: 7/7] Thread the internal copy algorithm



commit a6e67f4ac55fc0a651c6eed5d3fbd47f3d2b9336
Author: Phillip Susi <psusi ubuntu com>
Date:   Sun Jan 20 10:33:54 2013 -0500

    Thread the internal copy algorithm
    
    Have the copy code create a background thread to do the actual copying so
    that it won't block the main loop.

 include/GParted_Core.h |   60 ++++++++++-----
 src/GParted_Core.cc    |  191 +++++++++++++++++++++--------------------------
 2 files changed, 126 insertions(+), 125 deletions(-)
---
diff --git a/include/GParted_Core.h b/include/GParted_Core.h
index d10ffc1..dd7ded3 100644
--- a/include/GParted_Core.h
+++ b/include/GParted_Core.h
@@ -170,25 +170,47 @@ private:
 
 	bool set_partition_type( const Partition & partition, OperationDetail & operationdetail ) ;
 
-	void set_progress_info( Sector total, Sector done, const Glib::Timer & timer, OperationDetail & operationdetail, bool readonly ) ;
-
-	bool copy_blocks( const Glib::ustring & src_device,
-			  const Glib::ustring & dst_device,
-			  Sector src_start,
-			  Sector dst_start,
-			  Byte_Value length,
-			  Byte_Value blocksize,
-			  OperationDetail & operationdetail,
-			  bool readonly,
-			  Byte_Value & total_done ) ;
-
-	bool copy_block( PedDevice * lp_device_src,
-			 PedDevice * lp_device_dst,
-			 Sector offset_src,
-			 Sector offset_dst,
-			 Byte_Value blocksize,
-			 Glib::ustring & error_message,
-			 bool readonly ) ; 
+	class copy_blocks {
+		const Glib::ustring & src_device;
+		const Glib::ustring & dst_device;
+		Byte_Value length;
+		Byte_Value blocksize;
+		OperationDetail &operationdetail;
+		bool readonly;
+		Byte_Value & total_done;
+		char *buf;
+		Byte_Value done;
+		PedDevice *lp_device_src;
+		PedDevice *lp_device_dst;
+		Sector offset_src;
+		Sector offset_dst;
+		Glib::Timer timer_total;
+		bool success;
+		Glib::ustring error_message;
+		bool set_progress_info();
+		void copy_thread();
+	public:
+		copy_blocks( const Glib::ustring & in_src_device,
+			     const Glib::ustring & in_dst_device,
+			     Sector src_start,
+			     Sector dst_start,
+			     Byte_Value in_length,
+			     Byte_Value in_blocksize,
+			     OperationDetail & in_operationdetail,
+			     bool in_readonly,
+			     Byte_Value & in_total_done ) :
+			src_device( in_src_device ),
+			dst_device ( in_dst_device ),
+			length ( in_length ),
+			blocksize ( in_blocksize ),
+			operationdetail ( in_operationdetail ),
+			readonly ( in_readonly ),
+			total_done ( in_total_done ),
+			offset_src ( src_start ),
+			offset_dst ( dst_start ) {};
+		bool copy();
+		void copy_block();
+	};
 	bool calibrate_partition( Partition & partition, OperationDetail & operationdetail ) ;
 	bool calculate_exact_geom( const Partition & partition_old,
 			           Partition & partition_new,
diff --git a/src/GParted_Core.cc b/src/GParted_Core.cc
index 40fd6d2..90ba96b 100644
--- a/src/GParted_Core.cc
+++ b/src/GParted_Core.cc
@@ -2573,7 +2573,7 @@ bool GParted_Core::copy_filesystem( const Glib::ustring & src_device,
 				      benchmark_blocksize,
 				      operationdetail .get_last_child(),
 				      readonly,
-				      total_done ) ;
+				      total_done ).copy();
 		timer.stop() ;
 
 		operationdetail .get_last_child() .get_last_child() .add_child( OperationDetail( 
@@ -2601,14 +2601,14 @@ bool GParted_Core::copy_filesystem( const Glib::ustring & src_device,
 
 	if ( succes && llabs( done ) < src_length )
 		succes = copy_blocks( src_device, 
-				    dst_device,
-				    src_start + ( dst_start > src_start ? 0 : (done / src_sector_size) ),
-				    dst_start + ( dst_start > src_start ? 0 : (done / dst_sector_size) ),
-				    src_length - llabs( done ),
-				    optimal_blocksize,
-				    operationdetail,
-				    readonly,
-				    total_done ) ;
+				      dst_device,
+				      src_start + ((done > 0 ? done : 0) / src_sector_size),
+				      dst_start + ((done > 0 ? done : 0) / dst_sector_size),
+				      src_length - llabs( done ),
+				      optimal_blocksize,
+				      operationdetail,
+				      readonly,
+				      total_done ).copy();
 
 	operationdetail .add_child( OperationDetail( 
 		String::ucompose( readonly ?
@@ -2766,15 +2766,12 @@ bool GParted_Core::set_partition_type( const Partition & partition, OperationDet
 	return return_value ;
 }
 	
-void GParted_Core::set_progress_info( Byte_Value total,
-				      Byte_Value done,
-				      const Glib::Timer & timer,
-				      OperationDetail & operationdetail,
-				      bool readonly ) 
+bool GParted_Core::copy_blocks::set_progress_info()
 {
-	operationdetail .fraction = done / static_cast<double>( total ) ;
+	Byte_Value done = llabs(this->done);
+	operationdetail.fraction = done / static_cast<double>( length );
 
-	std::time_t time_remaining = Utils::round( (total - done) / ( done / timer .elapsed() ) ) ;
+	std::time_t time_remaining = Utils::round( (length - done) / ( done / timer_total.elapsed() ) );
 
 	operationdetail .progress_text = 
 		String::ucompose( readonly ?
@@ -2783,7 +2780,7 @@ void GParted_Core::set_progress_info( Byte_Value total,
 				/*TO TRANSLATORS: looks like  1.00 MiB of 16.00 MiB copied (00:01:59 remaining) */
 				_("%1 of %2 copied (%3 remaining)"),
 				  Utils::format_size( done, 1 ),
-				  Utils::format_size( total,1 ),
+				  Utils::format_size( length,1 ),
 				  Utils::format_time( time_remaining) ) ; 
 			
 	operationdetail .set_description( 
@@ -2792,19 +2789,46 @@ void GParted_Core::set_progress_info( Byte_Value total,
 				_("%1 of %2 read") :
 				/*TO TRANSLATORS: looks like  1.00 MiB of 16.00 MiB copied */
 				_("%1 of %2 copied"),
-				Utils::format_size( done, 1 ), Utils::format_size( total, 1 ) ),
+				Utils::format_size( done, 1 ), Utils::format_size( length, 1 ) ),
 				FONT_ITALIC ) ;
+	return false;
+}
+
+void GParted_Core::copy_blocks::copy_thread()
+{
+	ped_device_sync( lp_device_dst );
+
+	success = true;
+
+	if ( done != 0 )
+	{
+		Byte_Value b = blocksize;
+		blocksize = done;
+		done = 0;
+		/* copy partial block first */
+		copy_block();
+		blocksize = b;
+	}
+	Glib::Timer timer_progress_timeout;
+	while( success && llabs( done ) < length )
+	{
+		copy_block();
+		if ( timer_progress_timeout .elapsed() >= 0.5 )
+		{
+			Glib::signal_idle().connect( sigc::mem_fun(
+							     *this,
+							     &GParted_Core::copy_blocks::set_progress_info) );
+			timer_progress_timeout.reset();
+		}
+	}
+	//set progress bar current info on completion
+	Glib::signal_idle().connect( sigc::mem_fun(
+					     *this,
+					     &GParted_Core::copy_blocks::set_progress_info) );
+	g_idle_add( (GSourceFunc)_mainquit, NULL );
 }
 	
-bool GParted_Core::copy_blocks( const Glib::ustring & src_device,
-				const Glib::ustring & dst_device,
-				Sector src_start,
-				Sector dst_start,
-				Byte_Value length,
-				Byte_Value blocksize,
-				OperationDetail & operationdetail,
-				bool readonly,
-				Byte_Value & total_done ) 
+bool GParted_Core::copy_blocks::copy()
 {
 	if ( blocksize > length )
 		blocksize = length ;
@@ -2820,11 +2844,10 @@ bool GParted_Core::copy_blocks( const Glib::ustring & src_device,
 				String::ucompose( _("copy %1 using a block size of %2"), Utils::format_size( length, 1 ),
 					Utils::format_size( blocksize, 1 ) ) ) ) ;
 
-	Byte_Value done = length % blocksize ; 
+	done = length % blocksize;
 
-	bool succes = false ;
-	PedDevice *lp_device_src = ped_device_get( src_device .c_str() );
-	PedDevice *lp_device_dst = src_device != dst_device ? ped_device_get( dst_device .c_str() ) : lp_device_src ;
+	lp_device_src = ped_device_get( src_device .c_str() );
+	lp_device_dst = src_device != dst_device ? ped_device_get( dst_device .c_str() ) : lp_device_src ;
 
 	if ( lp_device_src && lp_device_dst && ped_device_open( lp_device_src ) && ped_device_open( lp_device_dst ) )
 	{
@@ -2833,67 +2856,24 @@ bool GParted_Core::copy_blocks( const Glib::ustring & src_device,
 
 		//Handle situation where we need to perform the copy beginning
 		//  with the end of the partition and finishing with the start.
-		if ( dst_start > src_start )
+		if ( offset_src < offset_dst )
 		{
 			blocksize -= 2*blocksize ;
 			done -= 2*done ;
-			src_start += ( (length / src_sector_size) - 1 ) ;
+			offset_src += ( (length / src_sector_size) - 1 ) ;
 			/* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
-			dst_start += ( ((length + (dst_sector_size - 1))/ dst_sector_size) - 1 ) ;
+			offset_dst += ( ((length + (dst_sector_size - 1))/ dst_sector_size) - 1 ) ;
 		}
 
-		Glib::ustring error_message ;
 		buf = static_cast<char *>( malloc( llabs( blocksize ) ) ) ;
+		//add an empty sub which we will constantly update in the loop
+		operationdetail.get_last_child().add_child( OperationDetail( "", STATUS_NONE ) );
+
 		if ( buf )
 		{
-			ped_device_sync( lp_device_dst ) ;
-
-			succes = true ;
-			if ( done != 0 )
-				succes = copy_block( lp_device_src,
-						lp_device_dst,
-						src_start,
-						dst_start, 
-						done,
-						error_message,
-						readonly ) ;
-			if ( ! succes )
-				done = 0 ;
-
-			//add an empty sub which we will constantly update in the loop
-			operationdetail .get_last_child() .add_child( OperationDetail( "", STATUS_NONE ) ) ;
-
-			Glib::Timer timer_progress_timeout, timer_total ;
-			while( succes && llabs( done ) < length )
-			{
-				succes = copy_block( lp_device_src,
-						     lp_device_dst,
-						     src_start + (done / src_sector_size),
-						     dst_start + (done / dst_sector_size),
-						     blocksize,
-						     error_message,
-						     readonly ) ; 
-				if ( succes )
-					done += blocksize ;
-
-				if ( timer_progress_timeout .elapsed() >= 0.5 )
-				{
-					set_progress_info( length,
-							   llabs( done + blocksize ),
-							   timer_total,
-							   operationdetail .get_last_child() .get_last_child(),
-							   readonly ) ;
-			
-					timer_progress_timeout .reset() ;
-				}
-			}
-			//set progress bar current info on completion
-			set_progress_info( length,
-			                   llabs( done ),
-			                   timer_total,
-			                   operationdetail .get_last_child() .get_last_child(),
-			                   readonly ) ;
-			
+			Glib::Thread::create( sigc::mem_fun( *this, &GParted_Core::copy_blocks::copy_thread ),
+					      false );
+			Gtk::Main::run();
 			free( buf ) ;
 		}
 		else
@@ -2913,7 +2893,7 @@ bool GParted_Core::copy_blocks( const Glib::ustring & src_device,
 					Utils::format_size( length, 1 ) ),
 					FONT_ITALIC ) ;
 		
-		if ( ! succes && ! error_message .empty() )
+		if ( ! success && ! error_message .empty() )
 			operationdetail .get_last_child() .add_child( 
 				OperationDetail( error_message, STATUS_NONE, FONT_ITALIC ) ) ;
 		
@@ -2930,50 +2910,49 @@ bool GParted_Core::copy_blocks( const Glib::ustring & src_device,
 		}
 	}
 
-	operationdetail .get_last_child() .set_status( succes ? STATUS_SUCCES : STATUS_ERROR ) ;
-	return succes ;
+	operationdetail .get_last_child() .set_status( success ? STATUS_SUCCES : STATUS_ERROR ) ;
+	return success;
 }
 
-bool GParted_Core::copy_block( PedDevice * lp_device_src,
-			       PedDevice * lp_device_dst,
-			       Sector offset_src,
-			       Sector offset_dst,
-			       Byte_Value block_length,
-			       Glib::ustring & error_message,
-			       bool readonly ) 
+void GParted_Core::copy_blocks::copy_block()
 {
 	Byte_Value sector_size_src = lp_device_src ->sector_size ;
 	Byte_Value sector_size_dst = lp_device_dst ->sector_size ;
 
 	//Handle case where src and dst sector sizes are different.
 	//    E.g.,  5 sectors x 512 bytes/sector = ??? 2048 byte sectors
-	Sector num_blocks_src = (llabs(block_length) + (sector_size_src - 1) ) / sector_size_src ;
-	Sector num_blocks_dst = (llabs(block_length) + (sector_size_dst - 1) ) / sector_size_dst ;
+	Sector num_blocks_src = (llabs(blocksize) + (sector_size_src - 1) ) / sector_size_src;
+	Sector num_blocks_dst = (llabs(blocksize) + (sector_size_dst - 1) ) / sector_size_dst;
 
 	//Handle situation where we are performing copy operation beginning
 	//  with the end of the partition and finishing with the start.
-	if ( block_length < 0 )
+	if ( blocksize < 0 )
 	{
-		block_length = llabs( block_length ) ;
-		offset_src -= ( (block_length / sector_size_src) - 1 ) ;
-		/* Handle situation where src sector size is smaller than dst sector size and an additional partial dst sector is required. */
-		offset_dst -= ( ( (block_length + (sector_size_dst - 1)) / sector_size_dst) - 1 ) ;
+		offset_src += (blocksize / sector_size_src);
+		offset_dst += (blocksize / sector_size_dst);
 	}
 
-	if ( block_length != 0 )
+	if ( blocksize != 0 )
 	{
 		if ( ped_device_read( lp_device_src, buf, offset_src, num_blocks_src ) )
 		{
 			if ( readonly || ped_device_write( lp_device_dst, buf, offset_dst, num_blocks_dst ) )
-				return true ;
-			else
-				error_message = String::ucompose( _("Error while writing block at sector %1"), offset_dst ) ;
+				success = true;
+			else {
+				error_message = String::ucompose( _("Error while writing block at sector %1"), offset_dst );
+				success = false;
+			}
 		}
 		else
 			error_message = String::ucompose( _("Error while reading block at sector %1"), offset_src ) ;
 	}
-
-	return false ;
+	if ( blocksize > 0 )
+	{
+		offset_src += (blocksize / sector_size_src);
+		offset_dst += (blocksize / sector_size_dst);
+	}
+	if( success )
+		done += blocksize;
 }
 
 bool GParted_Core::calibrate_partition( Partition & partition, OperationDetail & operationdetail ) 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]