FileDocCategorySizeDatePackage
PEPieceImpl.javaAPI DocAzureus 3.0.3.418573Thu May 03 19:08:34 BST 2007org.gudy.azureus2.core3.peer.impl

PEPieceImpl

public class PEPieceImpl extends Object implements PEPiece
author
parg
author
MjrTom 2005/Oct/08: numerous changes for new piece-picking 2006/Jan/02: refactoring piece picking to elsewhere, and consolidations

Fields Summary
private static final LogIDs
LOGID
private final DiskManagerPiece
dmPiece
private final PEPeerManager
manager
private final int
nbBlocks
private long
creationTime
private final String[]
requested
private boolean
fully_requested
private final boolean[]
downloaded
private boolean
fully_downloaded
private long
time_last_download
private final String[]
writers
private List
writes
private String
reservedBy
private int
speed
private int
resumePriority
private Object
real_time_data
protected static final AEMonitor
class_mon
Constructors Summary
public PEPieceImpl(PEPeerManager _manager, DiskManagerPiece _dm_piece, int _pieceSpeed)
piece for tracking partially downloaded pieces

param
_manager the PEPeerManager
param
_dm_piece the backing dmPiece
param
_pieceSpeed the speed threshold for potential new requesters

	
                                 
	 
		 		 
			
                         
	
        creationTime =SystemTime.getCurrentTime();
		manager =_manager;
		dmPiece =_dm_piece;
        speed =_pieceSpeed;

		nbBlocks =dmPiece.getNbBlocks();

		requested =new String[nbBlocks];
        
        final boolean[] written =dmPiece.getWritten();
		if (written ==null)
			downloaded =new boolean[nbBlocks];
		else
			downloaded =(boolean[])written.clone();

        writers =new String[nbBlocks];
		writes =new ArrayList(0);
	
Methods Summary
protected voidaddWrite(PEPieceWriteImpl write)

		try{
			class_mon.enter();
			
			writes.add(write);
			
		}finally{
			
			class_mon.exit();
		}
	
public voidaddWrite(int blockNumber, java.lang.String sender, byte[] hash, boolean correct)

		addWrite( new PEPieceWriteImpl( blockNumber, sender, hash, correct ));
	
public voidcheckRequests()
This will scan each block looking for requested blocks. For each one, it'll verify if the PEPeer for it still exists and is still willing and able to upload data. If not, it'll unmark the block as requested.

return
int of how many were cleared (0 to nbBlocks)

        if ( getTimeSinceLastActivity() < 30*1000 ){
        	
            return;
        }
        
		int cleared = 0;
				
		for (int i=0; i<nbBlocks; i++){
		
			if (!downloaded[i] &&!dmPiece.isWritten(i)){
			
				final String			requester = requested[i];
				
				if ( requester != null ){
				
					if ( !manager.requestExists( 
							requester, 
							getPieceNumber(),
							i *DiskManager.BLOCK_SIZE, 
							getBlockSize( i ))){

                        clearRequested(i);
                        
						cleared++;
					}
				}
			}
		}
		
		if ( cleared > 0 ){
					
            if (Logger.isEnabled())
                Logger.log(new LogEvent(dmPiece.getManager().getTorrent(), LOGID, LogEvent.LT_WARNING,
                        "checkRequests(): piece #" +getPieceNumber()+" cleared " +cleared +" requests" ));
		}else{
			
			if ( fully_requested && getNbUnrequested() > 0 ){

		          if (Logger.isEnabled())
		                Logger.log(new LogEvent(dmPiece.getManager().getTorrent(), LOGID, LogEvent.LT_WARNING,
		                        "checkRequests(): piece #" +getPieceNumber()+" reset fully requested" ));

				fully_requested = false;
			}
		}
	
public voidclearDownloaded(int offset)
This flags the block at the given offset as NOT having been downloaded and the whole piece as not having been fully downloaded

param
blockNumber

        downloaded[offset /DiskManager.BLOCK_SIZE] =false;
       
        fully_downloaded	= false;
    
public voidclearRequested(int blockNumber)
This method clears the requested information for the given block unless the block has already been downloaded, in which case the writer's IP is recorded as a request for the block.

		requested[blockNumber] =downloaded[blockNumber] ?writers[blockNumber] :null;
		
		fully_requested = false;
	
public voidgetAndMarkBlock(PEPeer peer, int index)

		requested[index] = peer.getIp();
		
		if ( getNbUnrequested() <= 0 ){
			
			setRequested();
		}
	
public int[]getAndMarkBlocks(PEPeer peer, int nbWanted, boolean enable_request_hints)
This method scans a piece for the first unrequested block. Upon finding it, it counts how many are unrequested up to nbWanted. The blocks are marked as requested by the PEPeer Assumption - single threaded access to this TODO: this should return the largest span equal or smaller than nbWanted OR, probably a different method should do that, so this one can support 'more sequential' picking

		final String ip =peer.getIp();
        final boolean[] written =dmPiece.getWritten();
		int blocksFound =0;
		
		if ( enable_request_hints ){
			
			int[]	request_hint = peer.getRequestHint();
			
			if ( request_hint != null && request_hint[0] == dmPiece.getPieceNumber()){
				
					// try to honour the hint first
				
				int	hint_block_start 	= request_hint[1] / DiskManager.BLOCK_SIZE;
				int hint_block_count	=  ( request_hint[2] + DiskManager.BLOCK_SIZE-1 ) / DiskManager.BLOCK_SIZE;
				
				for (int i =hint_block_start; i < nbBlocks && i <hint_block_start + hint_block_count; i++)
				{
					while (blocksFound <nbWanted &&(i +blocksFound) <nbBlocks &&!downloaded[i +blocksFound]
					    &&requested[i +blocksFound] ==null &&(written ==null ||!written[i]))
					{
						requested[i +blocksFound] =ip;
						blocksFound++;
					}
					if (blocksFound >0){
												
						return new int[] {i, blocksFound};
					}
				}
			}
		}
		
		// scan piece to find first free block
		for (int i =0; i <nbBlocks; i++)
		{
			while (blocksFound <nbWanted &&(i +blocksFound) <nbBlocks &&!downloaded[i +blocksFound]
			    &&requested[i +blocksFound] ==null &&(written ==null ||!written[i]))
			{
				requested[i +blocksFound] =ip;
				blocksFound++;
			}
			if (blocksFound >0)
				return new int[] {i, blocksFound};
		}
		return new int[] {-1, 0};
	
public intgetAvailability()

return
int of availability in the swarm for this piece
see
org.gudy.azureus2.core3.peer.PEPeerManager.getAvailability(int pieceNumber)

        return manager.getAvailability(dmPiece.getPieceNumber());
    
public intgetBlockNumber(int offset)

        return offset /DiskManager.BLOCK_SIZE;
    
public intgetBlockSize(int blockNumber)

		if ( blockNumber == (nbBlocks - 1)){
			
			int	length = dmPiece.getLength();
			
			if ((length % DiskManager.BLOCK_SIZE) != 0){
				
				return( length % DiskManager.BLOCK_SIZE );
			}
		}
		
		return DiskManager.BLOCK_SIZE;
	
public longgetCreationTime()

        final long now =SystemTime.getCurrentTime();
        if (now >=creationTime &&creationTime >0)
            return creationTime;
        creationTime =now;
        return now;
    
public DiskManagerPiecegetDMPiece()

        return dmPiece;
    
public boolean[]getDownloaded()

    	return( downloaded );
    
public longgetLastDownloadTime(long now)

		if (time_last_download <=now)
			return time_last_download;
		return time_last_download =now;
	
public intgetLength()

		return dmPiece.getLength();
	
public PEPeerManagergetManager()

return
Returns the manager.

		return manager;
	
public intgetNbBlocks()

		return nbBlocks;
	
public intgetNbRequests()

        int result =0;
        for (int i =0; i <nbBlocks; i++)
        {
            if (!downloaded[i] &&requested[i] !=null)
                result++;
        }
        return result;
    
public intgetNbUnrequested()

        int result =0;
        final boolean[] written =dmPiece.getWritten();
        for (int i =0; i <nbBlocks; i++ )
        {
            if (!downloaded[i] &&requested[i] ==null &&(written ==null ||!written[i]))
                result++;
        }
        return result;
    
public intgetNbWritten()
This support method returns how many blocks have already been written from the dmPiece

return
int from dmPiece.getNbWritten()
see
org.gudy.azureus2.core3.disk.DiskManagerPiece.getNbWritten()

        return dmPiece.getNbWritten();
    
public intgetPieceNumber()

		return dmPiece.getPieceNumber();
	
public java.util.ListgetPieceWrites()

		List result;
		try{
			class_mon.enter();
			
			result = new ArrayList(writes);
		}finally{
			
			class_mon.exit();
		}
		return result;
	
public java.util.ListgetPieceWrites(int blockNumber)

		final List result;
		try{
			class_mon.enter();
			
			result = new ArrayList(writes);
			
		}finally{
			
			class_mon.exit();
		}
		final Iterator iter = result.iterator();
		while(iter.hasNext()) {
			final PEPieceWriteImpl write = (PEPieceWriteImpl) iter.next();
			if(write.getBlockNumber() != blockNumber)
				iter.remove();
		}
		return result;
	
public java.util.ListgetPieceWrites(PEPeer peer)

		final List result;
		try{
			class_mon.enter();
			
			result = new ArrayList(writes);
		}finally{
			class_mon.exit();
		}
		final Iterator iter = result.iterator();
		while(iter.hasNext()) {
			PEPieceWriteImpl write = (PEPieceWriteImpl) iter.next();
			if(peer == null || ! peer.getIp().equals(write.getSender()))
				iter.remove();
		}
		return result;
	
public java.util.ListgetPieceWrites(java.lang.String ip)

		final List result;
		
		try{
			class_mon.enter();
			
			result = new ArrayList(writes);
			
		}finally{
			
			class_mon.exit();
		}
		
		final Iterator iter = result.iterator();
		
		while(iter.hasNext()) {
			
			final PEPieceWriteImpl write = (PEPieceWriteImpl) iter.next();
			
			if ( !write.getSender().equals( ip )){
				
				iter.remove();
			}
		}
		
		return result;
	
public java.lang.ObjectgetRealTimeData()

		return( real_time_data );
	
public java.lang.StringgetReservedBy()

		return reservedBy;
	
public intgetResumePriority()

		return resumePriority;
	
public intgetSpeed()

		return speed;
	
public java.lang.StringgetString()

		String	text  = "";
		
		PiecePicker pp = manager.getPiecePicker();

		text	+= ( isRequestable()?"reqable,":"" );
		text	+= "req=" + getNbRequests() + ",";
		text	+= ( isRequested()?"reqstd,":"" );
		text	+= ( isDownloaded()?"downed,":"" );
		text	+= ( getReservedBy()!=null?"resrv,":"" );
		text	+= "speed=" + getSpeed() + ",";
		text	+= ( pp==null?("pri=" + getResumePriority()):pp.getPieceString(dmPiece.getPieceNumber()));
		
		if ( text.endsWith(",")){
			text = text.substring(0,text.length()-1);
		}
		
		return( text );
	
public longgetTimeSinceLastActivity()

        final long now =SystemTime.getCurrentTime();
        final long lastWriteTime =getLastDownloadTime(now);
        if (time_last_download >0 &&now >=time_last_download)
            return now -time_last_download;
        if (creationTime >0 &&now >=creationTime)
            return now -creationTime;
        creationTime =now;
        return 0;
    
public java.lang.String[]getWriters()

		return writers;
	
public boolean[]getWritten()
This support method returns the dmPiece's written array

return
boolean[] from the dmPiece
see
org.gudy.azureus2.core3.disk.DiskManagerPiece.getWritten()

        return dmPiece.getWritten();
    
public booleanhasUndownloadedBlock()

    	for (int i =0; i <nbBlocks; i++ ){
    		
			if (!downloaded[i]){
				
				return( true );
			}
		}
    	
    	return( false );
    
public booleanhasUnrequestedBlock()

return
true if the piece has any blocks that are not; Downloaded, Requested, or Written

		final boolean[] written =dmPiece.getWritten();
		for (int i =0; i <nbBlocks; i++ )
		{
			if (!downloaded[i] &&requested[i] ==null &&(written ==null ||!written[i]))
				return true;
		}
		return false;
	
public booleanisDownloaded()

    	return( fully_downloaded );
    
public booleanisDownloaded(int blockNumber)
Tells if a block has been downloaded

param
blockNumber the block in question
return
true if the block is downloaded already

		return downloaded[blockNumber];
	
public booleanisRequestable()

		return( dmPiece.isDownloadable() && !( fully_downloaded || fully_requested ));
	
public booleanisRequested()

		return( fully_requested );
	
public booleanisRequested(int blockNumber)
Tells if a block has been requested

param
blockNumber the block in question
return
true if the block is Requested already

		return requested[blockNumber] !=null;
	
public booleanisWritten()

        return dmPiece.isWritten();
    
public booleanisWritten(int block)

        return dmPiece.isWritten( block );
    
public voidreDownloadBlock(int blockNumber)
for a block that's already downloadedt, mark up the piece so that the block will get downloaded again. This is used when the piece fails hash-checking.

		downloaded[blockNumber] =false;
		requested[blockNumber] =null;
		fully_downloaded = false;
		writers[blockNumber] = null;
		dmPiece.reDownloadBlock(blockNumber);
	
public voidreDownloadBlocks(java.lang.String address)
finds all blocks downloaded by the given address and marks them up for re-downloading

param
address String

		for (int i =0; i <writers.length; i++ )
		{
			final String writer =writers[i];

			if (writer !=null &&writer.equals(address))
				reDownloadBlock(i);
		}
	
public voidreset()

		dmPiece.reset();
		for (int i =0; i <nbBlocks; i++)
		{
            requested[i] =null;
			downloaded[i] =false;
			writers[i] =null;
		}
		fully_downloaded = false;
		time_last_download = 0;
		reservedBy =null;
		real_time_data=null;
	
public voidsetDownloaded(int offset)
This flags the block at the given offset as having been downloaded If all blocks are now downloaed, sets the dmPiece as downloaded

param
blockNumber

		time_last_download =SystemTime.getCurrentTime();
		downloaded[offset /DiskManager.BLOCK_SIZE] =true;
        for (int i =0; i <nbBlocks; i++)
        {
            if (!downloaded[i])
                return;
        }
        
        fully_downloaded	= true;
        fully_requested		= false;
	
public voidsetLastRequestedPeerSpeed(int peerSpeed)

		// Up the speed on this piece?
		if (peerSpeed > speed ){
			speed++;
		}
	
public voidsetRealTimeData(java.lang.Object o)

		real_time_data = o;
	
public voidsetRequestable()

		fully_downloaded	= false;
		fully_requested		= false;
		
		dmPiece.setDownloadable();
	
public voidsetRequested()

		fully_requested	= true;
	
public booleansetRequested(PEPeer peer, int blockNumber)
Assumption - single threaded with getAndMarkBlock

		if (!downloaded[blockNumber])
		{
			requested[blockNumber] =peer.getIp();
			return true;
		}
		return false;
	
public voidsetReservedBy(java.lang.String peer)

		reservedBy =peer;
	
public voidsetResumePriority(int p)

		resumePriority =p;
	
public voidsetSpeed(int newSpeed)

		speed =newSpeed;
	
public voidsetWritten(PEPeer peer, int blockNumber)
This marks a given block as having been written by the given peer

param
peer the PEPeer that sent the data
param
blockNumber the block we're operating on

		writers[blockNumber] =peer.getIp();
		dmPiece.setWritten(blockNumber);