Changeset f9818a2b


Ignore:
Timestamp:
Dec 13, 2011 3:55:03 PM (8 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
5a715f3
Parents:
900defcd
Message:
  • DataHelper?:
    • Speed up heavily used long/byte[] converters
    • Add little endian versions of the converters
    • Cache common properties keys
  • RouterAddress?: Cache transport names
Location:
core/java/src/net/i2p/data
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • core/java/src/net/i2p/data/DataHelper.java

    r900defcd rf9818a2b  
    3535import java.util.Comparator;
    3636import java.util.Date;
     37import java.util.HashMap;
    3738import java.util.Iterator;
    3839import java.util.List;
     
    5960    private static final byte[] EQUAL_BYTES = getUTF8("=");
    6061    private static final byte[] SEMICOLON_BYTES = getUTF8(";");
     62
     63    /**
     64     *  Map of String to itself to cache common
     65     *  keys in RouterInfo, RouterAddress, and BlockfileNamingService properties.
     66     *  Reduces Object proliferation caused by frequent deserialization.
     67     *  @since 0.8.12
     68     */
     69    private static final Map<String, String> _propertiesKeyCache;
     70    static {
     71        String keys[] = {
     72            // NTCP/SSU RouterAddress options
     73            "cost", "host", "port",
     74            // SSU RouterAddress options
     75            "key",
     76            "ihost0", "iport0", "ikey0", "itag0",
     77            "ihost1", "iport1", "ikey1", "itag1",
     78            "ihost2", "iport2", "ikey2", "itag2",
     79            // RouterInfo options
     80            "caps", "coreVersion", "netId", "router.version",
     81            "stat_bandwidthReceiveBps.60m",
     82            "stat_bandwidthSendBps.60m",
     83            "stat_tunnel.buildClientExpire.60m",
     84            "stat_tunnel.buildClientReject.60m",
     85            "stat_tunnel.buildClientSuccess.60m",
     86            "stat_tunnel.buildExploratoryExpire.60m",
     87            "stat_tunnel.buildExploratoryReject.60m",
     88            "stat_tunnel.buildExploratorySuccess.60m",
     89            "stat_tunnel.participatingTunnels.60m",
     90            "stat_uptime",
     91            // BlockfileNamingService
     92            "version", "created", "upgraded", "lists",
     93            "a", "s",
     94        };
     95        _propertiesKeyCache = new HashMap(keys.length);
     96        for (int i = 0; i < keys.length; i++) {
     97            _propertiesKeyCache.put(keys[i], keys[i]);
     98        }
     99    }
    61100
    62101    /** Read a mapping from the stream, as defined by the I2P data structure spec,
     
    75114     * @throws DataFormatException if the format is invalid
    76115     * @throws IOException if there is a problem reading the data
    77      * @return mapping
     116     * @return an OrderedProperties
    78117     */
    79118    public static Properties readProperties(InputStream rawStream)
     
    89128        while (in.available() > 0) {
    90129            String key = readString(in);
     130            String cached = _propertiesKeyCache.get(key);
     131            if (cached != null)
     132                key = cached;
    91133            read = read(in, eqBuf);
    92134            if ((read != eqBuf.length) || (!eq(eqBuf, EQUAL_BYTES))) {
    93                 break;
     135                throw new DataFormatException("Bad key");
    94136            }
    95137            String val = readString(in);
    96138            read = read(in, semiBuf);
    97139            if ((read != semiBuf.length) || (!eq(semiBuf, SEMICOLON_BYTES))) {
    98                 break;
     140                throw new DataFormatException("Bad value");
    99141            }
    100142            props.put(key, val);
     
    150192     * Keys and values must be 255 bytes or less,
    151193     * Formatted length must not exceed 65535 bytes
    152      * @throws DataFormatException if either is too long.
    153194     *
    154195     * jrandom disabled UTF-8 in mid-2004, for performance reasons,
     
    160201     * @param props source may be null
    161202     * @param sort should we sort the properties? (set to false if already sorted, e.g. OrderedProperties)
     203     * @throws DataFormatException if any string is over 255 bytes long, or if the total length
     204     *                             (not including the two length bytes) is greater than 65535 bytes.
    162205     * @since 0.8.7
    163206     */
     
    187230                baos.write(SEMICOLON_BYTES);
    188231            }
    189             baos.close();
     232            if (baos.size() > 65535)
     233                throw new DataFormatException("Properties too big (65535 max): " + baos.size());
    190234            byte propBytes[] = baos.toByteArray();
    191             if (propBytes.length > 65535)
    192                 throw new DataFormatException("Properties too big (65535 max): " + propBytes.length);
    193235            writeLong(rawStream, 2, propBytes.length);
    194236            rawStream.write(propBytes);
     
    213255     * @return new offset
    214256     * @throws DataFormatException if any string is over 255 bytes long, or if the total length
    215      *                             is greater than 65535 bytes.
     257     *                             (not including the two length bytes) is greater than 65535 bytes.
    216258     */
    217259    @Deprecated
     
    229271                baos.write(SEMICOLON_BYTES);
    230272            }
    231             baos.close();
     273            if (baos.size() > 65535)
     274                throw new DataFormatException("Properties too big (65535 max): " + baos.size());
    232275            byte propBytes[] = baos.toByteArray();
    233             if (propBytes.length > 65535)
    234                 throw new DataFormatException("Properties too big (65535 max): " + propBytes.length);
    235276            toLong(target, offset, 2, propBytes.length);
    236277            offset += 2;
     
    264305            try {
    265306                key = readString(in);
     307                String cached = _propertiesKeyCache.get(key);
     308                if (cached != null)
     309                    key = cached;
    266310                int read = read(in, eqBuf);
    267311                if ((read != eqBuf.length) || (!eq(eqBuf, EQUAL_BYTES))) {
     
    469513     * @param rawStream stream to read from
    470514     * @param numBytes number of bytes to read and format into a number, 1 to 8
    471      * @throws DataFormatException if the stream doesn't contain a validly formatted number of that many bytes
     515     * @throws DataFormatException if negative (only possible if numBytes = 8) (since 0.8.12)
    472516     * @throws EOFException since 0.8.2, if there aren't enough bytes to read the number
    473517     * @throws IOException if there is an IO error reading the number
     
    481525        long rv = 0;
    482526        for (int i = 0; i < numBytes; i++) {
    483             long cur = rawStream.read();
     527            int cur = rawStream.read();
    484528            // was DataFormatException
    485529            if (cur == -1) throw new EOFException("EOF reading " + numBytes + " byte value");
    486             cur &= 0xFF;
    487530            // we loop until we find a nonzero byte (or we reach the end)
    488531            if (cur != 0) {
    489532                // ok, data found, now iterate through it to fill the rv
    490                 long remaining = numBytes - i;
    491                 for (int j = 0; j < remaining; j++) {
    492                     long shiftAmount = 8 * (remaining-j-1);
    493                     cur = cur << shiftAmount;
    494                     rv += cur;
    495                     if (j + 1 < remaining) {
    496                         cur = rawStream.read();
    497                         // was DataFormatException
    498                         if (cur == -1)
    499                             throw new EOFException("EOF reading " + numBytes + " byte value");
    500                         cur &= 0xFF;
    501                     }
     533                rv = cur & 0xff;
     534                for (int j = i + 1; j < numBytes; j++) {
     535                    rv <<= 8;
     536                    cur = rawStream.read();
     537                    // was DataFormatException
     538                    if (cur == -1)
     539                        throw new EOFException("EOF reading " + numBytes + " byte value");
     540                    rv |= cur & 0xff;
    502541                }
    503542                break;
     
    505544        }
    506545       
     546        if (rv < 0)
     547            throw new DataFormatException("wtf, fromLong got a negative? " + rv + " numBytes=" + numBytes);
    507548        return rv;
    508549    }
     
    519560        throws DataFormatException, IOException {
    520561        if (value < 0) throw new DataFormatException("Value is negative (" + value + ")");
    521         for (int i = numBytes - 1; i >= 0; i--) {
    522             byte cur = (byte)( (value >>> (i*8) ) & 0xFF);
     562        for (int i = (numBytes - 1) * 8; i >= 0; i -= 8) {
     563            byte cur = (byte) (value >> i);
    523564            rawStream.write(cur);
    524565        }
     
    543584        if (numBytes <= 0) throw new IllegalArgumentException("Invalid number of bytes");
    544585        if (value < 0) throw new IllegalArgumentException("Negative value not allowed");
    545         for (int i = 0; i < numBytes; i++)
    546             target[offset+numBytes-i-1] = (byte)(value >>> (i*8));
    547     }
    548    
    549     /**
     586
     587        for (int i = offset + numBytes - 1; i >= offset; i--) {
     588            target[i] = (byte) value;
     589            value >>= 8;
     590        }
     591    }
     592   
     593    /**
     594     * Little endian, i.e. backwards. Not for use in I2P protocols.
     595     *
     596     * @param numBytes 1-8
     597     * @param value non-negative
     598     * @since 0.8.12
     599     */
     600    public static void toLongLE(byte target[], int offset, int numBytes, long value) {
     601        if (value < 0) throw new IllegalArgumentException("Negative value not allowed");
     602        int limit = offset + numBytes;
     603        for (int i = offset; i < limit; i++) {
     604            target[i] = (byte) value;
     605            value >>= 8;
     606        }
     607    }
     608   
     609    /**
     610     * @param src if null returns 0
    550611     * @param numBytes 1-8
    551612     * @return non-negative
     613     * @throws AIOOBE
     614     * @throws IllegalArgumentException if negative (only possible if numBytes = 8)
    552615     */
    553616    public static long fromLong(byte src[], int offset, int numBytes) {
     
    556619       
    557620        long rv = 0;
    558         for (int i = 0; i < numBytes; i++) {
    559             long cur = src[offset+i] & 0xFF;
    560             if (cur < 0) cur = cur+256;
    561             cur = (cur << (8*(numBytes-i-1)));
    562             rv += cur;
     621        int limit = offset + numBytes;
     622        for (int i = offset; i < limit; i++) {
     623            rv <<= 8;
     624            rv |= src[i] & 0xFF;
     625        }
     626        if (rv < 0)
     627            throw new IllegalArgumentException("wtf, fromLong got a negative? " + rv + ": offset="+ offset +" numBytes="+numBytes);
     628        return rv;
     629    }
     630   
     631    /**
     632     * Little endian, i.e. backwards. Not for use in I2P protocols.
     633     *
     634     * @param numBytes 1-8
     635     * @return non-negative
     636     * @throws AIOOBE
     637     * @throws IllegalArgumentException if negative (only possible if numBytes = 8)
     638     * @since 0.8.12
     639     */
     640    public static long fromLongLE(byte src[], int offset, int numBytes) {
     641        long rv = 0;
     642        for (int i = offset + numBytes - 1; i >= offset; i--) {
     643            rv <<= 8;
     644            rv |= src[i] & 0xFF;
    563645        }
    564646        if (rv < 0)
     
    637719     */
    638720    public static String readString(InputStream in) throws DataFormatException, IOException {
    639         int size = (int) readLong(in, 1);
     721        int size = in.read();
     722        if (size == -1)
     723            throw new EOFException("EOF reading string");
     724        if (size == 0)
     725            return "";   // reduce object proliferation
     726        size &= 0xff;
    640727        byte raw[] = new byte[size];
    641728        int read = read(in, raw);
     
    662749        throws DataFormatException, IOException {
    663750        if (string == null) {
    664             writeLong(out, 1, 0);
     751            out.write((byte) 0);
    665752        } else {
    666753            int len = string.length();
     
    668755                throw new DataFormatException("The I2P data spec limits strings to 255 bytes or less, but this is "
    669756                                              + len + " [" + string + "]");
    670             writeLong(out, 1, len);
     757            out.write((byte) len);
    671758            for (int i = 0; i < len; i++)
    672759                out.write((byte)(string.charAt(i) & 0xFF));
     
    688775        throws DataFormatException, IOException {
    689776        if (string == null) {
    690             writeLong(out, 1, 0);
     777            out.write((byte) 0);
    691778        } else {
    692779            // the following method throws an UnsupportedEncodingException which is an IOException,
     
    697784                throw new DataFormatException("The I2P data spec limits strings to 255 bytes or less, but this is "
    698785                                              + len + " [" + string + "]");
    699             writeLong(out, 1, len);
     786            out.write((byte) len);
    700787            out.write(raw);
    701788        }
     
    711798     */
    712799    public static Boolean readBoolean(InputStream in) throws DataFormatException, IOException {
    713         int val = (int) readLong(in, 1);
     800        int val = in.read();
    714801        switch (val) {
     802        case -1:
     803            throw new EOFException("EOF reading boolean");
    715804        case 0:
    716805            return Boolean.FALSE;
     
    14701559     *  instead of an UnsupportedEncodingException if no UTF-8, for ease of use.
    14711560     *
     1561     *  @return null if orig is null
    14721562     *  @throws RuntimeException
    14731563     */
     
    14851575     *  instead of an UnsupportedEncodingException if no UTF-8, for ease of use.
    14861576     *
     1577     *  @return null if orig is null
    14871578     *  @throws RuntimeException
    14881579     *  @deprecated unused
     
    14971588     *  instead of an UnsupportedEncodingException if no UTF-8, for ease of use.
    14981589     *
     1590     *  @return null if orig is null
    14991591     *  @throws RuntimeException
    15001592     *  @deprecated unused
     
    15131605     *  instead of an UnsupportedEncodingException if no UTF-8, for ease of use.
    15141606     *
     1607     *  @return null if orig is null
    15151608     *  @throws RuntimeException
    15161609     *  @deprecated unused
  • core/java/src/net/i2p/data/RouterAddress.java

    r900defcd rf9818a2b  
    111111        _expiration = DataHelper.readDate(in);
    112112        _transportStyle = DataHelper.readString(in);
     113        // reduce Object proliferation
     114        if (_transportStyle.equals("SSU"))
     115            _transportStyle = "SSU";
     116        else if (_transportStyle.equals("NTCP"))
     117            _transportStyle = "NTCP";
    113118        _options = DataHelper.readProperties(in);
    114119    }
Note: See TracChangeset for help on using the changeset viewer.