📄 piecepickerimpl.java
字号:
}
// copy updated local variables into globals
globalAvail =(total /(float) nbPieces) +allMin;
nbRarestActive =rarestActive;
globalAvgAvail =totalAvail /(float)(nbPieces)
/(1 +peerControl.getNbSeeds() +peerControl.getNbPeers());
}
private int[] recomputeAvailability()
{
if (availabilityDrift >0 &&availabilityDrift !=nbPieces &&Logger.isEnabled())
Logger.log(new LogEvent(diskManager.getTorrent(), LOGID, LogEvent.LT_INFORMATION,
"Recomputing availabiliy. Drift=" +availabilityDrift +":" +peerControl.getDisplayName()));
final List peerTransports =peerControl.getPeers();
int[] newAvailability = new int[nbPieces];
int j;
int i;
// first our pieces
for (j =0; j <nbPieces; j++)
newAvailability[j] =dmPieces[j].isDone() ?1 :0;
//for all peers
for (i =0; i <peerTransports.size(); i++)
{ //get the peer connection
final PEPeerTransport pt =(PEPeerTransport)peerTransports.get(i);
if (pt !=null &&pt.getPeerState() ==PEPeer.TRANSFERING)
{
//cycle trhough the pieces they actually have
final BitFlags peerHavePieces =pt.getAvailable();
if (peerHavePieces !=null &&peerHavePieces.nbSet >0)
{
for (j =peerHavePieces.start; j <=peerHavePieces.end; j++)
{
if (peerHavePieces.flags[j])
++newAvailability[j];
}
}
}
}
return newAvailability;
}
public int[] getAvailability()
{
return availability;
}
public int getAvailability(final int pieceNumber)
{
return availability[pieceNumber];
}
//this only gets called when the My Torrents view is displayed
public float getMinAvailability()
{
return globalAvail;
}
public float getAvgAvail()
{
return globalAvgAvail;
}
/**
* Early-outs when finds a downloadable piece
* Either way sets hasNeededUndonePiece and neededUndonePieceChange if necessary
*/
protected void checkDownloadablePiece()
{
for (int i =0; i <nbPieces; i++)
{
if (dmPieces[i].isInteresting())
{
if (!hasNeededUndonePiece)
{
hasNeededUndonePiece =true;
neededUndonePieceChange++;
}
return;
}
}
if (hasNeededUndonePiece)
{
hasNeededUndonePiece =false;
neededUndonePieceChange++;
}
}
/**
* one reason requests don't stem from the individual peers is so the connections can be
* sorted by best uploaders, providing some ooprtunity to download the most important
* (ie; rarest and/or highest priority) pieces faster and more reliably
*/
public boolean checkDownloadPossible()
{
if (!hasNeededUndonePiece)
return false;
final List bestUploaders =new ArrayList();
final List peer_transports =peerControl.getPeers();
final long[] upRates =new long[peer_transports.size()];
Arrays.fill(upRates, -1);
for (int i =0; i <peer_transports.size(); i++)
{
final PEPeerTransport pt =(PEPeerTransport) peer_transports.get(i);
if (pt.getPeerState() <PEPeer.CLOSING)
{
final long upRate =pt.getStats().getSmoothDataReceiveRate();
UnchokerUtil.updateLargestValueFirstSort(upRate, upRates, pt, bestUploaders, 0);
}
}
checkEndGameMode();
computeBasePriorities();
for (int i =0; i <bestUploaders.size(); i++)
{
// get a connection
final PEPeerTransport pt =(PEPeerTransport) bestUploaders.get(i);
// can we transfer something?
if (pt.isDownloadPossible())
{
// If queue is too low, we will enqueue another request
int found =0;
int maxRequests =REQUESTS_MIN +(int) (pt.getStats().getDataReceiveRate() /SLOPE_REQUESTS);
if (maxRequests >REQUESTS_MAX ||maxRequests <0)
maxRequests =REQUESTS_MAX;
if (endGameMode)
maxRequests =2;
if (pt.isSnubbed())
maxRequests =1;
// Only loop when 3/5 of the queue is empty, in order to make more consecutive requests,
// and improve cache efficiency
if (pt.getNbRequests() <=(maxRequests *3) /5)
{
while (pt.isDownloadPossible() &&pt.getNbRequests() <maxRequests)
{
// is there anything else to download?
if (!endGameMode)
found =findPieceToDownload(pt, maxRequests);
else
found =findPieceInEndGameMode(pt, maxRequests);
if (found <=0)
break;
}
}
}
}
return true;
}
/** This computes the base priority for all pieces that need requesting if there's
* been any availability change or user priority setting changes since the last
* call, which will be most of the time since availability changes so dynamicaly
* It will change startPriorities[] (unless there was nothing to do)
*/
private void computeBasePriorities()
{
final long now =SystemTime.getCurrentTime();
if (startPriorities !=null &&((now >timeLastPriorities &&now <time_last_avail +TIME_MIN_PRIORITIES)
||(priorityParamChange >=paramPriorityChange &&priorityFileChange >=filePriorityChange
&&priorityAvailChange >=availabilityChange)))
return; // *somehow* nothing changed, so nothing to do
// store the latest change indicators before we start making dependent calculations so that a
// further change while computing stuff doesn't get lost
priorityParamChange =paramPriorityChange;
priorityFileChange =filePriorityChange;
priorityAvailChange =availabilityChange;
timeLastPriorities =now;
boolean changedPriority =false;
boolean foundPieceToDownload =false;
long[] newPriorities =new long[nbPieces];
try
{
final boolean rarestOverride =getRarestOverride();
// calculate all base (starting) priorities for all pieces needing requesting
for (int i =0; i <nbPieces; i++)
{
final int avail =availability[i];
DiskManagerPiece dmPiece =dmPieces[i];
if (dmPiece.isDone())
continue; // nothing to do for pieces not needing requesting
long startPriority =Long.MIN_VALUE;
long priority =Long.MIN_VALUE;
final DMPieceList pieceList =diskManager.getPieceList(dmPiece.getPieceNumber());
for (int j =0; j <pieceList.size(); j++)
{
final DiskManagerFileInfoImpl fileInfo =pieceList.get(j).getFile();
final long length =fileInfo.getLength();
final long downloaded =fileInfo.getDownloaded();
if (length >0 &&downloaded <length &&!fileInfo.isSkipped())
{
priority =0;
// user option "prioritize first and last piece"
// TODO: should prioritize ~10% to ~%25 from edges of file
if (firstPiecePriority &&fileInfo.getNbPieces() >FIRST_PIECE_MIN_NB)
{
if (i ==fileInfo.getFirstPieceNumber() ||i ==fileInfo.getLastPieceNumber())
priority +=PRIORITY_W_FIRSTLAST;
}
// if the file is high-priority
// startPriority +=(1000 *fileInfo.getPriority()) /255;
if (fileInfo.isPriority())
{
priority +=PRIORITY_W_FILE;
if (completionPriority)
{
final long percent =(1000 *downloaded) /length;
if (percent >=900)
priority +=(PRIORITY_W_COMPLETION *downloaded) /diskManager.getTotalLength();
}
}
if (priority >startPriority)
startPriority =priority;
}
}
if (startPriority >=0)
{
dmPiece.setNeeded();
foundPieceToDownload =true;
// if (avail >0)
// {
// // boost priority for rarity
// startPriority +=(PRIORITY_W_RARE +peerControl.getNbPeers()) /avail;
// // Boost priority even a little more if it's a globally rarest piece
// if (!rarestOverride &&avail <=globalMinOthers)
// startPriority +=PRIORITY_W_RAREST /avail;
// }
} else
{
dmPiece.clearNeeded();
}
newPriorities[i] =startPriority;
changedPriority =true;
}
} catch (Throwable e)
{
Debug.printStackTrace(e);
}
if (foundPieceToDownload)
{
if (!hasNeededUndonePiece)
{
hasNeededUndonePiece =true;
neededUndonePieceChange++;
}
} else if (hasNeededUndonePiece)
{
hasNeededUndonePiece =false;
neededUndonePieceChange++;
}
if (changedPriority)
startPriorities =newPriorities;
}
private boolean getRarestOverride()
{
final int nbSeeds =peerControl.getNbSeeds();
final int nbPeers =peerControl.getNbPeers();
// Dont seek rarest this time around under a few circumstances, so that other factors work better
// never seek rarest when bootstrapping torrent
boolean rarestOverride =nbPiecesDone <4 ||endGameMode ||nbRarestActive >=(nbSeeds +nbPeers);
if (!rarestOverride &&nbRarestActive >1 &&globalMinOthers >1)
{
// if already getting some rarest, dont get more if swarm is healthy or too many pieces running
rarestOverride =globalMinOthers >globalMin
||(globalMinOthers >=(2 *nbSeeds) &&(2 *globalMinOthers) >=nbPeers);
// Interest in Rarest pieces (compared to user priority settings) could be influenced by several factors;
// less demand closer to 0% and 100% of the torrent/farther from 50% of the torrent
// less demand closer to 0% and 100% of peers interestd in us/farther from 50% of peers interested in us
// less demand the more pieces are in progress (compared to swarm size)
// less demand the farther ahead from absolute global minimum we're at already
// less demand the healthier a swarm is (rarity compared to # seeds and # peers)
}
return rarestOverride;
}
/**
* @param pc
* the PeerConnection we're working on
* @return true if a request was assigned, false otherwise
*/
protected int findPieceToDownload(final PEPeerTransport pt, final int nbWanted)
{
final int pieceNumber =getRequestCandidate(pt);
if (pieceNumber <0)
return 0;
int peerSpeed =(int) pt.getStats().getDataReceiveRate() /1000;
PEPeerControl pc =pt.getControl();
PEPiece pePiece =pc.getPiece(pieceNumber);
if (pePiece ==null)
{ //create piece manually
pePiece =new PEPieceImpl(pt.getManager(), dmPieces[pieceNumber], peerSpeed >>1);
// Assign the created piece to the pieces array.
pc.addPiece(pePiece, pieceNumber);
if (startPriorities !=null)
pePiece.setResumePriority(startPriorities[pieceNumber]);
if (availability[pieceNumber] <=globalMinOthers)
nbRarestActive++;
}
final int[] blocksFound =pePiece.getAndMarkBlocks(pt, nbWanted);
final int blockNumber =blocksFound[0];
final int nbBlocks =blocksFound[1];
if (nbBlocks <=0)
return 0;
int requested =0;
// really try to send the request to the peer
for (int i =0; i <nbBlocks; i++)
{
final int thisBlock =blockNumber +i;
if (pt.request(pieceNumber, thisBlock *DiskManager.BLOCK_SIZE, pePiece.getBlockSize(thisBlock)))
{
requested++;
pt.setLastPiece(pieceNumber);
// Up the speed on this piece?
if (peerSpeed >pePiece.getSpeed())
pePiece.incSpeed();
// have requested a block
}
}
return requested;
}
// set FORCE_PIECE if trying to diagnose piece problems and only want to d/l a specific piece from a torrent
private static final int FORCE_PIECE =-1;
/**
* This method is the downloading core. It decides, for a given peer,
* which block should be requested. Here is the overall algorithm :
* 0. If there a FORCED_PIECE or reserved piece, that will be started/resumed if possible
* 1. Scan all the active pieces and find the rarest piece (and highest priority among equally rarest)
* that can possibly be continued by this peer, if any
* 2. While scanning the active pieces, develop a list of equally highest priority pieces
* (and equally rarest among those) as candidates for starting a new piece
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -