📄 piecepickerimpl.java
字号:
* 3. If it can't find any piece, this means all pieces are
* already downloaded/full requested
* 4. Returns int[] pieceNumber, blockNumber if a request to be made is found,
* or null if none could be found
* @param pc PEPeerTransport to work with
*
* @return int with pieceNumberto be requested or -1 if no request could be found
*/
private int getRequestCandidate(final PEPeerTransport pt)
{
if (pt ==null ||pt.getPeerState() !=PEPeer.TRANSFERING)
return -1;
final BitFlags peerHavePieces =pt.getAvailable();
if (peerHavePieces ==null ||peerHavePieces.nbSet <=0)
return -1;
// piece number and its block number that we'll try to DL
int pieceNumber; // will be set to the piece # we want to resume
DiskManagerPiece dmPiece; // the DiskManagerPiece backing the PEPiece under inspection
if (FORCE_PIECE >=0 &&FORCE_PIECE <nbPieces)
pieceNumber =FORCE_PIECE;
else
pieceNumber =pt.getReservedPieceNumber();
// If there's a piece Reserved to this peer or a FORCE_PIECE, start/resume it and only it (if possible)
if (pieceNumber >=0)
{
dmPiece =dmPieces[pieceNumber];
if (peerHavePieces.flags[pieceNumber] &&dmPiece.isRequestable())
return pieceNumber;
return -1; // this is an odd case that maybe should be handled better, but checkers might fully handle it
}
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 rarestOverride =getRarestOverride();
long resumeMinAvail =Long.MAX_VALUE;
long resumeMaxPriority =Long.MIN_VALUE;
boolean resumeIsRarest =false; // can the peer continuea piece with lowest avail of all pieces we want
BitFlags startCandidates =null;
long startMaxPriority =Long.MIN_VALUE;
int startMinAvail =Integer.MAX_VALUE;
boolean startIsRarest =false;
PEPiece pePiece; // the PEPiece under inspection
long 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
int freeReqs; // the number of unrequested (free) blocks in the piece under inspection
int pieceSpeed; // the current speed rating of the PEPiece under inspection
long staleness; // how long since there's been a write to the resume 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 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])
{
dmPiece =dmPieces[i];
// is the piece: Needed, not fully: Requested, Downloaded, Written, hash-Checking or Done?
if (dmPiece.isRequestable())
{
priority =startPriorities[i];
if (priority >=0)
{
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
pePiece =peerControl.getPiece(i);
if (pePiece !=null)
{
// How many requests can still be made on this piece?
freeReqs =pePiece.getNbUnrequested();
if (freeReqs <=0)
{
dmPiece.setRequested();
continue;
}
// Don't touch pieces reserved for others
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, but we located it
pt.setReservedPieceNumber(i);
return i;
}
pieceSpeed =pePiece.getSpeed();
// peers allowed to continue same piece as last requested from them
// or pieces only they have
// or pieces with 0 speed
if (pieceSpeed >0 &&i !=lastPiece)
{
// if the peer is snubbed, only request on slow pieces
if (peerSpeed <pieceSpeed ||pt.isSnubbed())
{
// peer allowed when free blocks is >= 3 and enough to not slow piece down too much
if (avail >1 &&(freeReqs <3 ||pieceSpeed -1 >=freeReqs *peerSpeed))
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 +=pePiece.getTimeSinceLastActivity() /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); // this is only for display
if (avail <resumeMinAvail &&(!rarestOverride ||priority >=resumeMaxPriority)
||(priority >resumeMaxPriority &&(!resumeIsRarest ||rarestOverride)))
{ // 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
pieceNumber =i;
resumeMinAvail =avail;
resumeMaxPriority =priority;
resumeIsRarest =avail <=globalMinOthers; // only going to try to resume one
}
}
}
} else if (avail <=globalMinOthers &&!rarestOverride)
{ // 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 ||rarestOverride)
{ // 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);
}
}
}
}
}
}
}
// Didnt find anything to do
if (pieceNumber <0 &&(startCandidates ==null ||startCandidates.nbSet <1))
return -1;
// See if have found a valid (piece;block) to request from a piece in progress
boolean resumeIsBetter =false;
if (pieceNumber >=0)
{
resumeIsBetter =startCandidates ==null ||startCandidates.nbSet <1
||resumeIsRarest ||!startIsRarest ||rarestOverride
||(resumeMaxPriority /resumeMinAvail) >(startMaxPriority /globalMinOthers);
if (resumeIsBetter)
return pieceNumber;
}
if (Logger.isEnabled())
Logger.log(new LogEvent(pt, LOGID, "Starting Piece. "
+"resume piece #= " +pieceNumber +" globalMinOthers=" +globalMinOthers
+" startMaxPriority=" +startMaxPriority +" startMinAvail=" +startMinAvail +" startIsRarest=" +startIsRarest
+(pieceNumber >0
?" resumeMaxPriority=" +resumeMaxPriority +" resumeMinAvail=" +resumeMinAvail +" resumeIsRarest=" +resumeIsRarest
:"")
+" " +peerControl.getDisplayName()));
// Gets here when no resume piece choice was made
return getPieceToStart(pt, startCandidates); // pick piece from candidates bitfield
}
/** @return int the piece number that should be started, according to selection criteria
*
* @param pt PEPeer the piece would be started for
* @param startCandidates BitFlags of potential candidates to choose from
* @return int the piece number that was chosen to be started
*/
protected int getPieceToStart(final PEPeerTransport pt, final BitFlags startCandidates)
{
if (startCandidates ==null ||startCandidates.nbSet <=0)
{ // cant do anything if no pieces to startup
return -1;
}
int startI;
int direction;
if (startCandidates.nbSet ==1)
{
startI =startCandidates.start;
direction =1;
} else
{
// Mix it up!
startI =RandomUtils.generateRandomIntBetween(startCandidates.start,
startCandidates.end);
direction =RandomUtils.generateRandomPlusMinus1();
}
final PEPiece[] pePieces =pt.getControl().getPieces();
// For every Priority piece
for (int i =startI; i >=startCandidates.start &&i <=startCandidates.end; i +=direction)
{
// is piece flagged and confirmed not in progress
if (pePieces[i] ==null &&startCandidates.flags[i])
{
// This should be a piece we want to start
return i;
}
}
return -1;
}
public boolean hasDownloadablePiece()
{
return hasNeededUndonePiece;
}
public long getNeededUndonePieceChange()
{
return neededUndonePieceChange;
}
private 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.isEGMIgnored())
continue;
// If the piece is being downloaded (fully requested), count it and continue
if (dmPiece.isEGMActive())
{
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)
{
timeEndGameModeEntered =now;
endGameMode =true;
computeEndGameModeChunks();
if (Logger.isEnabled())
Logger.log(new LogEvent(diskManager.getTorrent(), LOGID, "Entering end-game mode: "
+peerControl.getDisplayName()));
// System.out.println("End-Game Mode activated");
}
}
private void computeEndGameModeChunks()
{
PEPiece[] _pieces =peerControl.getPieces();
if (_pieces ==null)
return;
endGameModeChunks =new ArrayList();
try
{
endGameModeChunks_mon.enter();
for (int i =0; i <nbPieces; i++ )
{
DiskManagerPiece dmPiece =dmPieces[i];
// Pieces not Needed or not needing more downloading are of no interest
if (!dmPiece.isInteresting())
continue;
PEPiece pePiece =_pieces[i];
if (pePiece ==null)
continue;
boolean written[] =dmPiece.getWritten();
if (written ==null)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -