Class WindowCache
- java.lang.Object
-
- org.eclipse.jgit.internal.storage.file.WindowCache
-
public class WindowCache extends java.lang.Object
Caches slices of aPackFile
in memory for faster read access.The WindowCache serves as a Java based "buffer cache", loading segments of a PackFile into the JVM heap prior to use. As JGit often wants to do reads of only tiny slices of a file, the WindowCache tries to smooth out these tiny reads into larger block-sized IO operations.
Whenever a cache miss occurs,
load(PackFile, long)
is invoked by exactly one thread for the given(PackFile,position)
key tuple. This is ensured by an array of locks, with the tuple hashed to a lock instance.During a miss, older entries are evicted from the cache so long as
isFull()
returns true.Its too expensive during object access to be 100% 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 loose LRU policy by randomly picking a window comprised of roughly 10% of the cache, and evicting the oldest accessed entry within that window.
Entities created by the cache are held under SoftReferences if option
core.packedGitUseStrongRefs
is set tofalse
in the git config (this is the default) or by callingWindowCacheConfig.setPackedGitUseStrongRefs(boolean)
, permitting the Java runtime's garbage collector to evict entries when heap memory gets low. Most JREs implement a loose least recently used algorithm for this eviction. When this option is set totrue
strong references are used which means that Java gc cannot evict the WindowCache to reclaim memory. On the other hand this provides more predictable performance since the cache isn't flushed when used heap comes close to the maximum heap size.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.
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.
This cache has an implementation rule such that:
load(PackFile, long)
is invoked by at most one thread at a time for a given(PackFile,position)
tuple.- For every
load()
invocation there is exactly onecreateRef(PackFile, long, ByteWindow)
invocation to wrap a SoftReference or a StrongReference around the cached entity. - For every Reference created by
createRef()
there will be exactly one call toclear(PageRef)
to cleanup any resources associated with the (now expired) cached entity.
Therefore, it is safe to perform resource accounting increments during the
load(PackFile, long)
orcreateRef(PackFile, long, ByteWindow)
methods, and matching decrements duringclear(PageRef)
. Implementors may need to overridecreateRef(PackFile, long, ByteWindow)
in order to embed additional accounting information into an implementation specificWindowCache.PageRef
subclass, as the cached entity may have already been evicted by the JRE's garbage collector.To maintain higher concurrency workloads, during eviction only one thread performs the eviction work, while other threads can continue to insert new objects in parallel. This means that the cache can be temporarily over limit, especially if the nominated eviction thread is being starved relative to the other threads.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description private static interface
WindowCache.CleanupQueue
private static class
WindowCache.Entry
private static class
WindowCache.Lock
private static interface
WindowCache.PageRef<T>
private static class
WindowCache.SoftCleanupQueue
private static class
WindowCache.SoftRef
A soft reference wrapped around a cached object.(package private) static interface
WindowCache.StatsRecorder
Record statistics for a cache(package private) static class
WindowCache.StatsRecorderImpl
private static class
WindowCache.StrongCleanupQueue
private static class
WindowCache.StrongRef
A strong reference wrapped around a cached object.
-
Field Summary
Fields Modifier and Type Field Description private static WindowCache
cache
private java.util.concurrent.atomic.AtomicLong
clock
Access clock for loose LRU.private int
evictBatch
Number oftable
buckets to scan for an eviction window.private java.util.concurrent.locks.ReentrantLock
evictLock
Lock to elect the eviction thread after a load occurs.private WindowCache.Lock[]
locks
Locks to prevent concurrent loads for same (PackFile,position).private long
maxBytes
private int
maxFiles
private WindowCache.StatsRecorderImpl
mbean
private boolean
mmap
private java.util.concurrent.atomic.AtomicBoolean
publishMBean
private WindowCache.CleanupQueue
queue
cleanup released and/or garbage collected windows.private static java.util.Random
rng
private WindowCache.StatsRecorder
statsRecorder
private static int
streamFileThreshold
private java.util.concurrent.atomic.AtomicReferenceArray<WindowCache.Entry>
table
Hash bucket directory; entries are chained below.private int
tableSize
Number of entries intable
.private boolean
useStrongRefs
private int
windowSize
private int
windowSizeShift
-
Constructor Summary
Constructors Modifier Constructor Description private
WindowCache(WindowCacheConfig cfg)
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Deprecated Methods Modifier and Type Method Description private static int
bits(int newSize)
private static WindowCache.Entry
clean(WindowCache.Entry top)
private void
clear(WindowCache.PageRef<ByteWindow> ref)
private void
close(PackFile pack)
private WindowCache.PageRef<ByteWindow>
createRef(PackFile p, long o, ByteWindow v)
private void
evict()
private void
gc()
(package private) static ByteWindow
get(PackFile pack, long offset)
static WindowCache
getInstance()
private ByteWindow
getOrLoad(PackFile pack, long position)
Lookup a cached object, creating and loading it if it doesn't exist.WindowCacheStats
getStats()
(package private) static int
getStreamFileThreshold()
private int
hash(int packHash, long off)
private void
hit(WindowCache.PageRef r)
private boolean
isFull()
private ByteWindow
load(PackFile pack, long offset)
private WindowCache.Lock
lock(PackFile pack, long position)
private static int
lockCount(WindowCacheConfig cfg)
private WindowCache
publishMBeanIfNeeded()
(package private) static void
purge(PackFile pack)
static void
reconfigure(WindowCacheConfig cfg)
Deprecated.usecfg.install()
to avoid internal reference.private void
removeAll()
Clear every entry from the cache.private void
removeAll(PackFile pack)
Clear all entries related to a single file.void
resetStats()
Reset stats.private ByteWindow
scan(WindowCache.Entry n, PackFile pack, long position)
private int
slot(PackFile pack, long position)
private static int
tableSize(WindowCacheConfig cfg)
private long
toStart(long offset)
-
-
-
Field Detail
-
rng
private static final java.util.Random rng
-
cache
private static volatile WindowCache cache
-
streamFileThreshold
private static volatile int streamFileThreshold
-
queue
private final WindowCache.CleanupQueue queue
cleanup released and/or garbage collected windows.
-
tableSize
private final int tableSize
Number of entries intable
.
-
clock
private final java.util.concurrent.atomic.AtomicLong clock
Access clock for loose LRU.
-
table
private final java.util.concurrent.atomic.AtomicReferenceArray<WindowCache.Entry> table
Hash bucket directory; entries are chained below.
-
locks
private final WindowCache.Lock[] locks
Locks to prevent concurrent loads for same (PackFile,position).
-
evictLock
private final java.util.concurrent.locks.ReentrantLock evictLock
Lock to elect the eviction thread after a load occurs.
-
evictBatch
private final int evictBatch
Number oftable
buckets to scan for an eviction window.
-
maxFiles
private final int maxFiles
-
maxBytes
private final long maxBytes
-
mmap
private final boolean mmap
-
windowSizeShift
private final int windowSizeShift
-
windowSize
private final int windowSize
-
statsRecorder
private final WindowCache.StatsRecorder statsRecorder
-
mbean
private final WindowCache.StatsRecorderImpl mbean
-
publishMBean
private final java.util.concurrent.atomic.AtomicBoolean publishMBean
-
useStrongRefs
private boolean useStrongRefs
-
-
Constructor Detail
-
WindowCache
private WindowCache(WindowCacheConfig cfg)
-
-
Method Detail
-
bits
private static final int bits(int newSize)
-
reconfigure
@Deprecated public static void reconfigure(WindowCacheConfig cfg)
Deprecated.usecfg.install()
to avoid internal reference.Modify the configuration of the window cache.The new configuration is applied immediately. If the new limits are smaller than what is currently cached, older entries will be purged as soon as possible to allow the cache to meet the new limit.
- Parameters:
cfg
- the new window cache configuration.- Throws:
java.lang.IllegalArgumentException
- the cache configuration contains one or more invalid settings, usually too low of a limit.
-
getStreamFileThreshold
static int getStreamFileThreshold()
-
getInstance
public static WindowCache getInstance()
- Returns:
- the cached instance.
-
get
static final ByteWindow get(PackFile pack, long offset) throws java.io.IOException
- Throws:
java.io.IOException
-
purge
static final void purge(PackFile pack)
-
publishMBeanIfNeeded
private WindowCache publishMBeanIfNeeded()
-
getStats
public WindowCacheStats getStats()
- Returns:
- cache statistics for the WindowCache
-
resetStats
public void resetStats()
Reset stats. Does not reset open bytes and open files stats.
-
hash
private int hash(int packHash, long off)
-
load
private ByteWindow load(PackFile pack, long offset) throws java.io.IOException
- Throws:
java.io.IOException
-
createRef
private WindowCache.PageRef<ByteWindow> createRef(PackFile p, long o, ByteWindow v)
-
clear
private void clear(WindowCache.PageRef<ByteWindow> ref)
-
close
private void close(PackFile pack)
-
isFull
private boolean isFull()
-
toStart
private long toStart(long offset)
-
tableSize
private static int tableSize(WindowCacheConfig cfg)
-
lockCount
private static int lockCount(WindowCacheConfig cfg)
-
getOrLoad
private ByteWindow getOrLoad(PackFile pack, long position) throws java.io.IOException
Lookup a cached object, creating and loading it if it doesn't exist.- Parameters:
pack
- the pack that "contains" the cached object.position
- offset withinpack
of the object.- Returns:
- the object reference.
- Throws:
java.io.IOException
- the object reference was not in the cache and could not be obtained byload(PackFile, long)
.
-
scan
private ByteWindow scan(WindowCache.Entry n, PackFile pack, long position)
-
hit
private void hit(WindowCache.PageRef r)
-
evict
private void evict()
-
removeAll
private void removeAll()
Clear every entry from the cache.This is a last-ditch effort to clear out the cache, such as before it gets replaced by another cache that is configured differently. This method tries to force every cached entry through
clear(PageRef)
to ensure that resources are correctly accounted for and cleaned up by the subclass. A concurrent reader loading entries while this method is running may cause resource accounting failures.
-
removeAll
private void removeAll(PackFile pack)
Clear all entries related to a single file.Typically this method is invoked during
PackFile.close()
, when we know the pack is never going to be useful to us again (for example, it no longer exists on disk). A concurrent reader loading an entry from this same pack may cause the pack to become stuck in the cache anyway.- Parameters:
pack
- the file to purge all entries of.
-
gc
private void gc()
-
slot
private int slot(PackFile pack, long position)
-
lock
private WindowCache.Lock lock(PackFile pack, long position)
-
clean
private static WindowCache.Entry clean(WindowCache.Entry top)
-
-