package com.aelitis.azureus.core.speedmanager.impl.v2;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.util.SystemTime;
import org.gudy.azureus2.core3.util.RealTimeInfo;
import com.aelitis.azureus.core.speedmanager.SpeedManagerLimitEstimate;
import com.aelitis.azureus.core.speedmanager.SpeedManagerPingMapper;
import com.aelitis.azureus.core.speedmanager.SpeedManager;
import com.aelitis.azureus.core.speedmanager.impl.SpeedManagerAlgorithmProviderAdapter;
import com.aelitis.azureus.core.AzureusCoreFactory;
/**
* Created on May 23, 2007
* Created by Alan Snyder
* Copyright (C) 2007 Aelitis, All Rights Reserved.
* <p/>
* 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.
* <p/>
* AELITIS, SAS au capital de 63.529,40 euros
* 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*/
/**
* This class is responsible for re-adjusting the limits used by AutoSpeedV2.
*
* This class will keep track of the "status" (i.e. seeding, downloading)of the
* application. It will then re-adjust the MAX limits when it thinks limits
* are being reached.
*
* Here are the rules it will use.
*
* #1) When seeding. If the upload is AT_LIMIT for a period of time it will allow
* that to adjust upward.
* #2) When downloading. If the download is AT_LIMIT for a period of time it will
* allow that to adjust upward.
*
* #3) When downloading, if a down-tick is detected and the upload is near a limit,
* it will drop the upload limit to 80% of MAX_UPLOAD.
*
* #4) Once that limit is reached it will drop both the upload and download limits together.
*
* #5) Seeding mode is triggered when - download bandwidth at LOW - compared to CAPACITY for 5 minutes continously.
*
* #6) Download mode is triggered when - download bandwidth reaches MEDIUM - compared to CURRENT_LIMIT for the first time.
*
* Rules #5 and #6 favor downloading over seeding.
*
*/
public class SpeedLimitMonitor implements PSMonitorListener
{
//use for home network.
private int uploadLimitMax = SMConst.START_UPLOAD_RATE_MAX;
private int uploadLimitMin = SMConst.calculateMinUpload( uploadLimitMax );
private int downloadLimitMax = SMConst.START_DOWNLOAD_RATE_MAX;
private int downloadLimitMin = SMConst.calculateMinDownload( downloadLimitMax );
private TransferMode transferMode = new TransferMode();
//Upload and Download bandwidth usage modes. Compare usage to current limit.
private SaturatedMode uploadBandwidthStatus =SaturatedMode.NONE;
private SaturatedMode downloadBandwidthStatus =SaturatedMode.NONE;
//Compare current limit to max limit.
private SaturatedMode uploadLimitSettingStatus=SaturatedMode.AT_LIMIT;
private SaturatedMode downloadLimitSettingStatus=SaturatedMode.AT_LIMIT;
//How much confidence to we have in the current limits?
private SpeedLimitConfidence uploadLimitConf = SpeedLimitConfidence.NONE;
private SpeedLimitConfidence downloadLimitConf = SpeedLimitConfidence.NONE;
private long clLastIncreaseTime =-1;
private long clFirstBadPingTime=-1;
private boolean currTestDone;
private boolean beginLimitTest;
private int highestUploadRate=0;
private int highestDownloadRate=0;
private int preTestUploadCapacity=5042;
private int preTestUploadLimit=5142;
private int preTestDownloadCapacity=5042;
private int preTestDownloadLimit=5142;
public static final String UPLOAD_CONF_LIMIT_SETTING="SpeedLimitMonitor.setting.upload.limit.conf";
public static final String DOWNLOAD_CONF_LIMIT_SETTING="SpeedLimitMonitor.setting.download.limit.conf";
public static final String UPLOAD_CHOKE_PING_COUNT="SpeedLimitMonitor.setting.choke.ping.count";
private static final long CONF_LIMIT_TEST_LENGTH=1000*30;
//these methods are used to see how high limits can go.
private boolean isUploadMaxPinned=true;
private boolean isDownloadMaxPinned=true;
private long uploadAtLimitStartTime =SystemTime.getCurrentTime();
private long downloadAtLimitStartTime = SystemTime.getCurrentTime();
private int uploadChokePingCount = 1;
private int uploadPinCounter = 0;
private static final long TIME_AT_LIMIT_BEFORE_UNPINNING = 30 * 1000; //30 seconds.
//which percent of the measured upload capacity to use in download and seeding mode.
public static final String USED_UPLOAD_CAPACITY_DOWNLOAD_MODE = "SpeedLimitMonitor.setting.upload.used.download.mode";
public static final String USED_UPLOAD_CAPACITY_SEEDING_MODE = "SpeedLimitMonitor.setting.upload.used.seeding.mode";
private float percentUploadCapacityDownloadMode = 0.6f;
//PingSpaceMaps for the entire session.
PingSpaceMapper pingMapOfDownloadMode;
PingSpaceMapper pingMapOfSeedingMode;
boolean useVariancePingMap = false;
SpeedManagerPingMapper transientPingMap;
PingSpaceMon longTermMonitor = new PingSpaceMon();
LimitControl slider = new LimitControlDropUploadFirst();
SpeedLimitListener persistentMapListener;
public SpeedLimitMonitor(SpeedManager sm){
//
longTermMonitor.addListener( this );
persistentMapListener = new SpeedLimitListener( this );
sm.addListener( persistentMapListener );
}
/**
* Splitting the limits our from other setting for SpeedManagerAlgorithmTI.
*/
public void updateSettingsFromCOConfigManager(){
percentUploadCapacityDownloadMode = (float)
COConfigurationManager.getIntParameter(SpeedLimitMonitor.USED_UPLOAD_CAPACITY_DOWNLOAD_MODE, 60)/100.0f;
slider.updateSeedSettings(percentUploadCapacityDownloadMode);
}
public void updateFromCOConfigManager(){
uploadLimitMax = COConfigurationManager.getIntParameter(SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT);
uploadLimitMin = SMConst.calculateMinUpload( uploadLimitMax );
downloadLimitMax =COConfigurationManager.getIntParameter(SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT);
downloadLimitMin=SMConst.calculateMinDownload( downloadLimitMax );
uploadLimitConf = SpeedLimitConfidence.parseString(
COConfigurationManager.getStringParameter( SpeedLimitMonitor.UPLOAD_CONF_LIMIT_SETTING ));
downloadLimitConf = SpeedLimitConfidence.parseString(
COConfigurationManager.getStringParameter( SpeedLimitMonitor.DOWNLOAD_CONF_LIMIT_SETTING));
percentUploadCapacityDownloadMode = (float)
COConfigurationManager.getIntParameter(SpeedLimitMonitor.USED_UPLOAD_CAPACITY_DOWNLOAD_MODE, 60)/100.0f;
uploadChokePingCount = Math.min(
COConfigurationManager.getIntParameter(SpeedLimitMonitor.UPLOAD_CHOKE_PING_COUNT),
30 );
slider.updateLimits(uploadLimitMax,uploadLimitMin,downloadLimitMax,downloadLimitMin);
slider.updateSeedSettings(percentUploadCapacityDownloadMode);
if( isSettingDownloadUnlimited() ){
slider.setDownloadUnlimitedMode( true );
}
}//updateFromCOConfigManager
/**
* replaces - updateFromCOConfigManager()
*/
public void readFromPersistentMap(){
//get persistent mapper.
SpeedManager sm = AzureusCoreFactory.getSingleton().getSpeedManager();
//get upload estimate.
SpeedManagerLimitEstimate uEst = SMConst.filterEstimate(
sm.getEstimatedUploadCapacityBytesPerSec(),
SMConst.START_UPLOAD_RATE_MAX );
int upPingMapLimit = uEst.getBytesPerSec();
if(upPingMapLimit<SMConst.START_UPLOAD_RATE_MAX){
//will find upload limit via slow search.
uploadLimitMax = SMConst.START_UPLOAD_RATE_MAX;
}else{
uploadLimitMax = upPingMapLimit;
}
uploadLimitMin = SMConst.calculateMinUpload( uploadLimitMax );
//get download estimate.
SpeedManagerLimitEstimate dEst = SMConst.filterEstimate(
sm.getEstimatedDownloadCapacityBytesPerSec(),
SMConst.START_DOWNLOAD_RATE_MAX );
int downPingMapLimit = dEst.getBytesPerSec();
if( isSettingDownloadUnlimited() ){
slider.setDownloadUnlimitedMode(true);
}else{
slider.setDownloadUnlimitedMode(false);
}
if(downPingMapLimit<SMConst.START_DOWNLOAD_RATE_MAX){
downloadLimitMax = SMConst.START_DOWNLOAD_RATE_MAX;
}else{
downloadLimitMax = downPingMapLimit;
}
downloadLimitMin = SMConst.calculateMinDownload( downloadLimitMax );
uploadLimitConf = SpeedLimitConfidence.convertType( uEst.getEstimateType() );
downloadLimitConf = SpeedLimitConfidence.convertType( dEst.getEstimateType() );
percentUploadCapacityDownloadMode = (float)
COConfigurationManager.getIntParameter(SpeedLimitMonitor.USED_UPLOAD_CAPACITY_DOWNLOAD_MODE, 60)/100.0f;
saveToCOConfiguration();
}
public void saveToCOConfiguration(){
COConfigurationManager.setParameter(SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT,uploadLimitMax);
COConfigurationManager.setParameter(SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT,downloadLimitMax);
COConfigurationManager.setParameter(SpeedLimitMonitor.UPLOAD_CONF_LIMIT_SETTING, uploadLimitConf.getString() );
COConfigurationManager.setParameter(SpeedLimitMonitor.DOWNLOAD_CONF_LIMIT_SETTING, downloadLimitConf.getString() );
COConfigurationManager.setParameter(SpeedLimitMonitor.UPLOAD_CHOKE_PING_COUNT,uploadChokePingCount);
}
private void logPMData(int oRate, SpeedLimitConfidence oConf, int nRate, float nConf, String type){
SpeedManagerLogger.log("speed-limit-conf: "+type+" rate="+oRate+" conf="+oConf.getString()+"("+oConf.asEstimateType()
+") pm-rate="+nRate+" pm-conf="+nConf);
}//logPMData
public void logPMDataEx(){
int tuploadLimitMax = COConfigurationManager.getIntParameter(SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT);
int tdownloadLimitMax =COConfigurationManager.getIntParameter(SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT);
//for testing.
SpeedManager sm = AzureusCoreFactory.getSingleton().getSpeedManager();
SpeedManagerLimitEstimate dEst = sm.getEstimatedDownloadCapacityBytesPerSec();
int tmpDMax = dEst.getBytesPerSec();
float tmpDMaxConf = dEst.getEstimateType();
// for testing.
SpeedManagerLimitEstimate uEst = sm.getEstimatedUploadCapacityBytesPerSec();
int tmpUMax = uEst.getBytesPerSec();
float tmpUMaxConf = uEst.getEstimateType();
SpeedLimitConfidence tuploadLimitConf = SpeedLimitConfidence.parseString(
COConfigurationManager.getStringParameter( SpeedLimitMonitor.UPLOAD_CONF_LIMIT_SETTING ));
SpeedLimitConfidence tdownloadLimitConf = SpeedLimitConfidence.parseString(
COConfigurationManager.getStringParameter( SpeedLimitMonitor.DOWNLOAD_CONF_LIMIT_SETTING));
//
logPMData(tuploadLimitMax, tuploadLimitConf, tmpUMax, tmpUMaxConf, "check-upload" );
logPMData(tdownloadLimitMax, tdownloadLimitConf, tmpDMax, tmpDMaxConf, "check-download" );
}//logPMDataEx
/**
* The criteria for download being unlimited is if the ConfigPanel has the
* "download == 0 " && "type==fixed"
* @return - true
*/
private boolean isSettingDownloadUnlimited(){
SpeedManagerAlgorithmProviderAdapter adpter = SMInstance.getInstance().getAdapter();
SpeedManager sm = adpter.getSpeedManager();
SpeedManagerLimitEstimate dEst = sm.getEstimatedDownloadCapacityBytesPerSec();
int rate = dEst.getBytesPerSec();
float type = dEst.getEstimateType();
//user or plug-in want the download rate unlimited.
if( rate==0 && type==SpeedManagerLimitEstimate.TYPE_MANUAL ){
return true;
}
//start the search in unlimited mode.
if( rate==0 && type==SpeedManagerLimitEstimate.TYPE_UNKNOWN){
return true;
}
return false;
}
//SpeedLimitMonitorStatus
public void setDownloadBandwidthMode(int rate, int limit){
downloadBandwidthStatus = SaturatedMode.getSaturatedMode(rate,limit);
}
public void setUploadBandwidthMode(int rate, int limit){
uploadBandwidthStatus = SaturatedMode.getSaturatedMode(rate,limit);
}
public void setDownloadLimitSettingMode(int currLimit){
downloadLimitSettingStatus = SaturatedMode.getSaturatedMode(currLimit, downloadLimitMax);
}
public void setUploadLimitSettingMode(int currLimit){
if( !transferMode.isDownloadMode() ){
uploadLimitSettingStatus = SaturatedMode.getSaturatedMode(currLimit, uploadLimitMax);
}else{
uploadLimitSettingStatus = SaturatedMode.getSaturatedMode(currLimit, uploadLimitMax);
}
}
public int getUploadMaxLimit(){
return uploadLimitMax;
}
public int getDownloadMaxLimit(){
return downloadLimitMax;
}
public int getUploadMinLimit(){
return uploadLimitMin;
}
public int getDownloadMinLimit(){
return downloadLimitMin;
}
public String getUploadConfidence(){
return uploadLimitConf.getString();
}
public String getDownloadConfidence(){
return downloadLimitConf.getString();
}
public SaturatedMode getDownloadBandwidthMode(){
return downloadBandwidthStatus;
}
public SaturatedMode getUploadBandwidthMode(){
return uploadBandwidthStatus;
}
public SaturatedMode getDownloadLimitSettingMode(){
return downloadLimitSettingStatus;
}
public SaturatedMode getUploadLimitSettingMode(){
return uploadLimitSettingStatus;
}
public void updateTransferMode(){
transferMode.updateStatus( downloadBandwidthStatus );
}
public String getTransferModeAsString(){
return transferMode.getString();
}
public TransferMode getTransferMode(){
return transferMode;
}
/**
* Are both the upload and download bandwidths usages is low?
* Otherwise false.
* @return -
*/
public boolean bandwidthUsageLow(){
if( uploadBandwidthStatus.compareTo(SaturatedMode.LOW)<=0 &&
downloadBandwidthStatus.compareTo(SaturatedMode.LOW)<=0){
return true;
}
//Either upload or download is at MEDIUM or above.
return false;
}
/**
*
* @return -
*/
public boolean bandwidthUsageMedium(){
if( uploadBandwidthStatus.compareTo(SaturatedMode.MED)<=0 &&
downloadBandwidthStatus.compareTo(SaturatedMode.MED)<=0){
return true;
}
//Either upload or download is at MEDIUM or above.
return false;
}
/**
* True if both are at limits.
* @return - true only if both the upload and download usages are at the limits.
*/
public boolean bandwidthUsageAtLimit(){
if( uploadBandwidthStatus.compareTo(SaturatedMode.AT_LIMIT)==0 &&
downloadBandwidthStatus.compareTo(SaturatedMode.AT_LIMIT)==0){
return true;
}
return false;
}
/**
* True if the upload bandwidth usage is HIGH or AT_LIMIT.
* @return -
*/
public boolean isUploadBandwidthUsageHigh(){
if( uploadBandwidthStatus.compareTo(SaturatedMode.AT_LIMIT)==0 ||
uploadBandwidthStatus.compareTo(SaturatedMode.HIGH)==0){
return true;
}
return false;
}
public boolean isEitherLimitUnpinned(){
return ( !isUploadMaxPinned || !isDownloadMaxPinned );
}
/**
* Does the same as createNewLimit except it drops the upload rate first when in download mode.
* @param signalStrength -
* @param multiple -
* @param currUpLimit -
* @param currDownLimit -
* @return -
*/
public SMUpdate modifyLimits(float signalStrength, float multiple, int currUpLimit, int currDownLimit){
//this flag is set in a previous method.
if( isStartLimitTestFlagSet() ){
SpeedManagerLogger.trace("modifyLimits - startLimitTesting.");
SMUpdate update = startLimitTesting(currUpLimit, currDownLimit);
return checkActiveProgressiveDownloadLimit( update );
}
if( isEitherLimitUnpinned() ){
SpeedManagerLogger.trace("modifyLimits - calculateNewUnpinnedLimits");
SMUpdate update = calculateNewUnpinnedLimits(signalStrength);
return checkActiveProgressiveDownloadLimit( update );
}
slider.updateLimits(uploadLimitMax,uploadLimitMin,
downloadLimitMax,downloadLimitMin);
slider.updateStatus(currUpLimit,uploadBandwidthStatus,
currDownLimit, downloadBandwidthStatus,transferMode);
SMUpdate update = slider.adjust( signalStrength*multiple );
return checkActiveProgressiveDownloadLimit( update );
}//modifyLimits
/**
* If a progressive download is currently active. Then the download limit should
* not be allowed to go below that limit, regardless of anything else.
* @param update -
* @return -
*/
private SMUpdate checkActiveProgressiveDownloadLimit( SMUpdate update ){
//Do we have an active download limit?
long prgDownLimit = RealTimeInfo.getProgressiveActiveBytesPerSec();
//If the value is zero, then the no progressive download is currently active.
if( prgDownLimit==0 ){
return update;
}
//We seem to have an active progressive download. Make sure the limit does not
//drop below that limit.
final int MULTIPLE = 2;
if( prgDownLimit*MULTIPLE > update.newDownloadLimit && update.newDownloadLimit!=0 )
{
log( "Active Progressive download in progress. Overriding limit. curr="+update.newDownloadLimit
+" progDownloadLimit="+prgDownLimit*MULTIPLE );
update.newDownloadLimit = (int)prgDownLimit*MULTIPLE;
}//if
return update;
}//checkActiveProgressiveDownloadLimit
/**
* Log debug info needed during beta period.
*/
private void logPinningInfo() {
StringBuffer sb = new StringBuffer("pin: ");
if(isUploadMaxPinned){
sb.append("ul-pinned:");
}else{
sb.append("ul-unpinned:");
}
if(isDownloadMaxPinned){
sb.append("dl-pinned:");
}else{
sb.append("dl-unpinned:");
}
long currTime = SystemTime.getCurrentTime();
long upWait = currTime - uploadAtLimitStartTime;
long downWait = currTime - downloadAtLimitStartTime;
sb.append(upWait).append(":").append(downWait);
log( sb.toString() );
}
/**
*
* @param signalStrength -
* @return -
*/
public SMUpdate calculateNewUnpinnedLimits(float signalStrength){
//first verify that is this is an up signal.
if(signalStrength<0.0f){
//down-tick is a signal to stop moving the files up.
isUploadMaxPinned=true;
isDownloadMaxPinned=true;
}//if
//just verify settings to make sure everything is sane before updating.
boolean updateUpload=false;
boolean updateDownload=false;
if( uploadBandwidthStatus.compareTo(SaturatedMode.AT_LIMIT)==0 &&
uploadLimitSettingStatus.compareTo(SaturatedMode.AT_LIMIT)==0 ){
updateUpload=true;
}
if( downloadBandwidthStatus.compareTo(SaturatedMode.AT_LIMIT)==0 &&
downloadLimitSettingStatus.compareTo(SaturatedMode.AT_LIMIT)==0 ){
updateDownload=true;
}
boolean uploadChanged=false;
boolean downloadChanged=false;
if(updateUpload && !transferMode.isDownloadMode() ){
//slow the upload rate the more.
uploadPinCounter++;
if( uploadPinCounter%(Math.ceil(Math.sqrt(uploadChokePingCount)))==0 ){
//increase limit by calculated amount, but only if not in downloading mode.
uploadLimitMax += calculateUnpinnedStepSize(uploadLimitMax);
uploadChanged=true;
COConfigurationManager.setParameter(
SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT, uploadLimitMax);
COConfigurationManager.setParameter(
SpeedLimitMonitor.UPLOAD_CHOKE_PING_COUNT,uploadChokePingCount);
}//if
}
if(updateDownload && !slider.isDownloadUnlimitedMode() ){
//increase limit by calculated amount.
downloadLimitMax += calculateUnpinnedStepSize(downloadLimitMax);
downloadChanged=true;
COConfigurationManager.setParameter(
SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT, downloadLimitMax);
}
//apply any rules that need applied.
//The download limit can never be less then the upload limit. (Unless zero. UNLIMITED)
if( uploadLimitMax > downloadLimitMax){
downloadLimitMax = uploadLimitMax;
downloadChanged=true;
COConfigurationManager.setParameter(
SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT, downloadLimitMax);
}
uploadLimitMin = SMConst.calculateMinUpload( uploadLimitMax );
downloadLimitMin = SMConst.calculateMinDownload( downloadLimitMax );
if( slider.isDownloadUnlimitedMode() ){
SpeedManagerLogger.trace("upload unpinned while download is unlimited.");
return new SMUpdate(uploadLimitMax,uploadChanged, 0,false);
}
return new SMUpdate(uploadLimitMax,uploadChanged, downloadLimitMax,downloadChanged);
}//calculateNewUnpinnedLimits
/**
* If setting is less then 100kBytes take 1 kByte steps.
* If setting is less then 500kBytes take 5 kByte steps.
* if setting is larger take 10 kBytes steps.
* @param currLimitMax - current limit setting.
* @return - set size for next change.
*/
private int calculateUnpinnedStepSize(int currLimitMax){
if(currLimitMax<102400){
return 1024;
}else if(currLimitMax<409600){
return 1024*5;
}else if(currLimitMax>=409600){
return 1024*10;
}
return 1024;
}//
/**
* Make a decision about unpinning either the upload or download limit. This is based on the
* time we are saturating the limit without a down-tick signal.
*/
public void checkForUnpinningCondition(){
long currTime = SystemTime.getCurrentTime();
//verify the download is not unlimited.
slider.setDownloadUnlimitedMode( isSettingDownloadUnlimited() );
//upload useage must be at limits for a set period of time before unpinning.
if( !uploadBandwidthStatus.equals(SaturatedMode.AT_LIMIT) ||
!uploadLimitSettingStatus.equals(SaturatedMode.AT_LIMIT) )
{
//start the clock over.
uploadAtLimitStartTime = currTime;
}else{
//check to see if we have been here for the time limit.
if( uploadAtLimitStartTime+(TIME_AT_LIMIT_BEFORE_UNPINNING* uploadChokePingCount) < currTime ){
if( isUploadConfidenceLow() ){
if( !transferMode.isDownloadMode() ){
//alway slow search the upload limit.
isUploadMaxPinned = false;
}
}else{
//Don't unpin the limit is we have absolute confidence in it.
if( !isUploadConfidenceAbsolute() ){
//we have been AT_LIMIT long enough. Time to un-pin the limit see if we can go higher.
isUploadMaxPinned = false;
SpeedManagerLogger.trace("unpinning the upload max limit!! #choke-pings="+uploadChokePingCount+
", pin-counter="+uploadPinCounter);
}
}
}
}
//download usage must be at limits for a set period of time before unpinning.
if( !downloadBandwidthStatus.equals(SaturatedMode.AT_LIMIT) ||
!downloadLimitSettingStatus.equals(SaturatedMode.AT_LIMIT) )
{
//start the clock over.
downloadAtLimitStartTime = currTime;
}else{
//check to see if we have been here for the time limit.
if( downloadAtLimitStartTime+TIME_AT_LIMIT_BEFORE_UNPINNING < currTime ){
if( isDownloadConfidenceLow() ){
if( transferMode.isDownloadMode() ){
triggerLimitTestingFlag();
}
}else{
if( !isDownloadConfidenceAbsolute() ){
//we have been AT_LIMIT long enough. Time to un-pin the limit see if we can go higher.
isDownloadMaxPinned = false;
SpeedManagerLogger.trace("unpinning the download max limit!!");
}
}
}
}
logPinningInfo();
}
/**
* If we have a down-tick signal then resetTimer all the counters for increasing the limits.
*/
public void notifyOfDownSignal(){
if( !isUploadMaxPinned ){
uploadChokePingCount++;
String msg = "pinning the upload max limit, due to downtick signal. #downtick="+ uploadChokePingCount;
SpeedManagerLogger.trace(msg);
SMSearchLogger.log(msg);
}
if( !isDownloadMaxPinned ){
String msg = "pinning the download max limit, due to downtick signal.";
SpeedManagerLogger.trace(msg);
SMSearchLogger.log(msg);
}
resetPinSearch();
}
void resetPinSearch(){
long currTime = SystemTime.getCurrentTime();
uploadAtLimitStartTime = currTime;
downloadAtLimitStartTime = currTime;
isUploadMaxPinned = true;
isDownloadMaxPinned = true;
}
void resetPinSearch(SpeedManagerLimitEstimate estimate){
//chocking ping needs higher limit.
float type = estimate.getEstimateType();
if(type>=SpeedManagerLimitEstimate.TYPE_CHOKE_ESTIMATED){
uploadChokePingCount++;
}
resetPinSearch();
}
/**
* Return true if we are confidence testing the limits.
* @return - SMUpdate
*/
public boolean isConfTestingLimits(){
return transferMode.isConfTestingLimits();
}//
/**
* Determine if we have low confidence in this limit.
* @return - true if the confidence setting is LOW or NONE. Otherwise return true.
*/
public boolean isDownloadConfidenceLow(){
return ( downloadLimitConf.compareTo(SpeedLimitConfidence.MED) < 0 );
}
public boolean isUploadConfidenceLow(){
return ( uploadLimitConf.compareTo(SpeedLimitConfidence.MED) < 0 );
}
public boolean isDownloadConfidenceAbsolute(){
return ( downloadLimitConf.compareTo(SpeedLimitConfidence.ABSOLUTE)==0 );
}
public boolean isUploadConfidenceAbsolute(){
return ( uploadLimitConf.compareTo(SpeedLimitConfidence.ABSOLUTE)==0 );
}
/**
*
* @param downloadRate - currentUploadRate in bytes/sec
* @param uploadRate - currentUploadRate in bytes/sec
*/
public synchronized void updateLimitTestingData( int downloadRate, int uploadRate ){
if( downloadRate>highestDownloadRate ){
highestDownloadRate=downloadRate;
}
if( uploadRate>highestUploadRate){
highestUploadRate=uploadRate;
}
//The exit criteria for this test is 30 seconds without an increase in the limits.
long currTime = SystemTime.getCurrentTime();
if( currTime > clLastIncreaseTime+CONF_LIMIT_TEST_LENGTH){
//set the test done flag.
currTestDone=true;
}
// or 30 seconds after its first bad ping.
if( clFirstBadPingTime!=-1){
if( currTime > clFirstBadPingTime+CONF_LIMIT_TEST_LENGTH){
//set the test done flag.
currTestDone=true;
}
}
}//updateLimitTestingData.
/**
* Convert raw ping value to new metric.
* @param lastMetric -
*/
public void updateLimitTestingPing(int lastMetric){
//Convert raw - pings into a rating.
if(lastMetric>500){
updateLimitTestingPing(-1.0f);
}
}
/**
* New metric from the PingMapper is value between -1.0 and +1.0f.
* @param lastMetric -
*/
public void updateLimitTestingPing(float lastMetric){
if( lastMetric<-0.3f){
//Setting this time is a signal to end soon.
clFirstBadPingTime = SystemTime.getCurrentTime();
}
}
/**
* Call this method to start the limit testing.
* @param currUploadLimit -
* @param currDownloadLimit -
* @return - SMUpdate
*/
public SMUpdate startLimitTesting(int currUploadLimit, int currDownloadLimit){
clLastIncreaseTime =SystemTime.getCurrentTime();
clFirstBadPingTime =-1;
highestUploadRate=0;
highestDownloadRate=0;
currTestDone=false;
//reset the flag.
beginLimitTest=false;
//get the limits before the test, we are restoring them after the test.
preTestUploadLimit = currUploadLimit;
preTestDownloadLimit = currDownloadLimit;
//configure the limits for this test. One will be at min and the other unlimited.
SMUpdate retVal;
if( transferMode.isDownloadMode() ){
//test the download limit.
retVal = new SMUpdate(uploadLimitMin,true,
Math.round(downloadLimitMax *1.2f),true);
preTestDownloadCapacity = downloadLimitMax;
transferMode.setMode( TransferMode.State.DOWNLOAD_LIMIT_SEARCH );
}else{
//test the upload limit.
retVal = new SMUpdate( Math.round(uploadLimitMax *1.2f),true,
downloadLimitMin,true);
preTestUploadCapacity = uploadLimitMax;
transferMode.setMode( TransferMode.State.UPLOAD_LIMIT_SEARCH );
}
return retVal;
}
/**
* Ramp the upload and download rates higher, so ping-times are relevant.
* @param uploadLimit -
* @param downloadLimit -
* @return -
*/
public SMUpdate rampTestingLimit(int uploadLimit, int downloadLimit){
SMUpdate retVal;
if( transferMode.getMode() == TransferMode.State.DOWNLOAD_LIMIT_SEARCH
&& downloadBandwidthStatus.isGreater( SaturatedMode.MED ) )
{
downloadLimit *= 1.1f;
clLastIncreaseTime = SystemTime.getCurrentTime();
retVal = new SMUpdate(uploadLimit,false,downloadLimit,true);
}else if( transferMode.getMode() == TransferMode.State.UPLOAD_LIMIT_SEARCH
&& uploadBandwidthStatus.isGreater( SaturatedMode.MED ))
{
uploadLimit *= 1.1f;
clLastIncreaseTime = SystemTime.getCurrentTime();
retVal = new SMUpdate(uploadLimit,true,downloadLimit,false);
}else{
retVal = new SMUpdate(uploadLimit,false,downloadLimit,false);
SpeedManagerLogger.trace("ERROR: rampTestLimit should only be called during limit testing. ");
}
return retVal;
}//rampTestingLimit
public void triggerLimitTestingFlag(){
SpeedManagerLogger.trace("triggerd fast limit test.");
beginLimitTest=true;
//if we are using a persistent PingSource then get that here.
if( useVariancePingMap ){
SMInstance pm = SMInstance.getInstance();
SpeedManagerAlgorithmProviderAdapter adapter = pm.getAdapter();
//start a new transientPingMap;
if(transientPingMap!=null){
transientPingMap.destroy();
}
transientPingMap = adapter.createTransientPingMapper();
}
}
public synchronized boolean isStartLimitTestFlagSet(){
return beginLimitTest;
}
public synchronized boolean isConfLimitTestFinished(){
return currTestDone;
}
public synchronized SMUpdate endLimitTesting(int downloadCapacityGuess, int uploadCapacityGuess){
SpeedManagerLogger.trace(" repalce highestDownloadRate: "+highestDownloadRate+" with "+downloadCapacityGuess);
SpeedManagerLogger.trace(" replace highestUploadRate: "+highestUploadRate+" with "+uploadCapacityGuess);
highestDownloadRate = downloadCapacityGuess;
highestUploadRate = uploadCapacityGuess;
return endLimitTesting();
}
/**
* Call this method to end the limit testing.
* @return - SMUpdate
*/
public synchronized SMUpdate endLimitTesting(){
SMUpdate retVal;
//determine if the new setting is different then the old setting.
if( transferMode.getMode()==TransferMode.State.DOWNLOAD_LIMIT_SEARCH ){
downloadLimitConf = determineConfidenceLevel();
//set that value.
SpeedManagerLogger.trace("pre-upload-setting="+ preTestUploadCapacity +" up-capacity"+ uploadLimitMax
+" pre-download-setting="+ preTestDownloadCapacity +" down-capacity="+ downloadLimitMax);
retVal = new SMUpdate(preTestUploadLimit,true, downloadLimitMax,true);
//change back to original mode.
transferMode.setMode( TransferMode.State.DOWNLOADING );
}else if( transferMode.getMode()==TransferMode.State.UPLOAD_LIMIT_SEARCH){
uploadLimitConf = determineConfidenceLevel();
//set that value.
retVal = new SMUpdate(uploadLimitMax,true, downloadLimitMax,true);
//change back to original mode.
transferMode.setMode( TransferMode.State.SEEDING );
}else{
//This is an "illegal state" make it in the logs, but try to recover by setting back to original state.
SpeedManagerLogger.log("SpeedLimitMonitor had IllegalState during endLimitTesting.");
retVal = new SMUpdate(preTestUploadLimit,true, preTestDownloadLimit,true);
}
currTestDone=true;
//reset the counter
uploadAtLimitStartTime = SystemTime.getCurrentTime();
downloadAtLimitStartTime = SystemTime.getCurrentTime();
return retVal;
}
/**
* After a test is complete determine how condifent the client should be in it
* based on how different it is from the previous result. If the new result is within
* 20% of the old result then give it a MED. If it is great then give it a LOW.
* @return - what the new confidence interval should be.
*/
public SpeedLimitConfidence determineConfidenceLevel(){
SpeedLimitConfidence retVal=SpeedLimitConfidence.NONE;
String settingMaxLimitName;
//String settingMinLimitName;
boolean isDownload;
String settingConfidenceName;
int preTestValue;
int highestValue;
if(transferMode.getMode()==TransferMode.State.DOWNLOAD_LIMIT_SEARCH){
settingConfidenceName = DOWNLOAD_CONF_LIMIT_SETTING;
settingMaxLimitName = SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT;
isDownload=true;
preTestValue = preTestDownloadCapacity;
highestValue = highestDownloadRate;
}else if(transferMode.getMode()==TransferMode.State.UPLOAD_LIMIT_SEARCH){
settingConfidenceName = UPLOAD_CONF_LIMIT_SETTING;
settingMaxLimitName = SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT;
isDownload=false;
preTestValue = preTestUploadCapacity;
highestValue = highestUploadRate;
}else{
//
SpeedManagerLogger.log("IllegalState in determineConfidenceLevel(). Setting level to NONE.");
return SpeedLimitConfidence.NONE;
}
boolean hadChockingPing = hadChockingPing();
float percentDiff = (float)Math.abs( highestValue-preTestValue )/(float)(Math.max(highestValue,preTestValue));
if( percentDiff<0.15f && hadChockingPing ){
//Only set to medium if had both a chocking ping and two tests with similar results.
retVal = SpeedLimitConfidence.MED;
}else{
retVal = SpeedLimitConfidence.LOW;
}
//update the values.
COConfigurationManager.setParameter(settingConfidenceName, retVal.getString() );
int newMaxLimitSetting = highestValue;
COConfigurationManager.setParameter(settingMaxLimitName, newMaxLimitSetting);
int newMinLimitSetting;
if( isDownload ){
newMinLimitSetting = SMConst.calculateMinDownload( newMaxLimitSetting );
}else{
newMinLimitSetting = SMConst.calculateMinUpload( newMaxLimitSetting );
}
StringBuffer sb = new StringBuffer();
if( transferMode.getMode()==TransferMode.State.UPLOAD_LIMIT_SEARCH ){
sb.append("new upload limits: ");
uploadLimitMax =newMaxLimitSetting;
uploadLimitMin=newMinLimitSetting;
//downloadCapacity can never be less then upload capacity.
if( downloadLimitMax < uploadLimitMax){
downloadLimitMax = uploadLimitMax;
COConfigurationManager.setParameter(
SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT, downloadLimitMax);
}
sb.append(uploadLimitMax);
}else{
sb.append("new download limits: ");
downloadLimitMax =newMaxLimitSetting;
downloadLimitMin=newMinLimitSetting;
//upload capacity should never be 40x less then download.
if( uploadLimitMax * 40 < downloadLimitMax){
uploadLimitMax = downloadLimitMax /40;
COConfigurationManager.setParameter(
SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT, uploadLimitMax);
uploadLimitMin = SMConst.calculateMinUpload( uploadLimitMax );
}//if
sb.append(downloadLimitMax);
}
slider.updateLimits(uploadLimitMax,uploadLimitMin,downloadLimitMax,downloadLimitMin);
SpeedManagerLogger.trace( sb.toString() );
return retVal;
}
/**
* If the user changes the line capacity settings on the configuration panel and adjustment
* needs to occur even if the signal is NO-CHANGE-NEEDED. Test for that condition here.
* @param currUploadLimit - reported upload capacity from the adapter
* @param currDownloadLimit - reported download capacity from the adapter.
* @return - true if the "capacity" is lower then the current limit.
*/
public boolean areSettingsInSpec(int currUploadLimit, int currDownloadLimit){
//during a confidence level test, anything goes.
if( isConfTestingLimits() ){
return true;
}
boolean retVal = true;
if( currUploadLimit> uploadLimitMax){
retVal = false;
}
if( currDownloadLimit> downloadLimitMax && slider.isDownloadUnlimitedMode() ){
retVal = false;
}
return retVal;
}
private int choseBestLimit(SpeedManagerLimitEstimate estimate, int currMaxLimit, SpeedLimitConfidence currConf) {
float type = estimate.getEstimateType();
int estBytesPerSec = estimate.getBytesPerSec();
int chosenLimit;
//no estimate less then 20k accepted.
if( (estBytesPerSec<currMaxLimit) && estBytesPerSec<20480 ){
return currMaxLimit;
}
String reason="";
if( type==SpeedManagerLimitEstimate.TYPE_MANUAL){
chosenLimit = estBytesPerSec;
reason="manual";
}else if( type==SpeedManagerLimitEstimate.TYPE_UNKNOWN){
chosenLimit = Math.max( estBytesPerSec, currMaxLimit );
reason="unknown";
}else{
//chose ping mapper.
chosenLimit = estBytesPerSec;
}
SpeedManagerLogger.trace("bestChosenLimit: reason="+reason+",chosenLimit="+chosenLimit);
return chosenLimit;
}
/**
* Make some choices about how usable the limits are before passing them on.
* @param estUp -
* @param estDown -
*/
public void setRefLimits(SpeedManagerLimitEstimate estUp,SpeedManagerLimitEstimate estDown){
SpeedManagerLimitEstimate up = SMConst.filterEstimate(estUp,SMConst.MIN_UPLOAD_BYTES_PER_SEC);
int upMax = choseBestLimit(up, uploadLimitMax, uploadLimitConf);
SpeedManagerLimitEstimate down = SMConst.filterEstimate(estDown, SMConst.MIN_DOWNLOAD_BYTES_PER_SEC);
int downMax = choseBestLimit(down, downloadLimitMax, downloadLimitConf);
if(downMax<upMax){
SpeedManagerLogger.trace("down max-limit was less then up-max limit. increasing down max-limit. upMax="
+upMax+" downMax="+downMax);
downMax = upMax;
}
setRefLimits(upMax,downMax);
}
public void setRefLimits(int uploadMax, int downloadMax){
if( (uploadLimitMax!=uploadMax) && (uploadMax>0) ){
uploadLimitMax=uploadMax;
COConfigurationManager.setParameter(
SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT, uploadLimitMax);
}
uploadLimitMin = SMConst.calculateMinUpload( uploadMax );
if( (downloadLimitMax!=downloadMax) && (downloadMax>0) ){
downloadLimitMax = downloadMax;
COConfigurationManager.setParameter(
SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT, downloadLimitMax);
}
downloadLimitMin = SMConst.calculateMinDownload(downloadMax);
SpeedManagerLogger.trace("setRefLimits uploadMax="+uploadMax+" uploadLimitMax="+uploadLimitMax+", downloadMax="+downloadMax+" downloadLimitMax="+downloadLimitMax);
slider.updateLimits(uploadLimitMax,uploadLimitMin,downloadLimitMax,downloadLimitMin);
}
/**
* It is likely the user adjusted the "line speed capacity" on the configuration panel.
* We need to adjust the current limits down to adjust.
* @param currUploadLimit -
* @param currDownloadLimit -
* @return - Updates as needed.
*/
public SMUpdate adjustLimitsToSpec(int currUploadLimit, int currDownloadLimit){
int newUploadLimit = currUploadLimit;
boolean uploadChanged = false;
int newDownloadLimit = currDownloadLimit;
boolean downloadChanged = false;
StringBuffer reason = new StringBuffer();
//check for the case when the line-speed capacity is below the current limit.
if( currUploadLimit> uploadLimitMax && uploadLimitMax!=0){
newUploadLimit = uploadLimitMax;
uploadChanged = true;
reason.append(" (a) upload line-speed cap below current limit. ");
}
if(uploadLimitMax==0){
reason.append("** uploadLimitMax=0 (Unlimited)! ** ");
}
//check for the case when the min setting has been moved above the current limit.
if( currDownloadLimit> downloadLimitMax && !slider.isDownloadUnlimitedMode() ){
newDownloadLimit = downloadLimitMax;
downloadChanged = true;
reason.append(" (b) download line-speed cap below current limit. ");
}
//Another possibility is the min limits have been raised.
if( currUploadLimit<uploadLimitMin ){
newUploadLimit = uploadLimitMin;
uploadChanged = true;
reason.append(" (c) min upload limit raised. ");
}
if( currDownloadLimit<downloadLimitMin ){
newDownloadLimit = downloadLimitMin;
downloadChanged = true;
reason.append(" (d) min download limit raised. ");
}
SpeedManagerLogger.trace("Adjusting limits due to out of spec: new-up="+newUploadLimit
+" new-down="+newDownloadLimit+" reasons: "+reason.toString());
return new SMUpdate(newUploadLimit,uploadChanged,newDownloadLimit,downloadChanged);
}
protected void log(String str){
SpeedManagerLogger.log(str);
}//log
public void initPingSpaceMap(int maxGoodPing, int minBadPing){
pingMapOfDownloadMode = new PingSpaceMapper(maxGoodPing,minBadPing);
pingMapOfSeedingMode = new PingSpaceMapper(maxGoodPing,minBadPing);
//pingMonitor = new PingSpaceMonitor(maxGoodPing,minBadPing,transferMode);
useVariancePingMap = false;
}
public void initPingSpaceMap(){
useVariancePingMap = true;
//ToDo: remove after beta-testing - just to characterize the different methods.
// pingMapOfDownloadMode = new PingSpaceMapper(150,500);
// pingMapOfSeedingMode = new PingSpaceMapper(150,500);
}
/**
* This is a lot of data, but is important debug info.
* @param name -
* @param transEst -
* @param hadChockPing -
* @param permEst -
* @param downMode -
* @param seedMode -
*/
public void betaLogPingMapperEstimates(String name,
SpeedManagerLimitEstimate transEst,
boolean hadChockPing,
SpeedManagerLimitEstimate permEst,
PingSpaceMapper downMode,
PingSpaceMapper seedMode)
{
StringBuffer sb = new StringBuffer("beta-ping-maps-").append(name).append(": ");
if(transEst!=null){
int rate = transEst.getBytesPerSec();
float conf = transEst.getMetricRating();
sb.append("transient-").append(rate).append("(").append(conf).append(")");
}
sb.append(" chockPing=").append(hadChockPing);
if(permEst!=null){
int rate = permEst.getBytesPerSec();
float conf = permEst.getMetricRating();
sb.append("; perm-").append(rate).append("(").append(conf).append(")");
}
if(downMode!=null){
int rateDown = downMode.guessDownloadLimit();
int rateUp = downMode.guessUploadLimit();
boolean downChockPing = downMode.hadChockingPing(true);
boolean upChockPing = downMode.hadChockingPing(false);
sb.append("; downMode- ");
sb.append("rateDown=").append(rateDown).append(" ");
sb.append("rateUp=").append(rateUp).append(" ");
sb.append("downChockPing=").append(downChockPing).append(" ");
sb.append("upChockPing=").append(upChockPing).append(" ");
}
if(seedMode!=null){
int rateDown = seedMode.guessDownloadLimit();
int rateUp = seedMode.guessUploadLimit();
boolean downChockPing = seedMode.hadChockingPing(true);
boolean upChockPing = seedMode.hadChockingPing(false);
sb.append("; seedMode- ");
sb.append("rateDown=").append(rateDown).append(" ");
sb.append("rateUp=").append(rateUp).append(" ");
sb.append("downChockPing=").append(downChockPing).append(" ");
sb.append("upChockPing=").append(upChockPing).append(" ");
}
SpeedManagerLogger.log( sb.toString() );
}//betaLogPingMapperEstimates
public int guessDownloadLimit(){
if( !useVariancePingMap){
return pingMapOfDownloadMode.guessDownloadLimit();
}else{
boolean wasChocked=true;
SpeedManagerLimitEstimate transientEst=null;
if(transientPingMap!=null){
transientEst = transientPingMap.getLastBadDownloadLimit();
if(transientEst==null){
wasChocked=false;
transientEst = transientPingMap.getEstimatedDownloadLimit(false);
}
}
//NOTE: Currently just getting the persistentMap for temp logging purposes.
SMInstance pm = SMInstance.getInstance();
SpeedManagerAlgorithmProviderAdapter adapter = pm.getAdapter();
SpeedManagerPingMapper persistentMap = adapter.getPingMapper();
SpeedManagerLimitEstimate persistentEst = persistentMap.getEstimatedDownloadLimit(false);
//log the different ping-mappers for beta.
betaLogPingMapperEstimates("down",transientEst,wasChocked,persistentEst,pingMapOfDownloadMode,pingMapOfSeedingMode);
if( transientEst!=null )
{
return choseBestLimit(transientEst,downloadLimitMax,downloadLimitConf);
}else{
return downloadLimitMax;
}
}
}//guessDownloadLimit
public int guessUploadLimit(){
if( !useVariancePingMap){
int dmUpLimitGuess = pingMapOfDownloadMode.guessUploadLimit();
int smUpLimitGuess = pingMapOfSeedingMode.guessUploadLimit();
return Math.max(dmUpLimitGuess,smUpLimitGuess);
}else{
boolean wasChocked=true;
SpeedManagerLimitEstimate transientEst=null;
if(transientPingMap!=null){
transientEst = transientPingMap.getLastBadUploadLimit();
if(transientEst==null){
wasChocked=false;
transientEst = transientPingMap.getEstimatedUploadLimit(false);
}
}
//NOTE: Currently just getting the persistentMap for temp logging purposes.
SMInstance pm = SMInstance.getInstance();
SpeedManagerAlgorithmProviderAdapter adapter = pm.getAdapter();
SpeedManagerPingMapper persistentMap = adapter.getPingMapper();
SpeedManagerLimitEstimate persistentEst = persistentMap.getEstimatedUploadLimit(false);
//log the different ping-mappers for beta.
betaLogPingMapperEstimates("up",transientEst,wasChocked,persistentEst,pingMapOfDownloadMode,pingMapOfSeedingMode);
if( transientEst!=null )
{
return choseBestLimit(transientEst,uploadLimitMax,uploadLimitConf);
}else{
return uploadLimitMax;
}
}
}//guessUploadLimit
/**
* Should return true if had a recent chocking ping.
* @return - true if
*/
public boolean hadChockingPing(){
if( !useVariancePingMap){
return pingMapOfDownloadMode.hadChockingPing(true);
}else{
SpeedManagerPingMapper pm = SMInstance.getInstance().getAdapter().getPingMapper();
//if either had a choking ping.
SpeedManagerLimitEstimate dEst = pm.getEstimatedDownloadLimit(true);
SpeedManagerLimitEstimate uEst = pm.getEstimatedUploadLimit(true);
boolean hadChokePingUp = (uEst.getEstimateType()==SpeedManagerLimitEstimate.TYPE_CHOKE_ESTIMATED);
boolean hadChokePingDown = (dEst.getEstimateType()==SpeedManagerLimitEstimate.TYPE_CHOKE_ESTIMATED);
return ( hadChokePingUp || hadChokePingDown );
}
}//hadChockingPing
/**
* Just log this data until we decide if it is useful.
*/
public void logPingMapData() {
if( !useVariancePingMap){
int downLimGuess = pingMapOfDownloadMode.guessDownloadLimit();
int upLimGuess = pingMapOfDownloadMode.guessUploadLimit();
int seedingUpLimGuess = pingMapOfSeedingMode.guessUploadLimit();
StringBuffer sb = new StringBuffer("ping-map: ");
sb.append(":down=").append(downLimGuess);
sb.append(":up=").append(upLimGuess);
sb.append(":(seed)up=").append(seedingUpLimGuess);
SpeedManagerLogger.log( sb.toString() );
}else{
SMInstance pm = SMInstance.getInstance();
SpeedManagerAlgorithmProviderAdapter adapter = pm.getAdapter();
SpeedManagerPingMapper persistentMap = adapter.getPingMapper();
SpeedManagerLimitEstimate estUp = persistentMap.getEstimatedUploadLimit(false);
SpeedManagerLimitEstimate estDown = persistentMap.getEstimatedDownloadLimit(false);
int downLimGuess = estDown.getBytesPerSec();
float downConf = estDown.getMetricRating();
int upLimGuess = estUp.getBytesPerSec();
float upConf = estUp.getMetricRating();
String name = persistentMap.getName();
StringBuffer sb = new StringBuffer("new-ping-map: ");
sb.append(" name=").append(name);
sb.append(", down=").append(downLimGuess);
sb.append(", down-conf=").append(downConf);
sb.append(", up=").append(upLimGuess);
sb.append(", up-conf=").append(upConf);
SpeedManagerLogger.log( sb.toString() );
}
}//logPingMapData
public void setCurrentTransferRates(int downRate, int upRate){
if( pingMapOfDownloadMode!=null && pingMapOfSeedingMode!=null){
pingMapOfDownloadMode.setCurrentTransferRates(downRate,upRate);
pingMapOfSeedingMode.setCurrentTransferRates(downRate,upRate);
}
}
public void resetPingSpace(){
if( pingMapOfDownloadMode!=null && pingMapOfSeedingMode!=null){
pingMapOfDownloadMode.reset();
pingMapOfSeedingMode.reset();
}
if(transientPingMap!=null){
transientPingMap.destroy();
}
}
public void addToPingMapData(int lastMetricValue){
String modeStr = getTransferModeAsString();
if( modeStr.equalsIgnoreCase(TransferMode.State.DOWNLOADING.getString())
|| modeStr.equalsIgnoreCase(TransferMode.State.DOWNLOAD_LIMIT_SEARCH.getString()) )
{
//add point to map for download mode
pingMapOfDownloadMode.addMetricToMap(lastMetricValue);
}
else if( modeStr.equalsIgnoreCase(TransferMode.State.SEEDING.getString())
|| modeStr.equalsIgnoreCase(TransferMode.State.UPLOAD_LIMIT_SEARCH.getString()) )
{
//add point to map for seeding mode.
pingMapOfSeedingMode.addMetricToMap(lastMetricValue);
}
//if confidence limit testing, inform of bad ping.
updateLimitTestingPing(lastMetricValue);
longTermMonitor.updateStatus(transferMode);
}//addToPingMapData
public void notifyUpload(SpeedManagerLimitEstimate estimate) {
int bestLimit = choseBestLimit(estimate,uploadLimitMax,uploadLimitConf);
SpeedManagerLogger.trace("notifyUpload uploadLimitMax="+uploadLimitMax);
tempLogEstimate(estimate);
if(bestLimit!=uploadLimitMax){
//update COConfiguration
SpeedManagerLogger.log("persistent PingMap changed upload limit to "+bestLimit);
resetPinSearch(estimate);
uploadLimitMax = bestLimit;
COConfigurationManager.setParameter(
SpeedManagerAlgorithmProviderV2.SETTING_UPLOAD_MAX_LIMIT, uploadLimitMax);
}
uploadLimitMin = SMConst.calculateMinUpload(uploadLimitMax);
slider.updateLimits(uploadLimitMax,uploadLimitMin,downloadLimitMax,downloadLimitMin);
SMSearchLogger.log("new upload rate: "+uploadLimitMax);
}
public void notifyDownload(SpeedManagerLimitEstimate estimate) {
int bestLimit = choseBestLimit(estimate,downloadLimitMax,downloadLimitConf);
SpeedManagerLogger.trace("notifyDownload downloadLimitMax="+downloadLimitMax
+" conf="+downloadLimitConf.getString()+" ("+downloadLimitConf.asEstimateType()+")");
tempLogEstimate(estimate);
if(downloadLimitMax!=bestLimit){
//update COConfiguration
SpeedManagerLogger.log( "persistent PingMap changed download limit to "+bestLimit );
downloadLimitMax = bestLimit;
COConfigurationManager.setParameter(
SpeedManagerAlgorithmProviderV2.SETTING_DOWNLOAD_MAX_LIMIT, bestLimit);
}
downloadLimitMin = SMConst.calculateMinDownload(downloadLimitMax);
slider.updateLimits(uploadLimitMax,uploadLimitMin,downloadLimitMax,downloadLimitMin);
if(estimate.getBytesPerSec()!=0){
slider.setDownloadUnlimitedMode(false);
}else{
slider.setDownloadUnlimitedMode(true);
}
SMSearchLogger.log("download "+downloadLimitMax );
}
private void tempLogEstimate(SpeedManagerLimitEstimate est){
if(est==null){
SpeedManagerLogger.trace( "notify log: SpeedManagerLimitEstimate was null" );
}
StringBuffer sb = new StringBuffer();
float metric = est.getMetricRating();
float type = est.getEstimateType();
int rate = est.getBytesPerSec();
String str = est.getString();
sb.append("notify log: ").append(str);
sb.append(" metricRating=").append(metric);
sb.append(" rate=").append(rate);
sb.append(" type=").append(type);
SpeedManagerLogger.trace( sb.toString() );
}//tempLogEstimate
}//SpeedLimitMonitor