Home | History | Annotate | Download | only in xz
      1 /*
      2  * ArrayCache
      3  *
      4  * Author: Lasse Collin <lasse.collin (at) tukaani.org>
      5  *
      6  * This file has been put into the public domain.
      7  * You can do whatever you want with this file.
      8  */
      9 
     10 package org.tukaani.xz;
     11 
     12 /**
     13  * Caches large arrays for reuse (base class and a dummy cache implementation).
     14  * <p>
     15  * When compressing or decompressing many (very) small files in a row, the
     16  * time spent in construction of new compressor or decompressor objects
     17  * can be longer than the time spent in actual compression or decompression.
     18  * A large part of this initialization overhead comes from allocation and
     19  * garbage collection of large arrays.
     20  * <p>
     21  * The {@code ArrayCache} API provides a way to cache large array allocations
     22  * for reuse. It can give a major performance improvement when compressing or
     23  * decompressing many tiny files. If you are only (de)compressing one or two
     24  * files or the files a very big, array caching won't improve anything,
     25  * although it won't make anything slower either.
     26  * <p>
     27  * <b>Important: The users of ArrayCache don't return the allocated arrays
     28  * back to the cache in all situations.</b>
     29  * This a reason why it's called a cache instead of a pool.
     30  * If it is important to be able to return every array back to a cache,
     31  * {@link ResettableArrayCache} can be useful.
     32  * <p>
     33  * In compressors (OutputStreams) the arrays are returned to the cache
     34  * when a call to {@code finish()} or {@code close()} returns
     35  * successfully (no exceptions are thrown).
     36  * <p>
     37  * In decompressors (InputStreams) the arrays are returned to the cache when
     38  * the decompression is successfully finished ({@code read} returns {@code -1})
     39  * or {@code close()} or {@code close(boolean)} is called. This is true even
     40  * if closing throws an exception.
     41  * <p>
     42  * Raw decompressors don't support {@code close(boolean)}. With raw
     43  * decompressors, if one wants to put the arrays back to the cache without
     44  * closing the underlying {@code InputStream}, one can wrap the
     45  * {@code InputStream} into {@link CloseIgnoringInputStream} when creating
     46  * the decompressor instance. Then one can use {@code close()}.
     47  * <p>
     48  * Different cache implementations can be extended from this base class.
     49  * All cache implementations must be thread safe.
     50  * <p>
     51  * This class also works as a dummy cache that simply calls {@code new}
     52  * to allocate new arrays and doesn't try to cache anything. A statically
     53  * allocated dummy cache is available via {@link #getDummyCache()}.
     54  * <p>
     55  * If no {@code ArrayCache} is specified when constructing a compressor or
     56  * decompressor, the default {@code ArrayCache} implementation is used.
     57  * See {@link #getDefaultCache()} and {@link #setDefaultCache(ArrayCache)}.
     58  * <p>
     59  * This is a class instead of an interface because it's possible that in the
     60  * future we may want to cache other array types too. New methods can be
     61  * added to this class without breaking existing cache implementations.
     62  *
     63  * @since 1.7
     64  *
     65  * @see BasicArrayCache
     66  */
     67 public class ArrayCache {
     68     /**
     69      * Global dummy cache instance that is returned by {@code getDummyCache()}.
     70      */
     71     private static final ArrayCache dummyCache = new ArrayCache();
     72 
     73     /**
     74      * Global default {@code ArrayCache} that is used when no other cache has
     75      * been specified.
     76      */
     77     private static volatile ArrayCache defaultCache = dummyCache;
     78 
     79     /**
     80      * Returns a statically-allocated {@code ArrayCache} instance.
     81      * It can be shared by all code that needs a dummy cache.
     82      */
     83     public static ArrayCache getDummyCache() {
     84         return dummyCache;
     85     }
     86 
     87     /**
     88      * Gets the default {@code ArrayCache} instance.
     89      * This is a global cache that is used when the application
     90      * specifies nothing else. The default is a dummy cache
     91      * (see {@link #getDummyCache()}).
     92      */
     93     public static ArrayCache getDefaultCache() {
     94         // It's volatile so no need for synchronization.
     95         return defaultCache;
     96     }
     97 
     98     /**
     99      * Sets the default {@code ArrayCache} instance.
    100      * Use with care. Other libraries using this package probably shouldn't
    101      * call this function as libraries cannot know if there are other users
    102      * of the xz package in the same application.
    103      */
    104     public static void setDefaultCache(ArrayCache arrayCache) {
    105         if (arrayCache == null)
    106             throw new NullPointerException();
    107 
    108         // It's volatile so no need for synchronization.
    109         defaultCache = arrayCache;
    110     }
    111 
    112     /**
    113      * Creates a new {@code ArrayCache} that does no caching
    114      * (a dummy cache). If you need a dummy cache, you may want to call
    115      * {@link #getDummyCache()} instead.
    116      */
    117     public ArrayCache() {}
    118 
    119     /**
    120      * Allocates a new byte array.
    121      * <p>
    122      * This implementation simply returns {@code new byte[size]}.
    123      *
    124      * @param   size            the minimum size of the array to allocate;
    125      *                          an implementation may return an array that
    126      *                          is larger than the given {@code size}
    127      *
    128      * @param   fillWithZeros   if true, the caller expects that the first
    129      *                          {@code size} elements in the array are zero;
    130      *                          if false, the array contents can be anything,
    131      *                          which speeds things up when reusing a cached
    132      *                          array
    133      */
    134     public byte[] getByteArray(int size, boolean fillWithZeros) {
    135         return new byte[size];
    136     }
    137 
    138     /**
    139      * Puts the given byte array to the cache. The caller must no longer
    140      * use the array.
    141      * <p>
    142      * This implementation does nothing.
    143      */
    144     public void putArray(byte[] array) {}
    145 
    146     /**
    147      * Allocates a new int array.
    148      * <p>
    149      * This implementation simply returns {@code new int[size]}.
    150      *
    151      * @param   size            the minimum size of the array to allocate;
    152      *                          an implementation may return an array that
    153      *                          is larger than the given {@code size}
    154      *
    155      * @param   fillWithZeros   if true, the caller expects that the first
    156      *                          {@code size} elements in the array are zero;
    157      *                          if false, the array contents can be anything,
    158      *                          which speeds things up when reusing a cached
    159      *                          array
    160      */
    161     public int[] getIntArray(int size, boolean fillWithZeros) {
    162         return new int[size];
    163     }
    164 
    165     /**
    166      * Puts the given int array to the cache. The caller must no longer
    167      * use the array.
    168      * <p>
    169      * This implementation does nothing.
    170      */
    171     public void putArray(int[] array) {}
    172 }
    173