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.RemoteFileDesc; /** * A ranker which uses the legacy logic for selecting from available sources. */ public class LegacyRanker extends AbstractSourceRanker { private static final Log LOG = LogFactory.getLog(LegacyRanker.class); private final Set<RemoteFileDescContext> rfds; public LegacyRanker() { rfds = new HashSet<RemoteFileDescContext>(); } @Override public synchronized boolean addToPool(RemoteFileDescContext host) { if (LOG.isDebugEnabled()) LOG.debug("adding host " + host + " to be ranked", new Exception()); 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. * * @return the best file/endpoint location */ @Override public synchronized RemoteFileDescContext getBest() { if (!hasMore()) return null; RemoteFileDescContext ret = getBest(rfds.iterator()); // The best rfd found so far boolean removed = rfds.remove(ret); assert removed : "unable to remove RFD."; if (LOG.isDebugEnabled()) LOG.debug("the best we came with is " + ret); return ret; } static RemoteFileDescContext getBest(Iterator<RemoteFileDescContext> iter) { RemoteFileDescContext currentRfdContext = 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()) { // define in loop to reflect current selection of ret RemoteFileDesc currentRfd = currentRfdContext.getRemoteFileDesc(); RemoteFileDescContext potentialRfdContext = iter.next(); RemoteFileDesc potentialRfd = potentialRfdContext.getRemoteFileDesc(); // 1. if (potentialRfdContext.isBusy(now)) { continue; } if (currentRfdContext.isBusy(now)) { currentRfdContext = potentialRfdContext; } // 2. else if (potentialRfd.getSHA1Urn() != null && currentRfd.getSHA1Urn() == null) { currentRfdContext = potentialRfdContext; } // (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 ((potentialRfd.getSHA1Urn() == null) == (currentRfd.getSHA1Urn() == null)) { // 3. if (potentialRfd.getQuality() > currentRfd.getQuality()) { currentRfdContext = potentialRfdContext; } else if (potentialRfd.getQuality() == currentRfd.getQuality()) { // 4. if (potentialRfd.getSpeed() > currentRfd.getSpeed()) { currentRfdContext = potentialRfdContext; } } } } return currentRfdContext; } @Override public boolean hasMore() { return !rfds.isEmpty(); } @Override public Collection<RemoteFileDescContext> getShareableHosts() { return rfds; } @Override protected Collection<RemoteFileDescContext> getPotentiallyBusyHosts() { return rfds; } @Override public int getNumKnownHosts() { return rfds.size(); } }