1 /* 2 * Created on 08-Oct-2004 3 * Created by Paul Gardner 4 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 */ 19 20 package org.gudy.azureus2.core3.disk.impl; 21 22 /** 23 * @author parg 24 * @author MjrTom 25 * 2005/Oct/08: startPriority/resumePriority handling and minor clock fixes 26 * 2006/Jan/02: refactoring, change booleans to statusFlags 27 */ 28 29 import org.gudy.azureus2.core3.disk.*; 30 import org.gudy.azureus2.core3.disk.impl.piecemapper.DMPieceList; 31 32 public class DiskManagerPieceImpl 33 implements DiskManagerPiece 34 { 35 //private static final LogIDs LOGID = LogIDs.PIECES; 36 37 private static final byte PIECE_STATUS_NEEDED = 0x01; //want to have the piece 38 private static final byte PIECE_STATUS_WRITTEN = 0x20; //piece fully written to storage 39 private static final byte PIECE_STATUS_CHECKING = 0x40; //piece is being hash checked 40 41 private static final byte PIECE_STATUS_MASK_DOWNLOADABLE = 42 PIECE_STATUS_CHECKING | PIECE_STATUS_WRITTEN | PIECE_STATUS_NEEDED; 43 44 // 0x65; // Needed IS once again included in this 45 46 private static final byte PIECE_STATUS_MASK_NEEDS_CHECK = PIECE_STATUS_CHECKING | PIECE_STATUS_WRITTEN; 47 48 //private static boolean statusTested =false; 49 50 private final DiskManagerHelper diskManager; 51 private final int pieceNumber; 52 53 /** the number of blocks in this piece: can be short as this gives up to .5GB piece sizes with 16K blocks */ 54 55 private final short nbBlocks; 56 57 // to save memory the "written" field is only maintained for pieces that are 58 // downloading. A value of "null" means that either the piece hasn't started 59 // download or that it is complete. 60 // access to "written" is single-threaded (by the peer manager) apart from when 61 // the disk manager is saving resume data. 62 // actually this is not longer strictly true, as setDone is called asynchronously 63 // however, this issue can be worked around by working on a reference to the written data 64 // as problems only occur when switching from all-written to done=true, both of which signify 65 // the same state of affairs. 66 67 protected volatile boolean[] written; 68 69 private byte statusFlags; 70 71 /** it's *very* important to accurately maintain the "done" state of a piece. Currently the statusFlags 72 * are updated in a non-thread-safe manner so a 'done' field is maintained seperatly. Synchronizing 73 * access to statusFlags or done would cause a tremendous performance hit. 74 */ 75 private short read_count; 76 77 private boolean done; 78 DiskManagerPieceImpl(final DiskManagerHelper _disk_manager, final int pieceIndex, int length )79 public DiskManagerPieceImpl(final DiskManagerHelper _disk_manager, final int pieceIndex, int length ) 80 { 81 diskManager =_disk_manager; 82 pieceNumber = pieceIndex; 83 84 nbBlocks =(short)((length +DiskManager.BLOCK_SIZE -1) /DiskManager.BLOCK_SIZE); 85 86 statusFlags = PIECE_STATUS_NEEDED; 87 } 88 getManager()89 public DiskManager getManager() 90 { 91 return diskManager; 92 } 93 getPieceNumber()94 public int getPieceNumber() 95 { 96 return pieceNumber; 97 } 98 99 /** 100 * @return int number of bytes in the piece 101 */ getLength()102 public int getLength() 103 { 104 return( diskManager.getPieceLength( pieceNumber )); 105 } 106 getNbBlocks()107 public int getNbBlocks() 108 { 109 return nbBlocks; 110 } 111 112 public short getReadCount()113 getReadCount() 114 { 115 return( read_count ); 116 } 117 118 public void setReadCount( short c )119 setReadCount( 120 short c ) 121 { 122 read_count = c; 123 } 124 getBlockSize(final int blockNumber)125 public int getBlockSize(final int blockNumber) 126 { 127 if ( blockNumber == nbBlocks -1 ){ 128 129 int len = getLength() % DiskManager.BLOCK_SIZE; 130 131 if ( len != 0 ){ 132 133 return( len ); 134 } 135 } 136 137 return DiskManager.BLOCK_SIZE; 138 } 139 140 public boolean isSkipped()141 isSkipped() 142 { 143 final DMPieceList pieceList =diskManager.getPieceList(pieceNumber); 144 for (int i =0; i <pieceList.size(); i++){ 145 final DiskManagerFileInfoImpl file =pieceList.get(i).getFile(); 146 if ( file == null ){ 147 return( false ); // can be null during diskmanager startup 148 } 149 if ( !file.isSkipped()){ 150 return( false ); 151 } 152 } 153 return( true ); 154 } 155 isNeeded()156 public boolean isNeeded() 157 { 158 return (statusFlags &PIECE_STATUS_NEEDED) !=0; 159 } 160 calcNeeded()161 public boolean calcNeeded() 162 { 163 boolean filesNeeded =false; 164 final DMPieceList pieceList =diskManager.getPieceList(pieceNumber); 165 for (int i =0; i <pieceList.size(); i++) 166 { 167 final DiskManagerFileInfoImpl file =pieceList.get(i).getFile(); 168 final long fileLength =file.getLength(); 169 filesNeeded |=fileLength >0 &&file.getDownloaded() <fileLength &&!file.isSkipped(); 170 } 171 if (filesNeeded) 172 { 173 statusFlags |=PIECE_STATUS_NEEDED; 174 return true; 175 } 176 statusFlags &=~PIECE_STATUS_NEEDED; 177 return false; 178 } 179 180 public boolean 181 spansFiles() 182 { 183 DMPieceList pieceList = diskManager.getPieceList(pieceNumber); 184 185 return( pieceList.size() > 1 ); 186 } 187 clearNeeded()188 public void clearNeeded() 189 { 190 statusFlags &=~PIECE_STATUS_NEEDED; 191 } 192 setNeeded()193 public void setNeeded() 194 { 195 statusFlags |=PIECE_STATUS_NEEDED; 196 } 197 setNeeded(boolean b)198 public void setNeeded(boolean b) 199 { 200 if (b) 201 statusFlags |=PIECE_STATUS_NEEDED; 202 else 203 statusFlags &=~PIECE_STATUS_NEEDED; 204 } 205 isWritten()206 public boolean isWritten() 207 { 208 return (statusFlags &PIECE_STATUS_WRITTEN) !=0; 209 } 210 211 212 /** written[] can be null, in which case if the piece is Done, 213 * all blocks are complete otherwise no blocks are complete 214 */ getWritten()215 public boolean[] getWritten() 216 { 217 return written; 218 } 219 isWritten(final int blockNumber)220 public boolean isWritten(final int blockNumber) 221 { 222 if (done) 223 return true; 224 final boolean[] writtenRef =written; 225 if (writtenRef ==null) 226 return false; 227 return writtenRef[blockNumber]; 228 } 229 getNbWritten()230 public int getNbWritten() 231 { 232 if (done) 233 return nbBlocks; 234 final boolean[] writtenRef =written; 235 if (writtenRef ==null) 236 return 0; 237 int res =0; 238 for (int i =0; i <nbBlocks; i++ ) 239 { 240 if (writtenRef[i]) 241 res++; 242 } 243 return res; 244 } 245 setWritten(final int blockNumber)246 public void setWritten(final int blockNumber) 247 { 248 if (written ==null) 249 written =new boolean[nbBlocks]; 250 final boolean[] written_ref =written; 251 252 written_ref[blockNumber] =true; 253 for (int i =0; i <nbBlocks; i++) 254 { 255 if (!written_ref[i]) 256 return; 257 } 258 statusFlags |=PIECE_STATUS_WRITTEN; 259 } 260 isChecking()261 public boolean isChecking() 262 { 263 return (statusFlags &PIECE_STATUS_CHECKING) !=0; 264 } 265 setChecking()266 public void setChecking() 267 { 268 statusFlags |=PIECE_STATUS_CHECKING; 269 } 270 isNeedsCheck()271 public boolean isNeedsCheck() 272 { 273 return !done &&(statusFlags &PIECE_STATUS_MASK_NEEDS_CHECK) ==PIECE_STATUS_WRITTEN; 274 } 275 276 277 // this cannot be implemented the same as others could be 278 // because the true state of Done is only determined by 279 // having gone through setDoneSupport() calcDone()280 public boolean calcDone() 281 { 282 return done; 283 } 284 isDone()285 public boolean isDone() 286 { 287 return done; 288 } 289 setDone(boolean b)290 public void setDone(boolean b) 291 { 292 // we delegate this operation to the disk manager so it can synchronise the activity 293 if (b !=done) 294 { 295 diskManager.setPieceDone(this, b); 296 } 297 } 298 299 /** this is ONLY used by the disk manager to update the done state while synchronized 300 *i.e. don't use it else where! 301 * @param b 302 */ 303 setDoneSupport(final boolean b)304 public void setDoneSupport(final boolean b) 305 { 306 done =b; 307 if (done) 308 written =null; 309 } 310 setDownloadable()311 public void setDownloadable() 312 { 313 setDone(false); 314 statusFlags &=~(PIECE_STATUS_MASK_DOWNLOADABLE); 315 calcNeeded(); // Needed wouldn't have been calced before if couldn't download more 316 } 317 isDownloadable()318 public boolean isDownloadable() 319 { 320 return !done &&(statusFlags &PIECE_STATUS_MASK_DOWNLOADABLE) == PIECE_STATUS_NEEDED; 321 } 322 323 /** 324 * @return true if the piece is Needed and not Done 325 */ isInteresting()326 public boolean isInteresting() 327 { 328 return !done &&(statusFlags &PIECE_STATUS_NEEDED) != 0; 329 } 330 reset()331 public void reset() 332 { 333 setDownloadable(); 334 written =null; 335 } 336 reDownloadBlock(int blockNumber)337 public void reDownloadBlock(int blockNumber) 338 { 339 final boolean[] written_ref = written; 340 if (written_ref !=null) 341 { 342 written_ref[blockNumber] =false; 343 setDownloadable(); 344 } 345 } 346 347 348 /* 349 public static final void testStatus() 350 { 351 if (statusTested) 352 return; 353 354 statusTested =true; 355 int originalStatus =statusFlags; 356 357 for (int i =0; i <0x100; i++) 358 { 359 statusFlags =i; 360 Logger.log(new LogEvent(this, LOGID, LogEvent.LT_INFORMATION, 361 "Done:" +isDone() 362 +" Checking:" +isChecking() 363 +" Written:" +isWritten() 364 +" Downloaded:" +isDownloaded() 365 +" Requested:" +isRequested() 366 +" Needed:" +isNeeded() 367 +" Interesting:" +isInteresting() 368 +" Requestable:" +isRequestable() 369 +" EGMActive:" +isEGMActive() 370 +" EGMIgnored:" +isEGMIgnored() 371 )); 372 } 373 statusFlags =originalStatus; 374 } 375 */ 376 377 public String getString()378 getString() 379 { 380 String text = ""; 381 382 text += ( isNeeded()?"needed,":"" ); 383 text += ( isDone()?"done,":"" ); 384 385 if ( !isDone()){ 386 text += ( isDownloadable()?"downable,":"" ); 387 text += ( isWritten()?"written":("written " + getNbWritten())) + ","; 388 text += ( isChecking()?"checking":"" ); 389 } 390 391 if ( text.endsWith(",")){ 392 text = text.substring(0,text.length()-1); 393 } 394 return( text ); 395 } 396 } 397