rdresumehandler.java

来自「Azureus is a powerful, full-featured, cr」· Java 代码 · 共 784 行 · 第 1/2 页

JAVA
784
字号
/*
 * Created on 31-Jul-2004
 * Created by Paul Gardner
 * Copyright (C) 2004 Aelitis, All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 * AELITIS, SARL au capital de 30,000 euros
 * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
 *
 */

package org.gudy.azureus2.core3.disk.impl.resume;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.io.File;

import org.gudy.azureus2.core3.logging.LGLogger;
import org.gudy.azureus2.core3.torrent.TOTorrent;
import org.gudy.azureus2.core3.torrent.TOTorrentException;
import org.gudy.azureus2.core3.util.*;

import org.gudy.azureus2.core3.config.*;
import org.gudy.azureus2.core3.download.*;
import org.gudy.azureus2.core3.disk.impl.*;
import org.gudy.azureus2.core3.disk.impl.access.*;
import org.gudy.azureus2.core3.disk.*;

import com.aelitis.azureus.core.diskmanager.cache.CacheFileManagerException;

/**
 * @author parg
 *
 */
public class 
RDResumeHandler
	implements ParameterListener
{
	protected DiskManagerHelper		disk_manager;
	protected DMWriterAndChecker	writer_and_checker;
	protected DownloadManagerState	download_manager_state;
	
	protected TOTorrent				torrent;
		
	protected int					nbPieces;
	protected int					pieceLength;
	protected int					lastPieceLength;
	
	protected boolean				bOverallContinue;
	
	protected boolean useFastResume = COConfigurationManager.getBooleanParameter("Use Resume", true);

	public 
	RDResumeHandler(
		DiskManagerHelper	_disk_manager,
		DMWriterAndChecker	_writer_and_checker )
	{
		disk_manager		= _disk_manager;
		writer_and_checker	= _writer_and_checker;
		
		download_manager_state	= disk_manager.getDownloadManager().getDownloadState();
		
		torrent			= disk_manager.getTorrent();
		nbPieces		= disk_manager.getNumberOfPieces();
		pieceLength		= disk_manager.getPieceLength();
		lastPieceLength	= disk_manager.getLastPieceLength();

	}
	
	public void
	start()
	{
		COConfigurationManager.addParameterListener("Use Resume", this);
		
		bOverallContinue	= true;
	}
	
	public void
	stop()
	{
		bOverallContinue	= false;
		
		COConfigurationManager.removeParameterListener("Use Resume", this);
	}
	
	public void 
	parameterChanged(
		String parameterName )
	{
	    useFastResume = COConfigurationManager.getBooleanParameter("Use Resume", true);
	}
	
	public void 
	checkAllPieces(
		boolean newfiles ) 
	{
		//long	start = System.currentTimeMillis();
		
		try{
			disk_manager.setState( DiskManager.CHECKING );
						
			boolean resumeEnabled = useFastResume;
			
				//disable fast resume if a new file was created
			
			if (newfiles){
				
				resumeEnabled = false;
			}
			
			boolean	resume_data_complete = false;
			
			
			final AESemaphore	pending_checks_sem 	= new AESemaphore( "RD:PendingChecks" );
			int					pending_check_num	= 0;

			DiskManagerPiece[]	pieces	= disk_manager.getPieces();


			if ( resumeEnabled ){
				
				boolean resumeValid = false;
				
				byte[] resumeArray = null;
				
				Map partialPieces = null;
				
				Map resumeMap = download_manager_state.getResumeData();
				
				if ( resumeMap != null ){
					
						// backward compatability here over path management changes :(
					
					String resume_key = 
						torrent.isSimpleTorrent()?
							disk_manager.getDownloadManager().getTorrentSaveDir():
							disk_manager.getDownloadManager().getTorrentSaveDirAndFile();
					
				
					String[]	resume_keys = new String[4];
			
						// see bug 869749 for explanation of this mangling
						
						// unfortunately, if the torrent hasn't been saved and restored then the
						// mangling with not yet have taken place. So we have to also try the 
						// original key (see 878015)
	
						// also I've introduced canonicalisation into the resume key (2.1.0.5), so until any migration
						// issues have been resolved we need to support both original + non-canonicalised forms
				
					resume_keys[0]	= resume_key;
					
					try{
						resume_keys[1]= new String( resume_key.getBytes(Constants.DEFAULT_ENCODING),Constants.BYTE_ENCODING);
						
						// System.out.println( "resume: path = " + ByteFormatter.nicePrint(path )+ ", mangled_path = " + ByteFormatter.nicePrint(mangled_path));
						
					}catch( Throwable e ){
						
						Debug.printStackTrace( e );
					}
					
					resume_keys[2]	= getCanonicalResumeKey( resume_key );
					
					try{
						resume_keys[3]= new String( resume_keys[2].getBytes(Constants.DEFAULT_ENCODING),Constants.BYTE_ENCODING);
						
						// System.out.println( "resume: path = " + ByteFormatter.nicePrint(path )+ ", mangled_path = " + ByteFormatter.nicePrint(mangled_path));
						
					}catch( Throwable e ){
						
						Debug.printStackTrace( e );
					}
				
					Map resumeDirectory = null;
					
					for (int i=0;i<resume_keys.length;i++){
						
						String	rk = resume_keys[i];
						
						if ( rk != null ){
								
							resumeDirectory	= (Map)resumeMap.get(rk);
							
							if ( resumeDirectory != null ){
								
								break;
							}
						}
					}
									
					if ( resumeDirectory != null ){
						
						try {
							
							resumeArray = (byte[])resumeDirectory.get("resume data");
							
							if ( resumeArray != null ){
								
								if ( resumeArray.length != pieces.length ){
								
									Debug.out( "Resume data array length mismatch: " + resumeArray.length + "/" + pieces.length );
									
									resumeArray	= null;
								}
							}
							
							partialPieces = (Map)resumeDirectory.get("blocks");
							
							resumeValid = ((Long)resumeDirectory.get("valid")).intValue() == 1;
							
								// if the torrent download is complete we don't need to invalidate the
								// resume data
							
							if ( isTorrentResumeDataComplete( 
									download_manager_state, 
									disk_manager.getDownloadManager().getTorrentSaveDir(),
									disk_manager.getDownloadManager().getTorrentSaveFile())){
								
								resume_data_complete	= true;
										
							}else{
								
								resumeDirectory.put("valid", new Long(0));
								
								download_manager_state.save();
							}
							
						}catch(Exception ignore){
							
							// ignore.printStackTrace();
						}
						
					}else{
						
						// System.out.println( "resume dir not found");
					}
				}
								
				if ( resumeArray == null ){
					
					resumeValid	= false;
					
					resumeArray	= new byte[pieces.length];
				}
				
					// calculate the current file sizes up front for performance reasons
				
				DiskManagerFileInfo[]	files = disk_manager.getFiles();
				
				Map	file_sizes = new HashMap();
				
				for (int i=0;i<files.length;i++){
					
					try{
						Long	len = new Long(((DiskManagerFileInfoImpl)files[i]).getCacheFile().getLength());
					
						file_sizes.put( files[i], len );
						
					}catch( CacheFileManagerException e ){
						
						Debug.printStackTrace(e);
					}
				}
				
				for (int i = 0; i < pieces.length && bOverallContinue; i++){ 
					
					DiskManagerPiece	dm_piece	= pieces[i];
					
					disk_manager.setPercentDone(((i + 1) * 1000) / nbPieces );
					
					boolean	ok = resumeArray[i] == 1;
					
						// valid resume data means that the resume array correctly represents
						// the state of pieces on disk, be they done or not
					
					if ( ok ){
					
							// at least check that file sizes are OK for this piece to be valid
						
						PieceList list = disk_manager.getPieceList(i);
						
						for (int j=0;j<list.size();j++){
							
							PieceMapEntry	entry = list.get(j);
							
							Long	file_size 		= (Long)file_sizes.get(entry.getFile());
							
							if ( file_size == null ){
								
								ok	= false;
								
								LGLogger.log(0, 0, LGLogger.INFORMATION, "Piece #" + i + ": file is missing, fails re-check." );

								break;
							}
							
							long	expected_size 	= entry.getOffset() + entry.getLength();
							
							if ( file_size.longValue() < expected_size ){
								
								ok	= false;
								
								LGLogger.log(0, 0, LGLogger.INFORMATION, "Piece #" + i + ": file is too small, fails re-check. File size = " + file_size + ", piece needs " + expected_size );

								break;
							}
						}
					}
					
					if ( ok ){
						
						dm_piece.setDone( ok );
						
					}else{								
						
							// We only need to recheck blocks that are marked as not-ok
							// if the resume data is invalid
						
						if ( !resumeValid ){
						
							try{
								writer_and_checker.checkPiece(
									i,
									new CheckPieceResultHandler()
									{
										public void
										processResult(
											int		piece_number,
											int		result,
											Object	user_data )
										{
											LGLogger.log(0, 0, LGLogger.INFORMATION, "Piece #" + piece_number + (result==CheckPieceResultHandler.OP_SUCCESS?" passed":" failed") + " re-check.");
		
											pending_checks_sem.release();
										}
									},
									null );
								
								pending_check_num++;
								
							}catch( Throwable e ){
							
								Debug.printStackTrace(e);
							}
						}
					}
				}
					
				if ( partialPieces != null && resumeValid ){
														
					Iterator iter = partialPieces.entrySet().iterator();
					
					while (iter.hasNext()) {
						
						Map.Entry key = (Map.Entry)iter.next();
						
						int pieceNumber = Integer.parseInt((String)key.getKey());
													
						List blocks = (List)partialPieces.get(key.getKey());
						
						Iterator iterBlock = blocks.iterator();
						
						while (iterBlock.hasNext()) {
							
							pieces[pieceNumber].setWritten(((Long)iterBlock.next()).intValue());
						}
					}
				}
			}else{
				
					// resume not enabled, recheck everything
				
				for (int i = 0; i < pieces.length && bOverallContinue; i++){ 
										
					disk_manager.setPercentDone(((i + 1) * 1000) / nbPieces );						
						
					try{

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?