package com.limegroup.gnutella.downloader;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.limegroup.gnutella.Assert;
import com.limegroup.gnutella.RemoteFileDesc;
/**
* A ranker which uses the legacy logic for selecting from available
* sources.
*/
public class LegacyRanker extends SourceRanker {
private static final Log LOG = LogFactory.getLog(LegacyRanker.class);
private final Set rfds;
public LegacyRanker() {
rfds = new HashSet();
}
public synchronized boolean addToPool(RemoteFileDesc host) {
if (LOG.isDebugEnabled())
LOG.debug("adding host "+host+" to be ranked");
return rfds.add(host);
}
/**
* Removes and returns the RemoteFileDesc with the highest quality in
* filesLeft. If two or more entries have the same quality, returns the
* entry with the highest speed.
*
* @param filesLeft the list of file/locations to choose from, which MUST
* have length of at least one. Each entry MUST be an instance of
* RemoteFileDesc. The assumption is that all are "same", though this
* isn't strictly needed.
* @return the best file/endpoint location
*/
public synchronized RemoteFileDesc getBest() {
if (!hasMore())
return null;
RemoteFileDesc ret = getBest(rfds.iterator());
//The best rfd found so far
boolean removed = rfds.remove(ret);
Assert.that(removed == true, "unable to remove RFD.");
if (LOG.isDebugEnabled())
LOG.debug("the best we came with is "+ret);
return ret;
}
static RemoteFileDesc getBest(Iterator iter) {
RemoteFileDesc ret=(RemoteFileDesc)iter.next();
long now = System.currentTimeMillis();
//Find max of each (remaining) element, storing in max.
//Follows the following logic:
//1) Find a non-busy host (make connections)
//2) Find a host that uses hashes (avoid corruptions)
//3) Find a better quality host (avoid dud locations)
//4) Find a speedier host (avoid slow downloads)
while (iter.hasNext()) {
RemoteFileDesc rfd=(RemoteFileDesc)iter.next();
// 1.
if (rfd.isBusy(now))
continue;
if (ret.isBusy(now))
ret=rfd;
// 2.
else if (rfd.getSHA1Urn()!=null && ret.getSHA1Urn()==null)
ret=rfd;
// 3 & 4.
// (note the use of == so that the comparison is only done
// if both rfd & ret either had or didn't have a SHA1)
else if ((rfd.getSHA1Urn()==null) == (ret.getSHA1Urn()==null)) {
// 3.
if (rfd.getQuality() > ret.getQuality())
ret=rfd;
else if (rfd.getQuality() == ret.getQuality()) {
// 4.
if (rfd.getSpeed() > ret.getSpeed())
ret=rfd;
}
}
}
return ret;
}
public boolean hasMore() {
return !rfds.isEmpty();
}
protected Collection getShareableHosts() {
return rfds;
}
protected Collection getPotentiallyBusyHosts() {
return rfds;
}
public int getNumKnownHosts() {
return rfds.size();
}
}