package org.gudy.azureus2.core3.peer.impl; ///* // * File : PEPieceImpl.java // * Created : 15-Oct-2003 // * By : Olivier // * // * Azureus - a Java Bittorrent client // * // * 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. // * // * 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 ( see the LICENSE file ). // * // * 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 // */ // //package org.gudy.azureus2.core3.peer.impl; // ///** // * @author parg // * @author MjrTom // * 2005/Oct/08: numerous changes for new piece-picking // * 2006/Jan/02: refactoring piece picking to elsewhere, and consolidations // */ // //import java.util.*; // ////import org.gudy.azureus2.core3.disk.*; ////import org.gudy.azureus2.core3.logging.*; //import org.gudy.azureus2.core3.peer.*; //import org.gudy.azureus2.core3.util.*; // //import com.aelitis.azureus.core.peermanager.piecepicker.PiecePicker; // // //public class PEPieceImpl // implements PEPiece //{ //// private static final LogIDs LOGID = LogIDs.PIECES; // //// private final DiskManagerPiece dmPiece; // private final PEPeerManager manager; // // private final int nbBlocks; // number of blocks in this piece // 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; // using address for when they send bad/disconnect/reconnect // // //In end game mode, this limitation isn't used // private int speed; //slower peers dont slow down fast pieces too much // // private int resumePriority; // // private Object real_time_data; // // // experimental class level lock // protected static final AEMonitor class_mon = new AEMonitor( "PEPiece:class"); // // /** 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 // */ //// public PEPieceImpl( //// PEPeerManager _manager, //// DiskManagerPiece _dm_piece, //// int _pieceSpeed) //// { //// 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); //// } //// //// public DiskManagerPiece getDMPiece() //// { //// return dmPiece; //// } // // public long getCreationTime() // { // final long now =SystemTime.getCurrentTime(); // if (now >=creationTime &&creationTime >0) // return creationTime; // creationTime =now; // return now; // } // // public long getTimeSinceLastActivity() // { // 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 long getLastDownloadTime(final long now) // { // if (time_last_download <=now) // return time_last_download; // return time_last_download =now; // } // // /** Tells if a block has been requested // * @param blockNumber the block in question // * @return true if the block is Requested already // */ // public boolean isRequested(int blockNumber) // { // return requested[blockNumber] !=null; // } // // /** Tells if a block has been downloaded // * @param blockNumber the block in question // * @return true if the block is downloaded already // */ // public boolean isDownloaded(int blockNumber) // { // return downloaded[blockNumber]; // } // // /** 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 // */ // public void setDownloaded(int offset) // { // 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; // } // // /** 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 // */ // public void clearDownloaded(int offset) // { // downloaded[offset /DiskManager.BLOCK_SIZE] =false; // // fully_downloaded = false; // } // // public boolean // isDownloaded() // { // return( fully_downloaded ); // } // // public boolean[] // getDownloaded() // { // return( downloaded ); // } // // public boolean // hasUndownloadedBlock() // { // for (int i =0; i <nbBlocks; i++ ){ // // if (!downloaded[i]){ // // return( true ); // } // } // // return( false ); // } // // /** 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 // */ // public void setWritten(PEPeer peer, int blockNumber) // { // writers[blockNumber] =peer.getIp(); // dmPiece.setWritten(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. // */ // public void clearRequested(int blockNumber) // { // requested[blockNumber] =downloaded[blockNumber] ?writers[blockNumber] :null; // // fully_requested = false; // } // // public boolean // isRequested() // { // return( fully_requested ); // } // // public void // setRequested() // { // fully_requested = true; // } // // /** 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) // */ // /* // public int checkRequests() // { // if (getTimeSinceLastActivity() <30 *1000) // return 0; // int cleared =0; // boolean nullPeer =false; // for (int i =0; i <nbBlocks; i++) // { // if (!downloaded[i] &&!dmPiece.isWritten(i)) // { // final String requester =requested[i]; // final PEPeerTransport pt; // if (requester !=null) // { // pt =manager.getTransportFromAddress(requester); // if (pt !=null) // { // pt.setSnubbed(true); // if (!pt.isDownloadPossible()) // { // clearRequested(i); // cleared++; // } // } else // { // nullPeer =true; // clearRequested(i); // cleared++; // } // } // } // } // if (cleared >0) // { // dmPiece.clearRequested(); // if (Logger.isEnabled()) // Logger.log(new LogEvent(dmPiece.getManager().getTorrent(), LOGID, LogEvent.LT_WARNING, // "checkRequests(): piece #" +getPieceNumber()+" cleared " +cleared +" requests." // + (nullPeer ?" Null peer was detected." :""))); // } // return cleared; // } // */ // // /* // * Parg: replaced above commented out checking with one that verifies that the // * requests still exist. As piece-picker activity and peer disconnect logic is multi-threaded // * and full of holes, this is a stop-gap measure to prevent a piece from being left with // * requests that no longer exist // */ // // public void // checkRequests() // { // 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; // } // } // } // // // /** @return true if the piece has any blocks that are not; // * Downloaded, Requested, or Written // */ // public boolean hasUnrequestedBlock() // { // 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; // } // // /** // * 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 // */ // public int[] getAndMarkBlocks(PEPeer peer, int nbWanted, boolean enable_request_hints ) // { // 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 void getAndMarkBlock(PEPeer peer, int index ) // { // requested[index] = peer.getIp(); // // if ( getNbUnrequested() <= 0 ){ // // setRequested(); // } // } // // public int getNbRequests() // { // int result =0; // for (int i =0; i <nbBlocks; i++) // { // if (!downloaded[i] &&requested[i] !=null) // result++; // } // return result; // } // // public int getNbUnrequested() // { // 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; // } // // /** // * Assumption - single threaded with getAndMarkBlock // */ // public boolean setRequested(PEPeer peer, int blockNumber) // { // if (!downloaded[blockNumber]) // { // requested[blockNumber] =peer.getIp(); // return true; // } // return false; // } // // public boolean // isRequestable() // { // return( dmPiece.isDownloadable() && !( fully_downloaded || fully_requested )); // } // // public int // getBlockSize( // 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 int getBlockNumber(int offset) // { // return offset /DiskManager.BLOCK_SIZE; // } // // public int getNbBlocks() // { // return nbBlocks; // } // // public List getPieceWrites() // { // List result; // try{ // class_mon.enter(); // // result = new ArrayList(writes); // }finally{ // // class_mon.exit(); // } // return result; // } // // // public List getPieceWrites(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 List getPieceWrites(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 List // getPieceWrites( // 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 void reset() // { // 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 Object // getRealTimeData() // { // return( real_time_data ); // } // // public void // setRealTimeData( // Object o ) // { // real_time_data = o; // } // // protected void addWrite(PEPieceWriteImpl write) { // try{ // class_mon.enter(); // // writes.add(write); // // }finally{ // // class_mon.exit(); // } // } // // public void // addWrite( // int blockNumber, // String sender, // byte[] hash, // boolean correct ) // { // addWrite( new PEPieceWriteImpl( blockNumber, sender, hash, correct )); // } // // public String[] getWriters() // { // return writers; // } // // public int getSpeed() // { // return speed; // } // // public void setSpeed(int newSpeed) // { // speed =newSpeed; // } // // public void // setLastRequestedPeerSpeed( // int peerSpeed ) // { // // Up the speed on this piece? // if (peerSpeed > speed ){ // speed++; // } // } // // /** // * @return Returns the manager. // */ // public PEPeerManager getManager() // { // return manager; // } // // public void setReservedBy(String peer) // { // reservedBy =peer; // } // // public String getReservedBy() // { // return reservedBy; // } // // /** 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. // */ // public void reDownloadBlock(int blockNumber) // { // downloaded[blockNumber] =false; // requested[blockNumber] =null; // fully_downloaded = false; // writers[blockNumber] = null; // dmPiece.reDownloadBlock(blockNumber); // } // // /** finds all blocks downloaded by the given address // * and marks them up for re-downloading // * @param address String // */ // public void reDownloadBlocks(String address) // { // for (int i =0; i <writers.length; i++ ) // { // final String writer =writers[i]; // // if (writer !=null &&writer.equals(address)) // reDownloadBlock(i); // } // } // // public void setResumePriority(int p) // { // resumePriority =p; // } // // public int getResumePriority() // { // return resumePriority; // } // // /** // * @return int of availability in the swarm for this piece // * @see org.gudy.azureus2.core3.peer.PEPeerManager.getAvailability(int pieceNumber) // */ // public int getAvailability() // { // return manager.getAvailability(dmPiece.getPieceNumber()); // } // // /** 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() // */ // public int getNbWritten() // { // return dmPiece.getNbWritten(); // } // // /** This support method returns the dmPiece's written array // * @return boolean[] from the dmPiece // * @see org.gudy.azureus2.core3.disk.DiskManagerPiece.getWritten() // */ // public boolean[] getWritten() // { // return dmPiece.getWritten(); // } // public boolean isWritten() // { // return dmPiece.isWritten(); // } // // public boolean isWritten( int block) // { // return dmPiece.isWritten( block ); // } // public int getPieceNumber() // { // return dmPiece.getPieceNumber(); // } // // public int getLength() // { // return dmPiece.getLength(); // } // // public void setRequestable() // { // fully_downloaded = false; // fully_requested = false; // // dmPiece.setDownloadable(); // } // // public String // getString() // { // 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 ); // } //}