📄 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.control.PeerControlScheduler;
import com.aelitis.azureus.core.peermanager.piecepicker.*;
import com.aelitis.azureus.core.peermanager.piecepicker.util.BitFlags;
import com.aelitis.azureus.core.peermanager.unchoker.UnchokerUtil;
import com.aelitis.azureus.core.util.CopyOnWriteList;
/**
* @author MjrTom
*
*/
public class PiecePickerImpl
implements PiecePicker
{
private static final boolean LOG_RTA = false;
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 forced availability rebuild */
private static final long TIME_AVAIL_REBUILD =5*60*1000 -24;
// The following are added to the base User setting based priorities (for all inspected pieces)
/** user select prioritize first/last */
private static final int PRIORITY_W_FIRSTLAST =1300;
/** min # pieces in file for first/last prioritization */
private static final long FIRST_PIECE_MIN_NB =4;
/** number of pieces for first pieces prioritization */
// private static final int FIRST_PIECE_RANGE_PERCENT= 10;
/** user sets file as "High" */
private static final int PRIORITY_W_FILE =1000;
/** Additional boost for more completed High priority */
private static final int PRIORITY_W_COMPLETION =2000;
// The following are only used when resuming already running pieces
/** priority boost due to being too old */
private static final int PRIORITY_W_AGE =900;
/** ms a block is expected to complete in */
private static final int PRIORITY_DW_AGE =60 *1000;
/** ms since last write */
private static final int PRIORITY_DW_STALE =120 *1000;
/** finish pieces already almost done */
private static final int PRIORITY_W_PIECE_DONE =900;
/** keep working on same piece */
private static final int PRIORITY_W_SAME_PIECE =700;
/** currently webseeds + other explicit priorities are around 10000 or more - at this point we ignore rarity */
private static final int PRIORITY_OVERRIDES_RAREST = 9000;
/** priority at and above which pieces require real-time scheduling */
private static final int PRIORITY_REALTIME = 9999999;
/** 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" );
protected static volatile boolean completionPriority =COConfigurationManager.getBooleanParameter("Prioritize Most Completed Files");
/** event # of user settings controlling priority changes */
protected static volatile long paramPriorityChange =Long.MIN_VALUE;
private static final int NO_REQUEST_BACKOFF_MAX_MILLIS = 5*1000;
private static final int NO_REQUEST_BACKOFF_MAX_LOOPS = NO_REQUEST_BACKOFF_MAX_MILLIS / PeerControlScheduler.SCHEDULE_PERIOD_MILLIS;
private final DiskManager diskManager;
private final PEPeerControl peerControl;
private final DiskManagerListenerImpl diskManagerListener;
protected final Map peerListeners;
private final PEPeerManagerListener peerManagerListener;
protected final int nbPieces;
protected final DiskManagerPiece[] dmPieces;
protected final PEPiece[] pePieces;
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;
private long timeAvailRebuild =TIME_AVAIL_REBUILD;
/** 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;
private boolean priorityRTAexists;
/** time that base priorities were last computed */
private long timeLastPriorities;
/** the priority for starting each piece/base priority for resuming */
private int[] 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;
private long lastProviderRecalcTime;
private CopyOnWriteList rta_providers = new CopyOnWriteList();
private long[] provider_piece_rtas;
private CopyOnWriteList priority_providers = new CopyOnWriteList();
private long[] provider_piece_priorities;
private int allocate_request_loop_count;
private CopyOnWriteList listeners = new CopyOnWriteList();
static
{
class ParameterListenerImpl
implements ParameterListener
{
public final void parameterChanged(final String parameterName)
{
if (parameterName.equals("Prioritize Most Completed Files"))
{
completionPriority =COConfigurationManager.getBooleanParameter(parameterName);
paramPriorityChange++; // this is a user's priority change event
} else if (parameterName.equals("Prioritize First Piece"))
{
firstPiecePriority =COConfigurationManager.getBooleanParameter(parameterName);
paramPriorityChange++; // this is a user's priority change event
}
}
}
final 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
peerControl = pc;
diskManager = peerControl.getDiskManager();
dmPieces =diskManager.getPieces();
nbPieces =diskManager.getNbPieces();
nbPiecesDone =0;
pePieces = pc.getPieces();
// 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 final void addHavePiece(final PEPeer peer, final int pieceNumber)
{
// peer is null if called from disk-manager callback
try
{ availabilityMon.enter();
if ( availabilityAsynch == null ){
availabilityAsynch = (int[])availability.clone();
}
++availabilityAsynch[pieceNumber];
availabilityChange++;
} finally {availabilityMon.exit();}
// if this is an interesting piece then clear any record of "no requests" so the peer gets
// scheduled next loop
if ( peer != null && dmPieces[pieceNumber].isDownloadable()){
peer.setConsecutiveNoRequestCount(0);
}
}
/**
* This methd will compute the pieces' overall availability (including ourself)
* and the _globalMinOthers & _globalAvail
*/
public final 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) > timeAvailRebuild){
try
{ availabilityMon.enter();
time_last_rebuild = now;
final int[] new_availability = recomputeAvailability();
if (Constants.isCVSVersion())
{
final 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++;
}
}
if (errors >0 &&errors !=nbPieces)
{
if (Logger.isEnabled())
Logger.log(new LogEvent(peerControl, LOGID, LogEvent.LT_ERROR,
"updateAvailability(): availability rebuild errors =" +errors
+" timeAvailRebuild =" +timeAvailRebuild
));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -