📄 piecepickerimpl.java
字号:
if ( pePiece != null ){
String peerReserved = pePiece.getReservedBy();
if ( peerReserved != null ){
if ( peerReserved.equals(pt.getIp())){
pePiece.setReservedBy( null );
}
}
}
// note, pieces reserved to peers that get disconnected are released in pepeercontrol
reservedPieceNumber = -1;
}
final int peerSpeed =(int) pt.getStats().getDataReceiveRate() /1000; // how many KB/s has the peer has been sending
final int lastPiece =pt.getLastPiece();
final boolean globalRarestOverride =isRarestOverride();
final int nbSnubbed =peerControl.getNbPeersSnubbed();
long resumeMinAvail =Long.MAX_VALUE;
int resumeMaxPriority =Integer.MIN_VALUE;
boolean resumeIsRarest =false; // can the peer continuea piece with lowest avail of all pieces we want
BitFlags startCandidates =null;
int startMaxPriority =Integer.MIN_VALUE;
int startMinAvail =Integer.MAX_VALUE;
boolean startIsRarest =false;
int priority; // aggregate priority of piece under inspection (start priority or resume priority for pieces to be resumed)
int avail =0; // the swarm-wide availability level of the piece under inspection
long pieceAge; // how long since the PEPiece first started downloading (requesting, actually)
final int startI =peerHavePieces.start;
final int endI =peerHavePieces.end;
int i;
final int[] peerPriorities = pt.getPriorityOffsets();
final long now =SystemTime.getCurrentTime();
// Try to continue a piece already loaded, according to priority
for (i =startI; i <=endI; i++)
{
// is the piece available from this peer?
if (peerHavePieces.flags[i])
{
priority =startPriorities[i];
if ( peerPriorities != null ){
if ( priority >= 0 ){
priority += peerPriorities[i];
}
}
final DiskManagerPiece dmPiece =dmPieces[i];
if ( priority >=0 && dmPiece.isDownloadable()){
final PEPiece pePiece = pePieces[i];
// if we are considering realtime pieces then don't bother with non-realtime ones
if (( pePiece == null || pePiece.isRequestable())){
// if this priority exceeds the priority-override threshold then we override rarity
boolean pieceRarestOverride = priority>=PRIORITY_OVERRIDES_RAREST?true:globalRarestOverride;
// piece is: Needed, not fully: Requested, Downloaded, Written, hash-Checking or Done
avail =availability[i];
if (avail ==0 )
{ // maybe we didn't know we could get it before
availability[i] =1; // but the peer says s/he has it
avail =1;
}
// is the piece active
if (pePiece !=null)
{
// How many requests can still be made on this piece?
final int freeReqs =pePiece.getNbUnrequested();
if (freeReqs <=0)
{
pePiece.setRequested();
continue;
}
// Don't touch pieces reserved for others
final String peerReserved =pePiece.getReservedBy();
if (peerReserved !=null)
{
if (!peerReserved.equals(pt.getIp()))
continue; //reserved to somebody else
// the peer forgot this is reserved to him; re-associate it
pt.setReservedPieceNumber(i);
return i;
}
final int pieceSpeed =pePiece.getSpeed();
final long timeSinceLastActivity =pePiece.getTimeSinceLastActivity();
// Snubbed peers or peers slower than the piece can only request on the piece if;
// they're the sole source OR
// it's the same as the last piece they were on AND there's enough free blocks
// TODO: instead of 3, should count how many peers are snubbed and use that
if (avail >1 &&(freeReqs <3 ||pieceSpeed -1 >=freeReqs *peerSpeed))
{
// unless the piece has been inactive too long,
// don't request from snubbed peers UNLESS;
// it's possible all sources for the piece are snubbed,
// don't request from slow peers UNLESS;
// it was the last piece requested from them already
if (timeSinceLastActivity < 10 *60*1000
&&(avail >nbSnubbed &&pt.isSnubbed()) ||(peerSpeed <pieceSpeed &&i !=lastPiece))
continue;
}
if (avail <=resumeMinAvail)
{
priority +=pieceSpeed;
priority +=(i ==lastPiece) ?PRIORITY_W_SAME_PIECE :0;
// Adjust priority for purpose of continuing pieces
// how long since last written to (if written to)
priority +=timeSinceLastActivity /PRIORITY_DW_STALE;
// how long since piece was started
pieceAge =now -pePiece.getCreationTime();
if (pieceAge >0)
priority +=PRIORITY_W_AGE *pieceAge /(PRIORITY_DW_AGE *dmPiece.getNbBlocks());
// how much is already written to disk
priority +=(PRIORITY_W_PIECE_DONE *dmPiece.getNbWritten()) /dmPiece.getNbBlocks();
pePiece.setResumePriority(priority);
if (avail <resumeMinAvail &&(!pieceRarestOverride ||priority >=resumeMaxPriority)
||(priority >resumeMaxPriority &&(!resumeIsRarest ||pieceRarestOverride)))
{ // this piece seems like best choice for resuming
// Verify it's still possible to get a block to request from this piece
if (pePiece.hasUnrequestedBlock())
{ // change the different variables to reflect interest in this block
reservedPieceNumber =i;
resumeMinAvail =avail;
resumeMaxPriority =priority;
resumeIsRarest =avail <=globalMinOthers; // only going to try to resume one
}
}
}
} else if (avail <=globalMinOthers &&!pieceRarestOverride)
{ // rarest pieces only from now on
if (!startIsRarest)
{ // 1st rarest piece
if (startCandidates ==null)
startCandidates =new BitFlags(nbPieces);
startMaxPriority =priority;
startMinAvail =avail;
startIsRarest =avail <=globalMinOthers;
startCandidates.setOnly(i); // clear the non-rarest bits in favor of only rarest
} else if (priority >startMaxPriority)
{ // continuing rarest, higher priority level
if (startCandidates ==null)
startCandidates =new BitFlags(nbPieces);
startMaxPriority =priority;
startCandidates.setOnly(i);
} else if (priority ==startMaxPriority)
{ // continuing rares, same priority level
startCandidates.setEnd(i);
}
} else if (!startIsRarest ||pieceRarestOverride)
{ // not doing rarest pieces
if (priority >startMaxPriority)
{ // new priority level
if (startCandidates ==null)
startCandidates =new BitFlags(nbPieces);
startMaxPriority =priority;
startMinAvail =avail;
startIsRarest =avail <=globalMinOthers;
startCandidates.setOnly(i);
} else if (priority ==startMaxPriority)
{ // continuing same priority level
if (avail <startMinAvail)
{ // same priority, new availability level
startMinAvail =avail;
startIsRarest =avail <=globalMinOthers;
startCandidates.setOnly(i);
} else if (avail ==startMinAvail)
{ // same priority level, same availability level
startCandidates.setEnd(i);
}
}
}
}
}
}
}
// can & should or must resume a piece?
if (reservedPieceNumber >=0 &&(resumeIsRarest ||!startIsRarest ||globalRarestOverride ||startCandidates ==null ||startCandidates.nbSet <=0))
return reservedPieceNumber;
// this would allow more non-rarest pieces to be resumed so they get completed so they can be re-shared,
// which can make us intersting to more peers, and generally improve the speed of the swarm,
// however, it can sometimes be hard to get the rarest pieces, such as when a holder unchokes very infrequently
// 20060312[MjrTom] this can lead to TOO many active pieces, so do the extra check with arbitrary # of active pieces
final boolean resumeIsBetter;
if (reservedPieceNumber >=0 &&globalMinOthers >0 &&peerControl.getNbActivePieces() >32) // check at arbitrary figure of 32 pieces
{
resumeIsBetter =(resumeMaxPriority /resumeMinAvail) >(startMaxPriority /globalMinOthers);
if (Constants.isCVSVersion() &&Logger.isEnabled())
Logger.log(new LogEvent(new Object[] {pt, peerControl}, LOGID,
"Start/resume choice; piece #:" +reservedPieceNumber +" resumeIsBetter:" +resumeIsBetter
+" globalMinOthers=" +globalMinOthers
+" startMaxPriority=" +startMaxPriority +" startMinAvail=" +startMinAvail
+" resumeMaxPriority=" +resumeMaxPriority +" resumeMinAvail=" +resumeMinAvail
+" : " +pt));
if (resumeIsBetter)
return reservedPieceNumber;
}
// start a new piece; select piece from start candidates bitfield
return getPieceToStart(startCandidates);
}
/**
* @param startCandidates BitFlags of potential candidates to choose from
* @return int the piece number that was chosen to be started. Note it's possible for
* the chosen piece to have been started already (by another thread).
* This method considers that potential to not be relevant.
*/
protected final int getPieceToStart(final BitFlags startCandidates)
{
if (startCandidates ==null ||startCandidates.nbSet <=0)
return -1;
if (startCandidates.nbSet ==1)
return startCandidates.start;
final int direction =RandomUtils.generateRandomPlusMinus1();
final int startI;
if (direction ==1)
startI =startCandidates.start;
else
startI =startCandidates.end;
// randomly select a bit flag to be the one
final int targetNb =RandomUtils.generateRandomIntUpto(startCandidates.nbSet);
// figure out the piece number of that selected bitflag
int foundNb =-1;
for (int i =startI; i <=startCandidates.end &&i >=startCandidates.start; i +=direction)
{
// is piece flagged
if (startCandidates.flags[i])
{
foundNb++;
if (foundNb >=targetNb)
return i;
}
}
return -1;
}
public final boolean hasDownloadablePiece()
{
return hasNeededUndonePiece;
}
public final long getNeededUndonePieceChange()
{
return neededUndonePieceChange;
}
private final void checkEndGameMode()
{
if (peerControl.getNbSeeds() +peerControl.getNbPeers() <3)
return;
final long now =SystemTime.getCurrentTime();
// We can't come back from end-game mode
if (endGameMode ||endGameModeAbandoned)
{
if (!endGameModeAbandoned)
{
if (now -timeEndGameModeEntered >END_GAME_MODE_TIMEOUT)
{
endGameModeAbandoned =true;
clearEndGameChunks();
if (Logger.isEnabled())
Logger.log(new LogEvent(diskManager.getTorrent(), LOGID, "Abandoning end-game mode: "
+peerControl.getDisplayName()));
}
}
return;
}
int active_pieces =0;
for (int i =0; i <nbPieces; i++)
{
final DiskManagerPiece dmPiece =dmPieces[i];
// If the piece isn't even Needed, or doesn't need more downloading, simply continue
if (!dmPiece.isDownloadable())
continue;
final PEPiece pePiece = pePieces[i];
if ( pePiece != null && pePiece.isDownloaded()){
continue;
}
// If the piece is being downloaded (fully requested), count it and continue
if ( pePiece != null && pePiece.isRequested() && dmPiece.isNeeded())
{
active_pieces++;
continue;
}
// Else, some piece is Needed, not downloaded/fully requested; this isn't end game mode
return;
}
// only flick into end-game mode if < trigger size left
if (active_pieces *diskManager.getPieceLength() <=END_GAME_MODE_SIZE_TRIGGER)
{
endGameModeChunks =new ArrayList();
timeEndGameModeEntered =now;
endGameMode =true;
computeEndGameModeChunks();
if (Logger.isEnabled())
Logger.log(new LogEvent(diskManage
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -