FileDocCategorySizeDatePackage
PingSourceManager.javaAPI DocAzureus 3.0.3.410011Tue Jul 17 10:53:10 BST 2007com.aelitis.azureus.core.speedmanager.impl.v2

PingSourceManager

public class PingSourceManager extends Object
This class manage cycling though the PingSources. It keep track of PingSource stats and applies rules on if/when to cycle though a ping-source. #1) If the slowest ping-source is 10x the the best for a 1 min average. kick it. #2) If a ping-source is slower then two combined sources (2x) for a 5 min average. then kick it. #3) Every 30 minutes kick the slowest ping source and request a new one. Just to keep things fresh. Also maintain logic do determine if a new source is better then the previous one. (To determine if these rules lead to good data.)

Fields Summary
private final Map
pingAverages
private long
lastPingRemoval
private static final long
TIME_BETWEEN_BAD_PING_REMOVALS
private static final long
TIME_BETWEEN_SLOW_PING_REMOVALS
private static final long
TIME_BETWEEN_FORCED_CYCLE_REMOVALS
Constructors Summary
Methods Summary
public voidaddPingTime(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource source)


        if(source==null){
            return;
        }

        PingSourceStats pss = (PingSourceStats) pingAverages.get(source);

        if(pss==null){
            pingSourceFound(source,false);
            pss = (PingSourceStats) pingAverages.get(source);
            SpeedManagerLogger.trace("added new source from addPingTime.");
        }

        int pingTime = source.getPingTime();
        if(pingTime>0){
            pss.addPingTime( source.getPingTime() );
        }

    
private booleancheckForBadPing(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource[] sources)
If the slowest ping in 10x the fastest then remove it.

param
sources -
return
- true is a source has been removed.


        //if we just recently removed a ping source then wait.
        long currTime = SystemTime.getCurrentTime();
        if( currTime<lastPingRemoval+ TIME_BETWEEN_BAD_PING_REMOVALS){
            return false;
        }

        double highestLongTermPing=0.0;
        SpeedManagerPingSource highestSource=null;
        double lowestLongTermPing=10000.0;

        int len = sources.length;
        for(int i=0; i<len; i++){
            PingSourceStats pss = (PingSourceStats) pingAverages.get(sources[i]);
            Average a = pss.getLongTermAve();
            double avePingTime = a.getAverage();

            //is this a new highest value?
            if( avePingTime>highestLongTermPing ){
                highestLongTermPing = avePingTime;
                highestSource = sources[i];
            }

            //is this a new lowest value?
            if( avePingTime<lowestLongTermPing ){
                lowestLongTermPing = avePingTime;
            }
        }//for

        boolean removedSource = false;
        //if the highest value is 8x the lowest then find another source.
        if( lowestLongTermPing*8 < highestLongTermPing ){
            //remove the slow source we will get a new one to replace it.
            if( highestSource!=null ){
                SpeedManagerLogger.log("dropping ping source: "+highestSource.getAddress()+" for being 8x greater then min source.");
                highestSource.destroy();
                removedSource = true;
                resetTimer();
            }
        }//if

        return removedSource;
    
private booleancheckForSlowSource(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource[] sources)
A slow source is something that is 2x the slower then the two fastest.

param
sources -
return
- true is a source has been removed.


        //We only apply this rule if nothing has been removed in the past 15 minutes.
        long currTime = SystemTime.getCurrentTime();
        if( currTime<lastPingRemoval+ TIME_BETWEEN_SLOW_PING_REMOVALS){
            return false;
        }

        SpeedManagerPingSource slowestSource = null;
        if( sources.length<3 ){
            return false;
        }

        double fastA = 10000.0;
        double fastB = 10000.0;
        double slowest = 0.0;
        int len = sources.length;
        for(int i=0; i<len; i++){
            PingSourceStats pss = (PingSourceStats) pingAverages.get(sources[i]);
            Average ave = pss.getHistory();
            double pingTime = ave.getAverage();

            //determine fastest or second fastest.
            if(pingTime<fastA){
                fastB=fastA;
                fastA=pingTime;
            }else if(pingTime<fastB){
                fastB=pingTime;
            }

            //determine slowest.
            if(pingTime>slowest){
                slowest = pingTime;
                slowestSource = sources[i];
                resetTimer();
            }
        }//for

        double sumFastest = fastA+fastB;

        boolean removedSource = false;
        if( sumFastest*2 < slowest ){
            //destroy this source. It is a bit too slow.
            if(slowestSource!=null){
                slowestSource.destroy();
                SpeedManagerLogger.log("dropping ping source: "+slowestSource.getAddress()+" for being 2x slower then two fastest.");
                removedSource = true;
                resetTimer();
            }
        }//if

        return removedSource;
    
public voidcheckPingSources(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource[] sources)
Determine if we should drop any ping sources. Sort them, if one significantly higher then the other two. then drop it.

param
sources - SpeedManagerPingSource[] inputs

// thirty minutes.


                                   
       

        //if the long term average of one source is 10 the lowest and twice a large as the
        //two lowest then drop the highest at the moment. Also, don't force sources to
        //drop to frequently.

        //no sources.
        if( sources==null ){
            return;
        }

        //if we have only two sources then don't do this test.
        if( sources.length<3 ){
            return;
        }

        //Test for a very bad ping source. i.e. slowest source is 10x slower then the fastest,
        if( checkForBadPing(sources) ){
            return;
        }

        //Test for slower then average source. i.e. slowest source is 3x media.
        if( checkForSlowSource(sources) ){
            return;
        }

        //Even if everything is going well then force a change every 30 minutes.
        forcePingSourceChange(sources);

    
private booleanforcePingSourceChange(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource[] sources)
If one ping source is twice the fastest then replace it. Otherwise reset the timer.

param
sources -
return
- true is a souce has been changed.


        //We only apply this rule if nothing has been removed in the past 30 minutes.
        long currTime = SystemTime.getCurrentTime();
        if( currTime<lastPingRemoval+ TIME_BETWEEN_FORCED_CYCLE_REMOVALS){
            return false;
        }

        if(sources.length<3){
            return false;
        }

        //just find the slowest ping-source and remove it.
        SpeedManagerPingSource slowestSource = null;
        double slowestPing = 0.0;
        double fastestPing = 10000.0;

        int len = sources.length;
        for(int i=0; i<len; i++){
            PingSourceStats pss = (PingSourceStats) pingAverages.get(sources[i]);
            Average ave = pss.getHistory();
            double pingTime = ave.getAverage();

            //find slowest
            if( pingTime>slowestPing ){
                slowestPing = pingTime;
                slowestSource=sources[i];
            }

            //find sped of fastest.
            if( pingTime<fastestPing ){
                fastestPing = pingTime;
            }

        }//for

        //regardless of result, resetTimer the timer.
        resetTimer();
        //only replace the slowest if it is twice the fastest.
        if( slowestPing > 2*fastestPing ){
            if(slowestSource!=null){
                slowestSource.destroy();
                return true;
            }
        }

        return false;
    
public voidpingSourceFailed(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource source)

        if( pingAverages.remove(source)==null){
            SpeedManagerLogger.log("didn't find source: "+source.getAddress().getHostName());
        }
    
public voidpingSourceFound(com.aelitis.azureus.core.speedmanager.SpeedManagerPingSource source, boolean is_replacement)

        PingSourceStats pss = new PingSourceStats(source);
        pingAverages.put(source,pss);
    
private voidresetTimer()
After a ping-source has been removed, need to resetTimer the timer.

        lastPingRemoval = SystemTime.getCurrentTime();