Class DfsBlockCache

java.lang.Object
org.eclipse.jgit.internal.storage.dfs.DfsBlockCache

public final class DfsBlockCache extends Object
Caches slices of a BlockBasedFile in memory for faster read access.

The DfsBlockCache serves as a Java based "buffer cache", loading segments of a BlockBasedFile into the JVM heap prior to use. As JGit often wants to do reads of only tiny slices of a file, the DfsBlockCache tries to smooth out these tiny reads into larger block-sized IO operations.

Whenever a cache miss occurs, loading is invoked by exactly one thread for the given (DfsStreamKey,position) key tuple. This is ensured by an array of locks, with the tuple hashed to a lock instance.

Its too expensive during object access to be accurate with a least recently used (LRU) algorithm. Strictly ordering every read is a lot of overhead that typically doesn't yield a corresponding benefit to the application. This cache implements a clock replacement algorithm, giving each block at least one chance to have been accessed during a sweep of the cache to save itself from eviction. The number of swipe chances is configurable per pack extension.

Entities created by the cache are held under hard references, preventing the Java VM from clearing anything. Blocks are discarded by the replacement algorithm when adding a new block would cause the cache to exceed its configured maximum size.

The key tuple is passed through to methods as a pair of parameters rather than as a single Object, thus reducing the transient memory allocations of callers. It is more efficient to avoid the allocation, as we can't be 100% sure that a JIT would be able to stack-allocate a key tuple.

The internal hash table does not expand at runtime, instead it is fixed in size at cache creation time. The internal lock table used to gate load invocations is also fixed in size.

  • Field Details

    • cache

      private static volatile DfsBlockCache cache
    • tableSize

      private final int tableSize
      Number of entries in table.
    • table

      Hash bucket directory; entries are chained below.
    • loadLocks

      private final ReentrantLock[] loadLocks
      Locks to prevent concurrent loads for same (PackFile,position) block. The number of locks is DfsBlockCacheConfig.getConcurrencyLevel() to cap the overall concurrent block loads.
    • refLocks

      private final ReentrantLock[][] refLocks
      A separate pool of locks per pack extension to prevent concurrent loads for same index or bitmap from PackFile.
    • maxBytes

      private final long maxBytes
      Maximum number of bytes the cache should hold.
    • maxStreamThroughCache

      private final long maxStreamThroughCache
      Pack files smaller than this size can be copied through the cache.
    • blockSize

      private final int blockSize
      Suggested block size to read from pack files in.

      If a pack file does not have a native block size, this size will be used.

      If a pack file has a native size, a whole multiple of the native size will be used until it matches this size.

      The value for blockSize must be a power of 2.

    • blockSizeShift

      private final int blockSizeShift
      As blockSize is a power of 2, bits to shift for a / blockSize.
    • statHit

      private final AtomicReference<AtomicLong[]> statHit
      Number of times a block was found in the cache, per pack file extension.
    • statMiss

      private final AtomicReference<AtomicLong[]> statMiss
      Number of times a block was not found, and had to be loaded, per pack file extension.
    • statEvict

      private final AtomicReference<AtomicLong[]> statEvict
      Number of blocks evicted due to cache being full, per pack file extension.
    • liveBytes

      private final AtomicReference<AtomicLong[]> liveBytes
      Number of bytes currently loaded in the cache, per pack file extension.
    • clockLock

      private final ReentrantLock clockLock
      Protects the clock and its related data.
    • refLockWaitTime

      private final Consumer<Long> refLockWaitTime
      A consumer of object reference lock wait time milliseconds. May be used to build a metric.
    • clockHand

      private DfsBlockCache.Ref clockHand
      Current position of the clock.
    • cacheHotLimits

      private final int[] cacheHotLimits
      Limits of cache hot count per pack file extension.
    • indexEventConsumer

      private final DfsBlockCacheConfig.IndexEventConsumer indexEventConsumer
      Consumer of loading and eviction events of indexes.
    • indexEvictionMap

      private final Map<DfsBlockCache.EvictKey,Long> indexEvictionMap
      Stores timestamps of the last eviction of indexes.
  • Constructor Details

  • Method Details

    • reconfigure

      public static void reconfigure(DfsBlockCacheConfig cfg)
      Modify the configuration of the window cache.

      The new configuration is applied immediately, and the existing cache is cleared.

      Parameters:
      cfg - the new window cache configuration.
      Throws:
      IllegalArgumentException - the cache configuration contains one or more invalid settings, usually too low of a limit.
    • getInstance

      public static DfsBlockCache getInstance()
      Get the currently active DfsBlockCache.
      Returns:
      the currently active DfsBlockCache.
    • shouldCopyThroughCache

      boolean shouldCopyThroughCache(long length)
    • getCurrentSize

      public long[] getCurrentSize()
      Get total number of bytes in the cache, per pack file extension.
      Returns:
      total number of bytes in the cache, per pack file extension.
    • getFillPercentage

      public long getFillPercentage()
      Get 0..100, defining how full the cache is.
      Returns:
      0..100, defining how full the cache is.
    • getHitCount

      public long[] getHitCount()
      Get number of requests for items in the cache, per pack file extension.
      Returns:
      number of requests for items in the cache, per pack file extension.
    • getMissCount

      public long[] getMissCount()
      Get number of requests for items not in the cache, per pack file extension.
      Returns:
      number of requests for items not in the cache, per pack file extension.
    • getTotalRequestCount

      public long[] getTotalRequestCount()
      Get total number of requests (hit + miss), per pack file extension.
      Returns:
      total number of requests (hit + miss), per pack file extension.
    • getHitRatio

      public long[] getHitRatio()
      Get hit ratios
      Returns:
      hit ratios
    • getEvictions

      public long[] getEvictions()
      Get number of evictions performed due to cache being full, per pack file extension.
      Returns:
      number of evictions performed due to cache being full, per pack file extension.
    • hasBlock0

      public boolean hasBlock0(DfsStreamKey key)
      Quickly check if the cache contains block 0 of the given stream.

      This can be useful for sophisticated pre-read algorithms to quickly determine if a file is likely already in cache, especially small reftables which may be smaller than a typical DFS block size.

      Parameters:
      key - the file to check.
      Returns:
      true if block 0 (the first block) is in the cache.
    • hash

      private int hash(int packHash, long off)
    • getBlockSize

      int getBlockSize()
    • tableSize

      private static int tableSize(DfsBlockCacheConfig cfg)
    • getOrLoad

      DfsBlock getOrLoad(BlockBasedFile file, long position, DfsReader ctx, DfsBlockCache.ReadableChannelSupplier fileChannel) throws IOException
      Look up a cached object, creating and loading it if it doesn't exist.
      Parameters:
      file - the pack that "contains" the cached object.
      position - offset within pack of the object.
      ctx - current thread's reader.
      fileChannel - supplier for channel to read pack.
      Returns:
      the object reference.
      Throws:
      IOException - the reference was not in the cache and could not be loaded.
    • reserveSpace

      private void reserveSpace(long reserve, DfsStreamKey key)
    • creditSpace

      private void creditSpace(long credit, DfsStreamKey key)
    • addToClock

      private void addToClock(DfsBlockCache.Ref ref, long credit)
    • put

      void put(DfsBlock v)
    • getOrLoadRef

      <T> DfsBlockCache.Ref<T> getOrLoadRef(DfsStreamKey key, long position, DfsBlockCache.RefLoader<T> loader) throws IOException
      Look up a cached object, creating and loading it if it doesn't exist.
      Parameters:
      key - the stream key of the pack.
      position - the position in the key. The default should be 0.
      loader - the function to load the reference.
      Returns:
      the object reference.
      Throws:
      IOException - the reference was not in the cache and could not be loaded.
    • putRef

      <T> DfsBlockCache.Ref<T> putRef(DfsStreamKey key, long size, T v)
    • put

      <T> DfsBlockCache.Ref<T> put(DfsStreamKey key, long pos, long size, T v)
    • contains

      boolean contains(DfsStreamKey key, long position)
    • get

      <T> T get(DfsStreamKey key, long position)
    • scan

      private <T> T scan(DfsBlockCache.HashEntry n, DfsStreamKey key, long position)
    • scanRef

      private <T> DfsBlockCache.Ref<T> scanRef(DfsBlockCache.HashEntry n, DfsStreamKey key, long position)
    • slot

      private int slot(DfsStreamKey key, long position)
    • lockFor

      private ReentrantLock lockFor(DfsStreamKey key, long position)
    • lockForRef

      private ReentrantLock lockForRef(DfsStreamKey key)
    • newCounters

      private static AtomicLong[] newCounters()
    • getStat

      private static AtomicLong getStat(AtomicReference<AtomicLong[]> stats, DfsStreamKey key)
    • getStatVals

      private static long[] getStatVals(AtomicReference<AtomicLong[]> stat)
    • clean

    • reportIndexRequested

      private void reportIndexRequested(DfsBlockCache.Ref<?> ref, boolean cacheHit, long start)
    • reportIndexEvicted

      private void reportIndexEvicted(DfsBlockCache.Ref<?> dead)
    • isIndexOrBitmapExtPos

      private static boolean isIndexOrBitmapExtPos(int packExtPos)