Changeset 6ca4b51


Ignore:
Timestamp:
May 19, 2012 1:27:02 PM (8 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
9cff4d5
Parents:
3685bf0
Message:
  • i2psnark:
    • Store received chunks in temp files
    • Don't allocate from heap for unneeded chunks
    • Remove peer count restriction for torrents with large pieces
    • Use priorities and rarest calculations to sort partials
    • Preserve p parameter in clear messages link
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java

    r3685bf0 r6ca4b51  
    184184    /** @since 0.8.9 */
    185185    public void setFilesPublic(boolean yes) { _areFilesPublic = yes; }
     186
     187    /** @since 0.9.1 */
     188    public File getTempDir() { return _tmpDir; }
    186189
    187190    /**
  • apps/i2psnark/java/src/org/klomp/snark/MetaInfo.java

    r3685bf0 r6ca4b51  
    423423    return true;
    424424  }
     425 
     426  /**
     427   *  @since 0.9.1
     428   */
     429  boolean checkPiece(PartialPiece pp) throws IOException {
     430    MessageDigest sha1 = SHA1.getInstance();
     431    int piece = pp.getPiece();
     432
     433    byte[] hash = pp.getHash();
     434    for (int i = 0; i < 20; i++)
     435      if (hash[i] != piece_hashes[20 * piece + i])
     436        return false;
     437    return true;
     438  }
    425439
    426440  /**
  • apps/i2psnark/java/src/org/klomp/snark/PartialPiece.java

    r3685bf0 r6ca4b51  
    11package org.klomp.snark;
    22
     3import java.io.DataInputStream;
     4import java.io.DataOutput;
     5import java.io.File;
     6import java.io.IOException;
     7import java.io.RandomAccessFile;
     8import java.security.MessageDigest;
     9
     10import net.i2p.I2PAppContext;
     11import net.i2p.crypto.SHA1;
     12import net.i2p.util.Log;
     13import net.i2p.util.SecureFile;
     14
    315/**
     16 * Store the received data either on the heap or in a temp file.
     17 * The third option, to write chunks directly to the destination file,
     18 * is unimplemented.
     19 *
    420 * This is the class passed from PeerCoordinator to PeerState so
    521 * PeerState may start requests.
     
    925 * when the Peer disconnects or chokes.
    1026 *
     27 * New objects for the same piece are created during the end game -
     28 * this object should not be shared among multiple peers.
     29 *
    1130 * @since 0.8.2
    1231 */
    1332class PartialPiece implements Comparable {
    1433
    15     private final int piece;
     34    // we store the piece so we can use it in compareTo()
     35    private final Piece piece;
     36    // null if using temp file
    1637    private final byte[] bs;
    17     private final int off;
    18     private final long createdTime;
     38    private int off;
     39    //private final long createdTime;
     40    private File tempfile;
     41    private RandomAccessFile raf;
     42    private final int pclen;
     43    private final File tempDir;
     44
     45    // Any bigger than this, use temp file instead of heap
     46    private static final int MAX_IN_MEM = 128 * 1024;
     47    // May be reduced on OOM
     48    private static int _max_in_mem = MAX_IN_MEM;
    1949
    2050    /**
    2151     * Used by PeerCoordinator.
    2252     * Creates a new PartialPiece, with no chunks yet downloaded.
    23      * Allocates the data.
     53     * Allocates the data storage area, either on the heap or in the
     54     * temp directory, depending on size.
    2455     *
    2556     * @param piece Piece number requested.
    2657     * @param len must be equal to the piece length
    2758     */
    28     public PartialPiece (int piece, int len) throws OutOfMemoryError {
     59    public PartialPiece (Piece piece, int len, File tempDir) {
    2960        this.piece = piece;
    30         this.bs = new byte[len];
    31         this.off = 0;
    32         this.createdTime = 0;
    33     }
    34 
    35     /**
    36      * Used by PeerState.
    37      * Creates a new PartialPiece, with chunks up to but not including
    38      * firstOutstandingRequest already downloaded and stored in the Request byte array.
    39      *
    40      * Note that this cannot handle gaps; chunks after a missing chunk cannot be saved.
    41      * That would be harder.
    42      *
    43      * @param firstOutstandingRequest the first request not fulfilled for the piece
    44      */
    45     public PartialPiece (Request firstOutstandingRequest) {
    46         this.piece = firstOutstandingRequest.piece;
    47         this.bs = firstOutstandingRequest.bs;
    48         this.off = firstOutstandingRequest.off;
    49         this.createdTime = System.currentTimeMillis();
     61        this.pclen = len;
     62        //this.createdTime = 0;
     63        this.tempDir = tempDir;
     64
     65        // temps for finals
     66        byte[] tbs = null;
     67        try {
     68            if (len <= MAX_IN_MEM) {
     69                try {
     70                    tbs = new byte[len];
     71                    return;
     72                } catch (OutOfMemoryError oom) {
     73                    if (_max_in_mem > PeerState.PARTSIZE)
     74                        _max_in_mem /= 2;
     75                    Log log = I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class);
     76                    log.logAlways(Log.WARN, "OOM creating new partial piece");
     77                    // fall through to use temp file
     78                }
     79            }
     80            // delay creating temp file until required in read()
     81        } finally {
     82            // finals
     83            this.bs = tbs;
     84        }
     85    }
     86
     87    /**
     88     *  Caller must synchronize
     89     *
     90     *  @since 0.9.1
     91     */
     92    private void createTemp() throws IOException {
     93        //tfile = SecureFile.createTempFile("piece", null, tempDir);
     94        // debug
     95        tempfile = SecureFile.createTempFile("piece_" + piece.getId() + '_', null, tempDir);
     96        //I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn("Created " + tempfile);
     97        // tfile.deleteOnExit() ???
     98        raf = new RandomAccessFile(tempfile, "rw");
     99        // Do not preallocate the file space.
     100        // Not necessary to call setLength(), file is extended when written
     101        //traf.setLength(len);
    50102    }
    51103
     
    56108
    57109    public Request getRequest() {
    58         return new Request(this.piece, this.bs, this.off, Math.min(this.bs.length - this.off, PeerState.PARTSIZE));
     110        return new Request(this, this.off, Math.min(this.pclen - this.off, PeerState.PARTSIZE));
    59111    }
    60112
    61113    /** piece number */
    62114    public int getPiece() {
    63          return this.piece;
    64     }
    65 
    66     /** how many bytes are good */
     115         return this.piece.getId();
     116    }
     117
     118    /**
     119     *  @since 0.9.1
     120     */
     121    public int getLength() {
     122         return this.pclen;
     123    }
     124
     125    /**
     126     *  How many bytes are good - only valid by setDownloaded()
     127     */
    67128    public int getDownloaded() {
    68129         return this.off;
    69130    }
    70131
     132    /**
     133     *  Call this before returning a PartialPiece to the PeerCoordinator
     134     *  @since 0.9.1
     135     */
     136    public void setDownloaded(int offset) {
     137         this.off = offset;
     138    }
     139
     140/****
    71141    public long getCreated() {
    72142         return this.createdTime;
    73143    }
    74 
    75     /**
    76      *  Highest downloaded first
     144****/
     145
     146    /**
     147     *  Piece must be complete.
     148     *  The SHA1 hash of the completely read data.
     149     *  @since 0.9.1
     150     */
     151    public byte[] getHash() throws IOException {
     152        MessageDigest sha1 = SHA1.getInstance();
     153        if (bs != null) {
     154            sha1.update(bs);
     155        } else {
     156            int read = 0;
     157            byte[] buf = new byte[Math.min(pclen, 16384)];
     158            synchronized (this) {
     159                if (raf == null)
     160                    throw new IOException();
     161                raf.seek(0);
     162                while (read < pclen) {
     163                    int rd = raf.read(buf, 0, Math.min(buf.length, pclen - read));
     164                    if (rd < 0)
     165                        break;
     166                    read += rd;
     167                    sha1.update(buf, 0, rd);
     168                }
     169            }
     170            if (read < pclen)
     171                throw new IOException();
     172        }
     173        return sha1.digest();
     174    }
     175   
     176    /**
     177     *  Blocking.
     178     *  @since 0.9.1
     179     */
     180    public void read(DataInputStream din, int off, int len) throws IOException {
     181        if (bs != null) {
     182            din.readFully(bs, off, len);
     183        } else {
     184            // read in fully before synching on raf
     185            byte[] tmp = new byte[len];
     186            din.readFully(tmp);
     187            synchronized (this) {
     188                if (raf == null)
     189                    createTemp();
     190                raf.seek(off);
     191                raf.write(tmp);
     192            }
     193        }
     194    }
     195
     196    /**
     197     *  Piece must be complete.
     198     *  Caller must synchronize on out and seek to starting point.
     199     *  Caller must call release() when done with the whole piece.
     200     *
     201     *  @param start offset in the output file
     202     *  @param offset offset in the piece
     203     *  @param len length to write
     204     *  @since 0.9.1
     205     */
     206    public void write(DataOutput out, int offset, int len) throws IOException {
     207        if (bs != null) {
     208            out.write(bs, offset, len);
     209        } else {
     210            int read = 0;
     211            byte[] buf = new byte[Math.min(len, 16384)];
     212            synchronized (this) {
     213                if (raf == null)
     214                    throw new IOException();
     215                raf.seek(offset);
     216                while (read < len) {
     217                    int rd = Math.min(buf.length, len - read);
     218                    raf.readFully(buf, 0, rd);
     219                    read += rd;
     220                    out.write(buf, 0, rd);
     221                }
     222            }
     223        }
     224    }
     225   
     226    /**
     227     *  Release all resources.
     228     *
     229     *  @since 0.9.1
     230     */
     231    public void release() {
     232        if (bs == null) {
     233            synchronized (this) {
     234                if (raf != null)
     235                    locked_release();
     236            }
     237            //if (raf != null)
     238            //    I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn("Released " + tempfile);
     239        }
     240    }
     241   
     242    /**
     243     *  Caller must synchronize
     244     *
     245     *  @since 0.9.1
     246     */
     247    private void locked_release() {
     248        try {
     249            raf.close();
     250        } catch (IOException ioe) {
     251            I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn("Error closing " + raf, ioe);
     252        }
     253        tempfile.delete();
     254    }
     255
     256    /*
     257     *  Highest priority first,
     258     *  then rarest first,
     259     *  then highest downloaded first
    77260     */
    78261    public int compareTo(Object o) throws ClassCastException {
    79         return ((PartialPiece)o).off - this.off;  // reverse
     262        PartialPiece opp = (PartialPiece)o;
     263        int d = this.piece.compareTo(opp.piece);
     264        if (d != 0)
     265            return d;
     266        return opp.off - this.off;  // reverse
    80267    }
    81268   
    82269    @Override
    83270    public int hashCode() {
    84         return piece * 7777;
     271        return piece.getId() * 7777;
    85272    }
    86273
     
    93280        if (o instanceof PartialPiece) {
    94281            PartialPiece pp = (PartialPiece)o;
    95             return pp.piece == this.piece;
     282            return pp.piece.getId() == this.piece.getId();
    96283        }
    97284        return false;
     
    100287    @Override
    101288    public String toString() {
    102         return "Partial(" + piece + ',' + off + ',' + bs.length + ')';
     289        return "Partial(" + piece.getId() + ',' + off + ',' + pclen + ')';
    103290    }
    104291}
  • apps/i2psnark/java/src/org/klomp/snark/Peer.java

    r3685bf0 r6ca4b51  
    461461          PeerListener p = s.listener;
    462462          if (p != null) {
    463             List<PartialPiece> pcs = s.returnPartialPieces();
     463            List<Request> pcs = s.returnPartialPieces();
    464464            if (!pcs.isEmpty())
    465465                p.savePartialPieces(this, pcs);
  • apps/i2psnark/java/src/org/klomp/snark/PeerConnectionIn.java

    r3685bf0 r6ca4b51  
    149149                len = i-9;
    150150                Request req = ps.getOutstandingRequest(piece, begin, len);
    151                 byte[] piece_bytes;
    152151                if (req != null)
    153152                  {
    154                     piece_bytes = req.bs;
    155                     din.readFully(piece_bytes, begin, len);
     153                    req.read(din);
    156154                    ps.pieceMessage(req);
    157155                    if (_log.shouldLog(Log.DEBUG))
     
    161159                  {
    162160                    // XXX - Consume but throw away afterwards.
    163                     piece_bytes = new byte[len];
    164                     din.readFully(piece_bytes);
     161                    int rcvd = din.skipBytes(len);
     162                    if (rcvd != len)
     163                        throw new IOException("EOF reading unwanted data");
    165164                    if (_log.shouldLog(Log.DEBUG))
    166165                        _log.debug("Received UNWANTED data(" + piece + "," + begin + ") from " + peer);
  • apps/i2psnark/java/src/org/klomp/snark/PeerConnectionOut.java

    r3685bf0 r6ca4b51  
    396396          {
    397397            Message m = (Message)it.next();
    398             if (m.type == Message.REQUEST && m.piece == req.piece &&
     398            if (m.type == Message.REQUEST && m.piece == req.getPiece() &&
    399399                m.begin == req.off && m.length == req.len)
    400400              {
     
    407407    Message m = new Message();
    408408    m.type = Message.REQUEST;
    409     m.piece = req.piece;
     409    m.piece = req.getPiece();
    410410    m.begin = req.off;
    411411    m.length = req.len;
     
    493493            Message m = (Message)it.next();
    494494            if (m.type == Message.REQUEST
    495                 && m.piece == req.piece
     495                && m.piece == req.getPiece()
    496496                && m.begin == req.off
    497497                && m.length == req.len)
     
    503503    Message m = new Message();
    504504    m.type = Message.CANCEL;
    505     m.piece = req.piece;
     505    m.piece = req.getPiece();
    506506    m.begin = req.off;
    507507    m.length = req.len;
  • apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java

    r3685bf0 r6ca4b51  
    117117  private final List<Piece> wantedPieces;
    118118
    119   /** partial pieces - lock by synching on wantedPieces */
     119  /** partial pieces - lock by synching on wantedPieces - TODO store Requests, not PartialPieces */
    120120  private final List<PartialPiece> partialPieces;
    121121
     
    350350    int size = metainfo.getPieceLength(0);
    351351    int max = _util.getMaxConnections();
    352     if (size <= 512*1024 || completed())
     352    // Now that we use temp files, no memory concern
     353    //if (size <= 512*1024 || completed())
    353354      return max;
    354     if (size <= 1024*1024)
    355       return (max + max + 2) / 3;
    356     return (max + 2) / 3;
     355    //if (size <= 1024*1024)
     356    //  return (max + max + 2) / 3;
     357    //return (max + 2) / 3;
    357358  }
    358359
     
    381382    // delete any saved orphan partial piece
    382383    synchronized (partialPieces) {
     384        for (PartialPiece pp : partialPieces) {
     385            pp.release();
     386        }
    383387        partialPieces.clear();
    384388    }
     
    631635   */
    632636  public int wantPiece(Peer peer, BitField havePieces) {
    633       return wantPiece(peer, havePieces, true);
     637      Piece pc = wantPiece(peer, havePieces, true);
     638      return pc != null ? pc.getId() : -1;
    634639  }
    635640
    636641  /**
    637642   * Returns one of pieces in the given BitField that is still wanted or
    638    * -1 if none of the given pieces are wanted.
     643   * null if none of the given pieces are wanted.
    639644   *
    640645   * @param record if true, actually record in our data structures that we gave the
     
    642647   * @since 0.8.2
    643648   */
    644   private int wantPiece(Peer peer, BitField havePieces, boolean record) {
     649  private Piece wantPiece(Peer peer, BitField havePieces, boolean record) {
    645650    if (halted) {
    646651      if (_log.shouldLog(Log.WARN))
    647652          _log.warn("We don't want anything from the peer, as we are halted!  peer=" + peer);
    648       return -1;
     653      return null;
    649654    }
    650655
     
    681686            // when the seeder is super-slow and all the peers are "caught up"
    682687            if (wantedSize > END_GAME_THRESHOLD)
    683                 return -1;  // nothing to request and not in end game
     688                return null;  // nothing to request and not in end game
    684689            // let's not all get on the same piece
    685690            // Even better would be to sort by number of requests
     
    705710                //  _log.warn("nothing to even rerequest from " + peer + ": requested = " + requested
    706711                //            + " wanted = " + wantedPieces + " peerHas = " + havePieces);
    707                 return -1; //If we still can't find a piece we want, so be it.
     712                return null; //If we still can't find a piece we want, so be it.
    708713            } else {
    709714                // Should be a lot smarter here -
     
    720725            piece.setRequested(peer, true);
    721726        }
    722         return piece.getId();
     727        return piece;
    723728      } // synch
    724729  }
     
    847852   * @throws RuntimeException on IOE saving the piece
    848853   */
    849   public boolean gotPiece(Peer peer, int piece, byte[] bs)
     854  public boolean gotPiece(Peer peer, PartialPiece pp)
    850855  {
    851856    if (metainfo == null || storage == null)
    852857        return true;
     858    int piece = pp.getPiece();
    853859    if (halted) {
    854860      _log.info("Got while-halted piece " + piece + "/" + metainfo.getPieces() +" from " + peer + " for " + metainfo.getName());
     
    873879        try
    874880          {
    875             if (storage.putPiece(piece, bs))
     881            if (storage.putPiece(pp))
    876882              {
    877883                if (_log.shouldLog(Log.INFO))
     
    923929          }
    924930   
     931    if (completed()) {
     932        synchronized (partialPieces) {
     933            for (PartialPiece ppp : partialPieces) {
     934                ppp.release();
     935            }
     936            partialPieces.clear();
     937        }
     938    }
     939
    925940    return true;
    926941  }
     
    9991014   *
    10001015   *  @param peer partials, must include the zero-offset (empty) ones too
     1016   *              No dup pieces, piece.setDownloaded() must be set
    10011017   *  @since 0.8.2
    10021018   */
    1003   public void savePartialPieces(Peer peer, List<PartialPiece> partials)
    1004   {
    1005       if (halted)
    1006           return;
     1019  public void savePartialPieces(Peer peer, List<Request> partials)
     1020  {
    10071021      if (_log.shouldLog(Log.INFO))
    10081022          _log.info("Partials received from " + peer + ": " + partials);
     1023      if (halted || completed()) {
     1024          for (Request req : partials) {
     1025              PartialPiece pp = req.getPartialPiece();
     1026              pp.release();
     1027          }
     1028          return;
     1029      }
    10091030      synchronized(wantedPieces) {
    1010           for (PartialPiece pp : partials) {
    1011               if (pp.getDownloaded() > 0) {
     1031          for (Request req : partials) {
     1032              PartialPiece pp = req.getPartialPiece();
     1033              if (req.off > 0) {
    10121034                  // PartialPiece.equals() only compares piece number, which is what we want
    10131035                  int idx = partialPieces.indexOf(pp);
     
    10181040                  } else if (idx >= 0 && pp.getDownloaded() > partialPieces.get(idx).getDownloaded()) {
    10191041                      // replace what's there now
     1042                      partialPieces.get(idx).release();
    10201043                      partialPieces.set(idx, pp);
    10211044                      if (_log.shouldLog(Log.INFO))
    10221045                          _log.info("Saving orphaned partial piece (bigger) " + pp);
    10231046                  } else {
     1047                      pp.release();
    10241048                      if (_log.shouldLog(Log.INFO))
    10251049                          _log.info("Discarding partial piece (not bigger)" + pp);
     
    10301054                      Collections.sort(partialPieces);
    10311055                      PartialPiece gone = partialPieces.remove(max);
     1056                      gone.release();
    10321057                      if (_log.shouldLog(Log.INFO))
    10331058                          _log.info("Discarding orphaned partial piece (list full)" + gone);
    10341059                  }
    1035               }  // else drop the empty partial piece
     1060              } else {
     1061                  // drop the empty partial piece
     1062                  pp.release();
     1063              }
    10361064              // synchs on wantedPieces...
    10371065              markUnrequested(peer, pp.getPiece());
     
    10801108      // ...and this section turns this into the general move-requests-around code!
    10811109      // Temporary? So PeerState never calls wantPiece() directly for now...
    1082       int piece = wantPiece(peer, havePieces);
    1083       if (piece >= 0) {
    1084           try {
    1085               return new PartialPiece(piece, metainfo.getPieceLength(piece));
    1086           } catch (OutOfMemoryError oom) {
    1087               if (_log.shouldLog(Log.WARN))
    1088                   _log.warn("OOM creating new partial piece");
    1089           }
     1110      Piece piece = wantPiece(peer, havePieces, true);
     1111      if (piece != null) {
     1112          return new PartialPiece(piece, metainfo.getPieceLength(piece.getId()), _util.getTempDir());
    10901113      }
    10911114      if (_log.shouldLog(Log.DEBUG))
     
    11221145          }
    11231146      }
    1124       return wantPiece(peer, havePieces, false) >= 0;
     1147      return wantPiece(peer, havePieces, false) != null;
    11251148  }
    11261149
  • apps/i2psnark/java/src/org/klomp/snark/PeerListener.java

    r3685bf0 r6ca4b51  
    9696   *
    9797   * @param peer the Peer that got the piece.
    98    * @param piece the piece number received.
     98   * @param piece the piece received.
    9999   * @param bs the byte array containing the piece.
    100100   *
    101101   * @return true when the bytes represent the piece, false otherwise.
    102102   */
    103   boolean gotPiece(Peer peer, int piece, byte[] bs);
     103  boolean gotPiece(Peer peer, PartialPiece piece);
    104104
    105105  /**
     
    168168   * @since 0.8.2
    169169   */
    170   void savePartialPieces(Peer peer, List<PartialPiece> pcs);
     170  void savePartialPieces(Peer peer, List<Request> pcs);
    171171
    172172  /**
  • apps/i2psnark/java/src/org/klomp/snark/PeerState.java

    r3685bf0 r6ca4b51  
    108108        // is that chunks above a missing request are lost.
    109109        // Future enhancements to PartialPiece could keep track of the holes.
    110         List<PartialPiece> pcs = returnPartialPieces();
     110        List<Request> pcs = returnPartialPieces();
    111111        if (!pcs.isEmpty()) {
    112112            if (_log.shouldLog(Log.DEBUG))
     
    305305    if (_log.shouldLog(Log.DEBUG))
    306306      _log.debug("got end of Chunk("
    307                   + req.piece + "," + req.off + "," + req.len + ") from "
     307                  + req.getPiece() + "," + req.off + "," + req.len + ") from "
    308308                  + peer);
    309309
    310310    // Last chunk needed for this piece?
    311     if (getFirstOutstandingRequest(req.piece) == -1)
     311    if (getFirstOutstandingRequest(req.getPiece()) == -1)
    312312      {
    313313        // warning - may block here for a while
    314         if (listener.gotPiece(peer, req.piece, req.bs))
     314        if (listener.gotPiece(peer, req.getPartialPiece()))
    315315          {
    316316            if (_log.shouldLog(Log.DEBUG))
    317               _log.debug("Got " + req.piece + ": " + peer);
     317              _log.debug("Got " + req.getPiece() + ": " + peer);
    318318          }
    319319        else
    320320          {
    321321            if (_log.shouldLog(Log.WARN))
    322               _log.warn("Got BAD " + req.piece + " from " + peer);
     322              _log.warn("Got BAD " + req.getPiece() + " from " + peer);
    323323          }
    324324      }
     
    336336   {
    337337    for (int i = 0; i < outstandingRequests.size(); i++)
    338       if (outstandingRequests.get(i).piece == piece)
     338      if (outstandingRequests.get(i).getPiece() == piece)
    339339        return i;
    340340    return -1;
     
    372372      {
    373373        req = outstandingRequests.get(r);
    374         while (req.piece == piece && req.off != begin
     374        while (req.getPiece() == piece && req.off != begin
    375375               && r < outstandingRequests.size() - 1)
    376376          {
     
    380380       
    381381        // Something wrong?
    382         if (req.piece != piece || req.off != begin || req.len != length)
     382        if (req.getPiece() != piece || req.off != begin || req.len != length)
    383383          {
    384384            if (_log.shouldLog(Log.INFO))
     
    428428      int lowest = Integer.MAX_VALUE;
    429429      for (Request r :  outstandingRequests) {
    430           if (r.piece == piece && r.off < lowest) {
     430          if (r.getPiece() == piece && r.off < lowest) {
    431431              lowest = r.off;
    432432              rv = r;
     
    434434      }
    435435      if (pendingRequest != null &&
    436           pendingRequest.piece == piece && pendingRequest.off < lowest)
     436          pendingRequest.getPiece() == piece && pendingRequest.off < lowest)
    437437          rv = pendingRequest;
    438438
     
    448448   *  @since 0.8.2
    449449   */
    450   synchronized List<PartialPiece> returnPartialPieces()
     450  synchronized List<Request> returnPartialPieces()
    451451  {
    452452      Set<Integer> pcs = getRequestedPieces();
    453       List<PartialPiece> rv = new ArrayList(pcs.size());
     453      List<Request> rv = new ArrayList(pcs.size());
    454454      for (Integer p : pcs) {
    455455          Request req = getLowestOutstandingRequest(p.intValue());
    456           if (req != null)
    457               rv.add(new PartialPiece(req));
     456          if (req != null) {
     457              req.getPartialPiece().setDownloaded(req.off);
     458              rv.add(req);
     459          }
    458460      }
    459461      outstandingRequests.clear();
     
    469471      Set<Integer> rv = new HashSet(outstandingRequests.size() + 1);
    470472      for (Request req : outstandingRequests) {
    471           rv.add(Integer.valueOf(req.piece));
     473          rv.add(Integer.valueOf(req.getPiece()));
    472474      if (pendingRequest != null)
    473           rv.add(Integer.valueOf(pendingRequest.piece));
     475          rv.add(Integer.valueOf(pendingRequest.getPiece()));
    474476      }
    475477      return rv;
     
    572574   */
    573575  synchronized void cancelPiece(int piece) {
    574         if (lastRequest != null && lastRequest.piece == piece)
     576        if (lastRequest != null && lastRequest.getPiece() == piece)
    575577          lastRequest = null;
    576578       
     
    579581          {
    580582            Request req = it.next();
    581             if (req.piece == piece)
     583            if (req.getPiece() == piece)
    582584              {
    583585                it.remove();
     
    595597   */
    596598  synchronized boolean isRequesting(int piece) {
    597       if (pendingRequest != null && pendingRequest.piece == piece)
     599      if (pendingRequest != null && pendingRequest.getPiece() == piece)
    598600          return true;
    599601      for (Request req : outstandingRequests) {
    600           if (req.piece == piece)
     602          if (req.getPiece() == piece)
    601603              return true;
    602604      }
     
    680682            int pieceLength;
    681683            boolean isLastChunk;
    682             pieceLength = metainfo.getPieceLength(lastRequest.piece);
     684            pieceLength = metainfo.getPieceLength(lastRequest.getPiece());
    683685            isLastChunk = lastRequest.off + lastRequest.len == pieceLength;
    684686
     
    688690            else
    689691              {
    690                     int nextPiece = lastRequest.piece;
     692                    PartialPiece nextPiece = lastRequest.getPartialPiece();
    691693                    int nextBegin = lastRequest.off + PARTSIZE;
    692                     byte[] bs = lastRequest.bs;
    693694                    int maxLength = pieceLength - nextBegin;
    694695                    int nextLength = maxLength > PARTSIZE ? PARTSIZE
    695696                                                          : maxLength;
    696697                    Request req
    697                       = new Request(nextPiece, bs, nextBegin, nextLength);
     698                      = new Request(nextPiece,nextBegin, nextLength);
    698699                    outstandingRequests.add(req);
    699700                    if (!choked)
     
    741742        int nextPiece = listener.wantPiece(peer, bitfield);
    742743        if (nextPiece != -1
    743             && (lastRequest == null || lastRequest.piece != nextPiece)) {
     744            && (lastRequest == null || lastRequest.getPiece() != nextPiece)) {
    744745                if (_log.shouldLog(Log.DEBUG))
    745746                    _log.debug(peer + " want piece " + nextPiece);
  • apps/i2psnark/java/src/org/klomp/snark/Request.java

    r3685bf0 r6ca4b51  
    2121package org.klomp.snark;
    2222
     23import java.io.DataInputStream;
     24import java.io.IOException;
     25
    2326/**
    2427 * Holds all information needed for a partial piece request.
     
    2730class Request
    2831{
    29   final int piece;
    30   final byte[] bs;
     32  private final PartialPiece piece;
    3133  final int off;
    3234  final int len;
     
    3739   *
    3840   * @param piece Piece number requested.
    39    * @param bs byte array where response should be stored.
    4041   * @param off the offset in the array.
    4142   * @param len the number of bytes requested.
    4243   */
    43   Request(int piece, byte[] bs, int off, int len)
     44  Request(PartialPiece piece, int off, int len)
    4445  {
     46    // Sanity check
     47    if (off < 0 || len <= 0 || off + len > piece.getLength())
     48      throw new IndexOutOfBoundsException("Illegal Request " + toString());
     49
    4550    this.piece = piece;
    46     this.bs = bs;
    4751    this.off = off;
    4852    this.len = len;
     53  }
    4954
    50     // Sanity check
    51     if (piece < 0 || off < 0 || len <= 0 || off + len > bs.length)
    52       throw new IndexOutOfBoundsException("Illegal Request " + toString());
     55  /**
     56   *  @since 0.9.1
     57   */
     58  public void read(DataInputStream din) throws IOException {
     59      piece.read(din, off, len);
     60  }
     61
     62  /**
     63   *  The piece number this Request is for
     64   *
     65   *  @since 0.9.1
     66   */
     67  public int getPiece() {
     68      return piece.getPiece();
     69  }
     70
     71  /**
     72   *  The PartialPiece this Request is for
     73   *
     74   *  @since 0.9.1
     75   */
     76  public PartialPiece getPartialPiece() {
     77      return piece;
    5378  }
    5479
     
    5681  public int hashCode()
    5782  {
    58     return piece ^ off ^ len;
     83    return piece.getPiece() ^ off ^ len;
    5984  }
    6085
     
    6590      {
    6691        Request req = (Request)o;
    67         return req.piece == piece && req.off == off && req.len == len;
     92        return req.piece.equals(piece) && req.off == off && req.len == len;
    6893      }
    6994
     
    7499  public String toString()
    75100  {
    76     return "(" + piece + "," + off + "," + len + ")";
     101    return "(" + piece.getPiece() + "," + off + "," + len + ")";
    77102  }
    78103}
  • apps/i2psnark/java/src/org/klomp/snark/Snark.java

    r3685bf0 r6ca4b51  
    12151215    }
    12161216    long limit = 1024l * _util.getMaxUpBW();
    1217     debug("Total up bw: " + total + " Limit: " + limit, Snark.WARNING);
     1217    debug("Total up bw: " + total + " Limit: " + limit, Snark.NOTICE);
    12181218    return total > limit;
    12191219  }
  • apps/i2psnark/java/src/org/klomp/snark/Storage.java

    r3685bf0 r6ca4b51  
    874874   * @exception IOException when some storage related error occurs.
    875875   */
    876   public boolean putPiece(int piece, byte[] ba) throws IOException
    877   {
    878     // First check if the piece is correct.
    879     // Copy the array first to be paranoid.
    880     byte[] bs = ba.clone();
    881     int length = bs.length;
    882     boolean correctHash = metainfo.checkPiece(piece, bs, 0, length);
    883     if (listener != null)
    884       listener.storageChecked(this, piece, correctHash);
    885     if (!correctHash)
    886       return false;
    887 
    888     synchronized(bitfield)
    889       {
    890         if (bitfield.get(piece))
    891           return true; // No need to store twice.
    892       }
    893 
    894     // Early typecast, avoid possibly overflowing a temp integer
    895     long start = (long) piece * (long) piece_size;
    896     int i = 0;
    897     long raflen = lengths[i];
    898     while (start > raflen)
    899       {
    900         i++;
    901         start -= raflen;
    902         raflen = lengths[i];
    903       }
     876  public boolean putPiece(PartialPiece pp) throws IOException
     877  {
     878      int piece = pp.getPiece();
     879      try {
     880          synchronized(bitfield) {
     881              if (bitfield.get(piece))
     882                  return true; // No need to store twice.
     883          }
     884
     885          // TODO alternative - check hash on the fly as we write to the file,
     886          // to save another I/O pass
     887          boolean correctHash = metainfo.checkPiece(pp);
     888          if (listener != null)
     889            listener.storageChecked(this, piece, correctHash);
     890          if (!correctHash) {
     891              return false;
     892          }
     893
     894          // Early typecast, avoid possibly overflowing a temp integer
     895          long start = (long) piece * (long) piece_size;
     896          int i = 0;
     897          long raflen = lengths[i];
     898          while (start > raflen) {
     899              i++;
     900              start -= raflen;
     901              raflen = lengths[i];
     902          }
    904903   
    905     int written = 0;
    906     int off = 0;
    907     while (written < length)
    908       {
    909         int need = length - written;
    910         int len = (start + need < raflen) ? need : (int)(raflen - start);
    911         synchronized(RAFlock[i])
    912           {
    913             checkRAF(i);
    914             rafs[i].seek(start);
    915             rafs[i].write(bs, off + written, len);
    916           }
    917         written += len;
    918         if (need - len > 0)
    919           {
    920             i++;
    921             raflen = lengths[i];
    922             start = 0;
    923           }
     904          int written = 0;
     905          int off = 0;
     906          int length = metainfo.getPieceLength(piece);
     907          while (written < length) {
     908              int need = length - written;
     909              int len = (start + need < raflen) ? need : (int)(raflen - start);
     910              synchronized(RAFlock[i]) {
     911                  checkRAF(i);
     912                  rafs[i].seek(start);
     913                  //rafs[i].write(bs, off + written, len);
     914                  pp.write(rafs[i], off + written, len);
     915              }
     916              written += len;
     917              if (need - len > 0) {
     918                  i++;
     919                  raflen = lengths[i];
     920                  start = 0;
     921              }
     922          }
     923      } finally {
     924          pp.release();
    924925      }
    925926
  • apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java

    r3685bf0 r6ca4b51  
    151151        resp.setHeader("X-Frame-Options", "SAMEORIGIN");
    152152
     153        String peerParam = req.getParameter("p");
     154        String peerString;
     155        if (peerParam == null || (!_manager.util().connected()) ||
     156            peerParam.replaceAll("[a-zA-Z0-9~=-]", "").length() > 0) {  // XSS
     157            peerString = "";
     158        } else {
     159            peerString = "?p=" + peerParam;
     160        }
     161
    153162        // AJAX for mainsection
    154163        if ("/.ajax/xhr1.html".equals(path)) {
     
    158167            //if (_log.shouldLog(Log.DEBUG))
    159168            //    _manager.addMessage((_context.clock().now() / 1000) + " xhr1 p=" + req.getParameter("p"));
    160             writeMessages(out, false);
     169            writeMessages(out, false, peerString);
    161170            writeTorrents(out, req);
    162171            return;
     
    202211        }
    203212       
    204         String peerParam = req.getParameter("p");
    205         String peerString;
    206         if (peerParam == null || (!_manager.util().connected()) ||
    207             peerParam.replaceAll("[a-zA-Z0-9~=-]", "").length() > 0) {  // XSS
    208             peerString = "";
    209         } else {
    210             peerString = "?p=" + peerParam;
    211         }
    212 
    213213        PrintWriter out = resp.getWriter();
    214214        out.write(DOCTYPE + "<html>\n" +
     
    275275        out.write("<div class=\"page\"><div id=\"mainsection\" class=\"mainsection\">");
    276276
    277         writeMessages(out, isConfigure);
     277        writeMessages(out, isConfigure, peerString);
    278278
    279279        if (isConfigure) {
     
    295295    }
    296296
    297     private void writeMessages(PrintWriter out, boolean isConfigure) throws IOException {
     297    private void writeMessages(PrintWriter out, boolean isConfigure, String peerString) throws IOException {
    298298        List<String> msgs = _manager.getMessages();
    299299        if (!msgs.isEmpty()) {
     
    303303                out.write("<li>" + msg + "</li>\n");
    304304            }
    305             // lazy GET, lose p parameter
    306305            out.write("</ul><p><a href=\"/i2psnark/");
    307306            if (isConfigure)
    308307                out.write("configure");
    309             out.write("?action=Clear&amp;nonce=" + _nonce + "\">" + _("clear messages") + "</a></p></div>");
     308            if (peerString.length() > 0)
     309                out.write(peerString + "&amp;");
     310            else
     311                out.write("?");
     312            out.write("action=Clear&amp;nonce=" + _nonce + "\">" + _("clear messages") + "</a></p></div>");
    310313        }
    311314    }
  • history.txt

    r3685bf0 r6ca4b51  
     12012-05-19 zzz
     2 * i2psnark:
     3   - Store received chunks in temp files
     4   - Don't allocate from heap for unneeded chunks
     5   - Remove peer count restriction for torrents with large pieces
     6   - Use priorities and rarest calculations to sort partials
     7   - Preserve p parameter in clear messages link
     8
    192012-05-13 zzz
    210 * Console: Add X-Frame-Options to headers,
  • router/java/src/net/i2p/router/RouterVersion.java

    r3685bf0 r6ca4b51  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 1;
     21    public final static long BUILD = 2;
    2222
    2323    /** for example "-test" */
Note: See TracChangeset for help on using the changeset viewer.