From 05e2da7c2257a9c420c775566a403e8aaf7e10a8 Mon Sep 17 00:00:00 2001
From: ragnarok <ragnarok>
Date: Thu, 20 Oct 2005 22:05:51 +0000
Subject: [PATCH] Request pieces in rarest-first order, instead of randomly.

---
 .../src/org/klomp/snark/PeerCoordinator.java  | 55 +++++++++++--------
 .../java/src/org/klomp/snark/Piece.java       | 35 ++++++++++++
 2 files changed, 68 insertions(+), 22 deletions(-)
 create mode 100644 apps/i2psnark/java/src/org/klomp/snark/Piece.java

diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java
index 3fb39ce96b..ce4a0658ac 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java
@@ -69,13 +69,12 @@ public class PeerCoordinator implements PeerListener
     this.storage = storage;
     this.listener = listener;
 
-    // Make a random list of piece numbers
+    // Make a list of pieces
     wantedPieces = new ArrayList();
     BitField bitfield = storage.getBitField();
     for(int i = 0; i < metainfo.getPieces(); i++)
       if (!bitfield.get(i))
-        wantedPieces.add(new Integer(i));
-    Collections.shuffle(wantedPieces);
+        wantedPieces.add(new Piece(i));
 
     // Install a timer to check the uploaders.
     timer.schedule(new PeerCheckerTask(this), CHECK_PERIOD, CHECK_PERIOD);
@@ -288,7 +287,7 @@ public class PeerCoordinator implements PeerListener
 
     synchronized(wantedPieces)
       {
-        return wantedPieces.contains(new Integer(piece));
+        return wantedPieces.contains(new Piece(piece));
       }
   }
 
@@ -306,8 +305,10 @@ public class PeerCoordinator implements PeerListener
         Iterator it = wantedPieces.iterator();
         while (it.hasNext())
           {
-            int i = ((Integer)it.next()).intValue();
+            Piece p = (Piece)it.next();
+            int i = p.getId();
             if (bitfield.get(i))
+              p.addPeer(peer);
               return true;
           }
       }
@@ -325,28 +326,38 @@ public class PeerCoordinator implements PeerListener
 
     synchronized(wantedPieces)
       {
-        Integer piece = null;
+        Piece piece = null;
+        Collections.sort(wantedPieces); // Sort in order of rarest first.
+        List requested = new ArrayList(); 
         Iterator it = wantedPieces.iterator();
         while (piece == null && it.hasNext())
           {
-            Integer i = (Integer)it.next();
-            if (havePieces.get(i.intValue()))
+            Piece p = (Piece)it.next();
+            if (havePieces.get(p.getId()) && !p.isRequested())
               {
-                it.remove();
-                piece = i;
+                piece = p;
               }
+            else if (p.isRequested()) 
+            {
+                requested.add(p);
+            }
           }
-
-        if (piece == null)
-          return -1;
-
-        // We add it back at the back of the list. It will be removed
-        // if gotPiece is called later. This means that the last
-        // couple of pieces might very well be asked from multiple
-        // peers but that is OK.
-        wantedPieces.add(piece);
-
-        return piece.intValue();
+        
+        //Only request a piece we've requested before if there's no other choice.
+        if (piece == null) {
+            Iterator it2 = requested.iterator();
+            while (piece == null && it2.hasNext())
+              {
+                Piece p = (Piece)it2.next();
+                if (havePieces.get(p.getId()))
+                  {
+                    piece = p;
+                  }
+              }
+            if (piece == null) return -1; //If we still can't find a piece we want, so be it.
+        }
+        piece.setRequested(true);
+        return piece.getId();
       }
   }
 
@@ -404,7 +415,7 @@ public class PeerCoordinator implements PeerListener
     
     synchronized(wantedPieces)
       {
-        Integer p = new Integer(piece);
+        Piece p = new Piece(piece);
         if (!wantedPieces.contains(p))
           {
             if (Snark.debug >= Snark.INFO)
diff --git a/apps/i2psnark/java/src/org/klomp/snark/Piece.java b/apps/i2psnark/java/src/org/klomp/snark/Piece.java
new file mode 100644
index 0000000000..d98421b992
--- /dev/null
+++ b/apps/i2psnark/java/src/org/klomp/snark/Piece.java
@@ -0,0 +1,35 @@
+package org.klomp.snark;
+
+import java.util.Set;
+import java.util.HashSet;
+
+public class Piece implements Comparable {
+
+    private int id;
+    private Set peers;
+    private boolean requested;
+    
+    public Piece(int id) {
+        this.id = id;
+        this.peers = new HashSet();
+    }
+    
+    public int compareTo(Object o) throws ClassCastException {
+        return this.peers.size() - ((Piece)o).peers.size();
+    }
+    
+    public boolean equals(Object o) {
+        if (o == null) return false;
+        try {
+            return this.id == ((Piece)o).id;
+        } catch (ClassCastException cce) {
+            return false;
+        }
+    }
+    
+    public int getId() { return this.id; }
+    public Set getPeers() { return this.peers; }
+    public boolean addPeer(Peer peer) { return this.peers.add(peer.getPeerID()); }
+    public boolean isRequested() { return this.requested; }
+    public void setRequested(boolean requested) { this.requested = requested; } 
+}
-- 
GitLab