Changeset 6ad1de8


Ignore:
Timestamp:
Jul 10, 2018 9:21:32 PM (2 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
9d2f684
Parents:
f6da5f4
Message:

Util: Convert more caches to TryCache? (ticket #2263)

Files:
6 edited

Legend:

Unmodified
Added
Removed
  • core/java/src/net/i2p/util/ByteCache.java

    rf6da5f4 r6ad1de8  
    33import java.util.Arrays;
    44import java.util.Map;
    5 import java.util.Queue;
    65import java.util.concurrent.ConcurrentHashMap;
    7 import java.util.concurrent.LinkedBlockingQueue;
    86
    97import net.i2p.I2PAppContext;
     
    2321
    2422        1K      32      32K     tunnel TrivialPreprocessor
     23                *changed to 512 since we disabled resize()
    2524        1K      512     512K    tunnel FragmentHandler
    2625        1K      512     512K    I2NP TunnelDataMessage
    2726        1K      512     512K    tunnel FragmentedMessage
    2827
     28        1572    64      100K    UDP InboundMessageState
     29
    2930        1730    128     216K    streaming MessageOutputStream
    30 
    31         2K      64      128K    UDP IMS
    3231
    3332        4K      32      128K    I2PTunnelRunner
     
    5049 *
    5150 */
    52 public final class ByteCache {
     51public final class ByteCache extends TryCache<ByteArray> {
    5352
    5453    //private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(ByteCache.class);
     
    8483            cacheSize = MAX_CACHE / size;
    8584        Integer sz = Integer.valueOf(size);
    86         ByteCache cache = _caches.get(sz);
    87         if (cache == null) {
    88             cache = new ByteCache(cacheSize, size);
    89             _caches.put(sz, cache);
     85        ByteCache cache;
     86        synchronized(_caches) {
     87            cache = _caches.get(sz);
     88            if (cache == null) {
     89                cache = new ByteCache(cacheSize, size);
     90                _caches.put(sz, cache);
     91            }
    9092        }
    9193        cache.resize(cacheSize);
     
    104106    }
    105107
    106     /** list of available and available entries */
    107     private volatile Queue<ByteArray> _available;
    108     private int _maxCached;
    109108    private final int _entrySize;
    110     private volatile long _lastOverflow;
    111    
    112     /** do we actually want to cache? Warning - setting to false may NPE, this should be fixed or removed */
    113     private static final boolean _cache = true;
    114109   
    115110    /** how often do we cleanup the cache */
     
    118113    private static final long EXPIRE_PERIOD = 2*60*1000;
    119114   
     115    /** @since 0.9.36 */
     116    private static class ByteArrayFactory implements TryCache.ObjectFactory<ByteArray> {
     117        private final int sz;
     118
     119        ByteArrayFactory(int entrySize) {
     120            sz = entrySize;
     121        }
     122
     123        public ByteArray newInstance() {
     124            byte data[] = new byte[sz];
     125            ByteArray rv = new ByteArray(data);
     126            rv.setValid(0);
     127            return rv;
     128        }
     129    }
     130
    120131    private ByteCache(int maxCachedEntries, int entrySize) {
    121         if (_cache)
    122             _available = new LinkedBlockingQueue<ByteArray>(maxCachedEntries);
    123         _maxCached = maxCachedEntries;
     132        super(new ByteArrayFactory(entrySize), maxCachedEntries);
    124133        _entrySize = entrySize;
    125         _lastOverflow = -1;
    126         SimpleTimer2.getInstance().addPeriodicEvent(new Cleanup(), CLEANUP_FREQUENCY + (entrySize % 777));   //stagger
     134        int stagger = SystemVersion.isAndroid() ? 0 : (entrySize % 777);
     135        SimpleTimer2.getInstance().addPeriodicEvent(new Cleanup(), CLEANUP_FREQUENCY + stagger);
    127136        I2PAppContext.getGlobalContext().statManager().createRateStat("byteCache.memory." + entrySize, "Memory usage (B)", "Router", new long[] { 10*60*1000 });
    128137    }
    129138   
    130139    private void resize(int maxCachedEntries) {
    131         if (_maxCached >= maxCachedEntries) return;
    132         _maxCached = maxCachedEntries;
    133         // make a bigger one, move the cached items over
    134         Queue<ByteArray> newLBQ = new LinkedBlockingQueue<ByteArray>(maxCachedEntries);
    135         ByteArray ba;
    136         while ((ba = _available.poll()) != null)
    137             newLBQ.offer(ba);
    138         _available = newLBQ;
    139     }
    140    
    141     /**
    142      * Get the next available structure, either from the cache or a brand new one.
    143      * Returned ByteArray will have valid = 0 and offset = 0.
    144      * Returned ByteArray may or may not be zero, depends on whether
    145      * release(ba) or release(ba, false) was called.
    146      * Which is a problem, you should really specify shouldZero on acquire, not release.
    147      */
    148     public final ByteArray acquire() {
    149         if (_cache) {
    150             ByteArray rv = _available.poll();
    151             if (rv != null)
    152                 return rv;
    153         }
    154         _lastOverflow = System.currentTimeMillis();
    155         byte data[] = new byte[_entrySize];
    156         ByteArray rv = new ByteArray(data);
    157         rv.setValid(0);
    158         //rv.setOffset(0);
    159         return rv;
     140        // disabled since we're now extending TryCache
    160141    }
    161142   
     
    164145     *
    165146     */
     147    @Override
    166148    public final void release(ByteArray entry) {
    167149        release(entry, true);
     
    169151
    170152    public final void release(ByteArray entry, boolean shouldZero) {
    171         if (_cache) {
    172             if (entry == null || entry.getData() == null)
    173                 return;
    174             if (entry.getData().length != _entrySize) {
    175                 Log log = I2PAppContext.getGlobalContext().logManager().getLog(ByteCache.class);
    176                 if (log.shouldLog(Log.WARN))
    177                     log.warn("Bad size", new Exception("I did it"));
    178                 return;
    179             }
    180             entry.setValid(0);
    181             entry.setOffset(0);
    182            
    183             if (shouldZero)
    184                 Arrays.fill(entry.getData(), (byte)0x0);
    185             _available.offer(entry);
     153        if (entry == null || entry.getData() == null)
     154            return;
     155        if (entry.getData().length != _entrySize) {
     156            Log log = I2PAppContext.getGlobalContext().logManager().getLog(ByteCache.class);
     157            if (log.shouldLog(Log.WARN))
     158                log.warn("Bad size", new Exception("I did it"));
     159            return;
    186160        }
    187     }
    188    
    189     /**
    190      *  Clear everything (memory pressure)
    191      *  @since 0.7.14
    192      */
    193     private void clear() {
    194         _available.clear();
     161        entry.setValid(0);
     162        entry.setOffset(0);
     163         
     164        if (shouldZero)
     165            Arrays.fill(entry.getData(), (byte)0x0);
     166        super.release(entry);
    195167    }
    196168
    197169    private class Cleanup implements SimpleTimer.TimedEvent {
    198170        public void timeReached() {
    199             I2PAppContext.getGlobalContext().statManager().addRateData("byteCache.memory." + _entrySize, _entrySize * _available.size(), 0);
    200             if (System.currentTimeMillis() - _lastOverflow > EXPIRE_PERIOD) {
    201                 // we haven't exceeded the cache size in a few minutes, so lets
    202                 // shrink the cache
    203                     int toRemove = _available.size() / 2;
    204                     for (int i = 0; i < toRemove; i++)
    205                         _available.poll();
    206                     //if ( (toRemove > 0) && (_log.shouldLog(Log.DEBUG)) )
    207                     //    _log.debug("Removing " + toRemove + " cached entries of size " + _entrySize);
     171            int origsz;
     172            lock.lock();
     173            try {
     174                origsz = items.size();
     175                if (origsz > 1 && System.currentTimeMillis() - _lastUnderflow > EXPIRE_PERIOD) {
     176                    // we haven't exceeded the cache size in a few minutes, so lets
     177                    // shrink the cache
     178                    int toRemove = origsz / 2;
     179                    for (int i = 0; i < toRemove; i++) {
     180                        items.remove(items.size() - 1);
     181                    }
     182                }
     183            } finally {
     184                lock.unlock();
    208185            }
     186            I2PAppContext.getGlobalContext().statManager().addRateData("byteCache.memory." + _entrySize, _entrySize * origsz);
    209187        }
    210188
  • core/java/src/net/i2p/util/SimpleByteCache.java

    rf6da5f4 r6ad1de8  
    11package net.i2p.util;
    22
    3 import java.util.Queue;
    4 import java.util.concurrent.ArrayBlockingQueue;
    53import java.util.concurrent.ConcurrentHashMap;
    6 import java.util.concurrent.LinkedBlockingQueue;
    74
    85/**
     
    1916
    2017    private static final int DEFAULT_SIZE = 64;
    21 
    22     /** up to this, use ABQ to minimize object churn and for performance; above this, use LBQ for two locks */
    23     private static final int MAX_FOR_ABQ = 64;
    2418
    2519    /**
     
    6155    }
    6256
    63     /** list of available and available entries */
    64     private Queue<byte[]> _available;
    65     private int _maxCached;
     57    private final TryCache<byte[]> _available;
    6658    private final int _entrySize;
    6759   
     60    /** @since 0.9.36 */
     61    private static class ByteArrayFactory implements TryCache.ObjectFactory<byte[]> {
     62        private final int sz;
     63
     64        ByteArrayFactory(int entrySize) {
     65            sz = entrySize;
     66        }
     67
     68        public byte[] newInstance() {
     69            return new byte[sz];
     70        }
     71    }
     72
    6873    private SimpleByteCache(int maxCachedEntries, int entrySize) {
    69         _maxCached = maxCachedEntries;
    70         _available = createQueue();
     74        _available = new TryCache(new ByteArrayFactory(entrySize), maxCachedEntries);
    7175        _entrySize = entrySize;
    7276    }
    7377   
    7478    private void resize(int maxCachedEntries) {
    75         if (_maxCached >= maxCachedEntries) return;
    76         _maxCached = maxCachedEntries;
    77         // make a bigger one, move the cached items over
    78         Queue<byte[]> newLBQ = createQueue();
    79         byte[] ba;
    80         while ((ba = _available.poll()) != null)
    81             newLBQ.offer(ba);
    82         _available = newLBQ;
     79        // _available is now final, and getInstance() is not used anywhere,
     80        // all call sites just use static acquire()
    8381    }
    8482   
    85     /**
    86      *  @return LBQ or ABQ
    87      *  @since 0.9.2
    88      */
    89     private Queue<byte[]> createQueue() {
    90         if (_entrySize <= MAX_FOR_ABQ)
    91             return new ArrayBlockingQueue<byte[]>(_maxCached);
    92         return new LinkedBlockingQueue<byte[]>(_maxCached);
    93     }
    94 
    9583    /**
    9684     * Get the next available array, either from the cache or a brand new one
     
    10088    }
    10189
    102     /**
     90     /**
    10391     * Get the next available array, either from the cache or a brand new one
    10492     */
    10593    private byte[] acquire() {
    106         byte[] rv = _available.poll();
    107         if (rv == null)
    108             rv = new byte[_entrySize];
    109         return rv;
     94        return _available.acquire();
    11095    }
    11196   
     
    127112        // should be safe without this
    128113        //Arrays.fill(entry, (byte) 0);
    129         _available.offer(entry);
     114        _available.release(entry);
    130115    }
    131116   
  • core/java/src/net/i2p/util/TryCache.java

    rf6da5f4 r6ad1de8  
    1212 *
    1313 * @param <T>
     14 * @since 0.9.36
    1415 */
    1516public class TryCache<T> {
     
    2526   
    2627    private final ObjectFactory<T> factory;
    27     private final int capacity;
    28     private final List<T> items;
    29     private final Lock lock = new ReentrantLock();
     28    protected final int capacity;
     29    protected final List<T> items;
     30    protected final Lock lock = new ReentrantLock();
     31    protected long _lastUnderflow;
    3032   
    3133    /**
     
    4850                if (!items.isEmpty()) {
    4951                    rv = items.remove(items.size() - 1);
     52                } else {
     53                    _lastUnderflow = System.currentTimeMillis();
    5054                }
    5155            } finally {
  • history.txt

    rf6da5f4 r6ad1de8  
    44   - Add support for IzPack 5
    55 * SSU: Sync/notify improvements (ticket #2260)
     6 * Util: Convert more caches to TryCache (ticket #2263)
    67
    782018-07-08 zzz
  • router/java/src/net/i2p/router/RouterVersion.java

    rf6da5f4 r6ad1de8  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 9;
     21    public final static long BUILD = 10;
    2222
    2323    /** for example "-test" */
  • router/java/src/net/i2p/router/tunnel/TrivialPreprocessor.java

    rf6da5f4 r6ad1de8  
    3535     * Used in BatchedPreprocessor; see add'l comments there
    3636     */
    37     protected static final ByteCache _dataCache = ByteCache.getInstance(32, PREPROCESSED_SIZE);
     37    protected static final ByteCache _dataCache = ByteCache.getInstance(512, PREPROCESSED_SIZE);
    3838
    3939    public TrivialPreprocessor(RouterContext ctx) {
Note: See TracChangeset for help on using the changeset viewer.