📄 piecepickerimpl.java
字号:
/*
* Created by Joseph Bridgewater
* Created on Jan 2, 2006
* Copyright (C) 2005, 2006 Aelitis, All Rights Reserved.
*
* 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, or (at your option) any later version.
* 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.
* 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.
*
* AELITIS, SAS au capital de 46,603.30 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*
*/
package com.aelitis.azureus.core.peermanager.piecepicker.impl;
import java.util.*;
import org.gudy.azureus2.core3.config.*;
import org.gudy.azureus2.core3.disk.*;
import org.gudy.azureus2.core3.disk.impl.DiskManagerFileInfoImpl;
import org.gudy.azureus2.core3.disk.impl.piecemapper.DMPieceList;
import org.gudy.azureus2.core3.logging.*;
import org.gudy.azureus2.core3.peer.*;
import org.gudy.azureus2.core3.peer.impl.*;
import org.gudy.azureus2.core3.util.*;
import com.aelitis.azureus.core.peermanager.piecepicker.*;
import com.aelitis.azureus.core.peermanager.piecepicker.priority.PiecePriorityShaper;
import com.aelitis.azureus.core.peermanager.piecepicker.util.BitFlags;
import com.aelitis.azureus.core.peermanager.unchoker.UnchokerUtil;
/**
* @author MjrTom
*
*/
public class PiecePickerImpl
implements PiecePicker
{
private static final LogIDs LOGID = LogIDs.PIECES;
/** min ms for recalculating availability - reducing this has serious ramifications */
private static final long TIME_MIN_AVAILABILITY =974;
/** min ms for recalculating base priorities */
private static final long TIME_MIN_PRIORITIES =999;
/** min ms for total availability rebuild */
private static final long TIME_AVAIL_REBUILD =2*60*1000;
// The following are added to the base User setting based priorities (for all inspected pieces)
/** user select prioritize first/last */
private static final long PRIORITY_W_FIRSTLAST =1200;
/** min # pieces in file for first/last prioritization */
private static final long FIRST_PIECE_MIN_NB =4;
/** user sets file as "High" */
private static final long PRIORITY_W_FILE =1100;
/** Additional boost for more completed High priority */
private static final long PRIORITY_W_COMPLETION =1000;
/** Additional boost for globally rarest piece */
private static final long PRIORITY_W_RAREST =1300;
/** boost for rarity */
private static final long PRIORITY_W_RARE =2300;
// The following are only used when resuming already running pieces
/** priority boost due to being too old */
private static final long PRIORITY_W_AGE =1000;
/** ms a block is expected to complete in, with leeway factor */
private static final long PRIORITY_DW_AGE =60 *1000;
/** ms since last write */
private static final long PRIORITY_DW_STALE =120 *1000;
/** finish pieces already almost done */
private static final long PRIORITY_W_PIECE_DONE =900;
/** keep working on same piece */
private static final long PRIORITY_W_SAME_PIECE =500;
/** Min number of requests sent to a peer */
private static final int REQUESTS_MIN =2;
/** Max number of request sent to a peer */
private static final int REQUESTS_MAX =256;
/** Default number of requests sent to a peer, (for each X B/s another request will be used) */
private static final int SLOPE_REQUESTS =4 *1024;
private static final long END_GAME_MODE_SIZE_TRIGGER =20 *1024 *1024;
private static final long END_GAME_MODE_TIMEOUT =60 *END_GAME_MODE_SIZE_TRIGGER /16384;
protected static volatile boolean firstPiecePriority =COConfigurationManager.getBooleanParameter("Prioritize First Piece", false);
protected static volatile boolean completionPriority =COConfigurationManager.getBooleanParameter("Prioritize Most Completed Files", false);
/** event # of user settings controlling priority changes */
protected static volatile long paramPriorityChange =Long.MIN_VALUE;
private final DiskManager diskManager;
private final PEPeerControl peerControl;
private final PiecePriorityShaper priorityShaper;
private final DiskManagerListenerImpl diskManagerListener;
protected final Map peerListeners;
private final PEPeerManagerListener peerManagerListener;
protected final int nbPieces;
protected final DiskManagerPiece[] dmPieces;
protected final AEMonitor availabilityMon = new AEMonitor("PiecePicker:avail");
private final AEMonitor endGameModeChunks_mon =new AEMonitor("PiecePicker:EGM");
protected volatile int nbPiecesDone;
/** asyncronously updated availability */
protected volatile int[] availabilityAsynch;
/** indicates availability needs to be recomputed due to detected drift */
protected volatile long availabilityDrift;
/** periodically updated consistent view of availability for calculating */
protected volatile int[] availability;
private long time_last_avail;
protected volatile long availabilityChange;
private volatile long availabilityComputeChange;
private long time_last_rebuild;
private float globalAvail;
private float globalAvgAvail;
private int nbRarestActive;
private int globalMin;
/**
* The rarest availability level of pieces that we affirmatively want to try to request from others soonest
* ie; our prime targets for requesting rarest pieces
*/
private volatile int globalMinOthers;
/** event # of user file priority settings changes */
protected volatile long filePriorityChange;
/** last user parameter settings event # when priority bases were calculated */
private volatile long priorityParamChange;
/** last user priority event # when priority bases were calculated */
private volatile long priorityFileChange;
/** last availability event # when priority bases were calculated */
private volatile long priorityAvailChange;
/** time that base priorities were last computed */
private long timeLastPriorities;
/** the priority for starting each piece/base priority for resuming */
private long[] startPriorities;
protected volatile boolean hasNeededUndonePiece;
protected volatile long neededUndonePieceChange;
/** A flag to indicate when we're in endgame mode */
private volatile boolean endGameMode;
private volatile boolean endGameModeAbandoned;
private volatile long timeEndGameModeEntered;
/** The list of chunks needing to be downloaded (the mechanism change when entering end-game mode) */
private List endGameModeChunks;
static
{
class ParameterListenerImpl
implements ParameterListener
{
public void parameterChanged(String parameterName)
{
if (parameterName.equals("Prioritize Most Completed Files"))
{
completionPriority =COConfigurationManager.getBooleanParameter(parameterName, false);
paramPriorityChange++; // this is a user's priority change event
} else if (parameterName.equals("Prioritize First Piece"))
{
firstPiecePriority =COConfigurationManager.getBooleanParameter(parameterName, false);
paramPriorityChange++; // this is a user's priority change event
}
}
}
ParameterListenerImpl parameterListener =new ParameterListenerImpl();;
COConfigurationManager.addParameterListener("Prioritize Most Completed Files", parameterListener);
COConfigurationManager.addAndFireParameterListener("Prioritize First Piece", parameterListener);
}
public PiecePickerImpl(final PEPeerControl pc)
{
// class administration first
priorityShaper =null; //PiecePriorityShaperFactory.create(this);
peerControl = pc;
diskManager = peerControl.getDiskManager();
dmPieces =diskManager.getPieces();
nbPieces =diskManager.getNbPieces();
nbPiecesDone =0;
// now do stuff related to availability
availability =new int[nbPieces]; //always needed
hasNeededUndonePiece =false;
neededUndonePieceChange =Long.MIN_VALUE;
// ensure all periodic calculaters perform operations at least once
time_last_avail =Long.MIN_VALUE;
availabilityChange =Long.MIN_VALUE +1;
availabilityComputeChange =Long.MIN_VALUE;
availabilityDrift =nbPieces;
// initialize each piece; on going changes will use event driven tracking
for (int i =0; i <nbPieces; i++)
{
if (dmPieces[i].isDone()){
availability[i]++;
nbPiecesDone++;
}else{
hasNeededUndonePiece |=dmPieces[i].calcNeeded();
}
}
if (hasNeededUndonePiece)
neededUndonePieceChange++;
updateAvailability();
// with availability charged and primed, ready for peer messages
peerListeners =new HashMap();
peerManagerListener =new PEPeerManagerListenerImpl();
peerControl.addListener(peerManagerListener);
// now do stuff related to starting/continuing pieces
// startPriorities =new long[nbPieces]; //allocate on demand
filePriorityChange =Long.MIN_VALUE;
priorityParamChange =Long.MIN_VALUE;
priorityFileChange =Long.MIN_VALUE;
priorityAvailChange =Long.MIN_VALUE;
timeLastPriorities =Long.MIN_VALUE;
endGameMode =false;
endGameModeAbandoned =false;
timeEndGameModeEntered =0;
// computeBasePriorities();
// with priorities charged and primed, ready for dm messages
diskManagerListener =new DiskManagerListenerImpl();
diskManager.addListener(diskManagerListener);
}
public void addHavePiece(final int pieceNumber)
{
try
{ availabilityMon.enter();
if ( availabilityAsynch == null ){
availabilityAsynch = (int[])availability.clone();
}
++availabilityAsynch[pieceNumber];
availabilityChange++;
} finally {availabilityMon.exit();}
}
/**
* This methd will compute the pieces' overall availability (including ourself)
* and the _globalMinOthers & _globalAvail
*/
public void updateAvailability()
{
final long now =SystemTime.getCurrentTime();
if (now >=time_last_avail &&now <time_last_avail +TIME_MIN_AVAILABILITY)
return;
if (availabilityDrift >0 || now < time_last_rebuild || now - time_last_rebuild > TIME_AVAIL_REBUILD ){
try
{ availabilityMon.enter();
time_last_rebuild = now;
int[] new_availability = recomputeAvailability();
/*
int[] old_availability = availabilityAsynch==null?availability:availabilityAsynch;
int errors = 0;
for (int i=0;i<new_availability.length;i++){
if ( new_availability[i] != old_availability[i]){
errors++;
}
}
System.out.println( "avail rebuild: errors = " + errors );
*/
availabilityAsynch = new_availability;
availabilityDrift =0;
availabilityChange++;
} finally {availabilityMon.exit();}
}else if (availabilityComputeChange >=availabilityChange){
return;
}
try
{ availabilityMon.enter();
time_last_avail =now;
availabilityComputeChange =availabilityChange;
// take a snapshot of availabilityAsynch
if ( availabilityAsynch != null ){
availability = availabilityAsynch;
availabilityAsynch = null;
}
} finally {availabilityMon.exit();}
int i;
int allMin =Integer.MAX_VALUE;
int rarestMin =Integer.MAX_VALUE;
for (i =0; i <nbPieces; i++)
{
final int avail =availability[i];
final DiskManagerPiece dmPiece =dmPieces[i];
if (avail >0 &&avail <rarestMin &&dmPiece.isRequestable())
rarestMin =avail; // most important targets for near future requests from others
if (avail <allMin)
allMin =avail;
}
// copy updated local variables into globals
globalMin =allMin;
globalMinOthers =rarestMin;
int total =0;
int rarestActive =0;
long totalAvail =0;
for (i =0; i <nbPieces; i++ )
{
final int avail =availability[i];
final DiskManagerPiece dmPiece =dmPieces[i];
if (avail >0)
{
if (avail >allMin)
total++;
if (avail <=rarestMin &&dmPiece.isRequestable() &&peerControl.getPiece(i) !=null)
rarestActive++;
totalAvail +=avail;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -