package com.limegroup.gnutella.downloader; import java.util.Comparator; import com.google.inject.Singleton; import com.limegroup.gnutella.PushEndpoint; /** * A RemoteFileDesc comparator for use with head pings. The comparator * uses five criteria to rank sources: * 1) Whether the source replied to a multicast query * 2) The source's queue status * 3) Whether the source is firewalled * 4) Whether the source has the complete file * 5) The round-trip time of the head ping */ @Singleton class PingedRemoteFileDescComparator implements Comparator<RemoteFileDescContext> { private static boolean isFirewalled(RemoteFileDescContext rfdContext) { return rfdContext.getAddress() instanceof PushEndpoint; } public int compare(RemoteFileDescContext pongA, RemoteFileDescContext pongB) { // Multicasts are best if(pongA.isReplyToMulticast() != pongB.isReplyToMulticast()) { if(pongA.isReplyToMulticast()) return -1; else return 1; } // Prefer sources with free slots (or at least short queues) if(pongA.getQueueStatus() > pongB.getQueueStatus()) return 1; else if(pongA.getQueueStatus() < pongB.getQueueStatus()) return -1; // Prefer firewalled sources - this is designed to balance load by // leaving non-firewalled sources for those who need them if(isFirewalled(pongA) != isFirewalled(pongB)) { if(isFirewalled(pongA)) return -1; else return 1; } // Prefer partial sources - this is designed to balance load by // leaving complete sources for those who need them if(pongA.isPartialSource() != pongB.isPartialSource()) { if(pongA.isPartialSource()) return -1; else return 1; } // Prefer nearby sources (low round-trip time) if(pongA.getRoundTripTime() > pongB.getRoundTripTime()) return 1; else if(pongA.getRoundTripTime() < pongB.getRoundTripTime()) return -1; // No preference return pongA.hashCode() - pongB.hashCode(); } }