Class StorageLocation
CacheEntry, controlling that the total size of stored
files doesn't exceed the maxSizeBytes and available space is always kept smaller than
freeSpaceToKeep.
CacheEntry can be stored in two manners in a storage location. The first is to store the entry indefinitely
with reserve(CacheEntry), where the space of the entry is accounted for and the storage space will not be
recovered until release(CacheEntry) is called. These entries are stored in staticCacheEntries.
The second way is to store as a transient cache item with one of reserveWeak(CacheEntry),
addWeakReservationHold(CacheEntryIdentifier, Supplier), or
addWeakReservationHoldIfExists(CacheEntryIdentifier). CacheEntry stored in this manner will exist on
disk in this location until the point that another new reservation needs more space than remains available in the
location, at which point reclaim(long) will be called to try to call CacheEntry.unmount() on any
eligible entries until enough space is available to store the new item.
Items are chosen for eviction using an algorithm based on SIEVE with additional mechanisms to place temporary holds on cache entries. The holds are required to support cases such as if a group of cache entries are taking part in a query and must all be loaded simultaneously before processing can continue.
Implementation-wise, CacheEntry are wrapped in StorageLocation.WeakCacheEntry to form a doubly linked list
functioning as a queue which can be interacted with via 3 fields, head, tail, and hand.
Head and tail expectedly mark the beginning and end of the queue, while the hand is the interesting bit and is used
as the position of the current item to consider for eviction the next time reclaim(long) needs to be called.
Entries are also stored in a map, weakCacheEntries, for fast retrieval. Using a weak cache entry sets
StorageLocation.WeakCacheEntry.visited to true, and addWeakReservationHold(CacheEntryIdentifier, Supplier) and
addWeakReservationHoldIfExists(CacheEntryIdentifier) additionally will call
StorageLocation.WeakCacheEntry.hold() until StorageLocation.ReservationHold.close() is called which will call
StorageLocation.WeakCacheEntry.release().
When it is time to reclaim space, first the hand is checked for holds - if any exist then the hand is moved
to StorageLocation.WeakCacheEntry.prev immediately and we try again. If no holds are present, then it is checked if it has
been marked as StorageLocation.WeakCacheEntry.visited - if so then it is unmarked as visited, and the hand moves to
StorageLocation.WeakCacheEntry.prev (allowing this entry to be reclaimed the next time we pass if it has not been visited
again). Lastly, if neither under a hold or marked, the entry will be unlinked from the queue AND unmounted from the
storage location (deleting the files from disk) with unlinkWeakEntry(WeakCacheEntry). This process
is repeated until either a sufficient amount of space has been reclaimed, or no additional space is able to be
reclaimed, in which case the new reservation fails.
There is an auxilary mode for weak references when areWeakEntriesEphemeral is set to true. In this mode, weak
entries are short-lived entries that only exist while one or more reservation hold are active, and are unmounted when
the holds are released. This is useful in cases where entries are unlikely to be re-used such as in asynchronous
tasks.
This class is thread-safe, so that multiple threads can update its state at the same time. One example usage is that a historical server can use multiple threads to load different segments in parallel from deep storage.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classstatic classACloseableCacheEntrywrapper representing both the entry and a 'hold' that is placed on it to prevent the entry from being dropped byreclaim(long)at least until the wrapper is closed.static final classstatic final class -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescription<T extends CacheEntry>
StorageLocation.ReservationHold<T>addWeakReservationHold(CacheEntryIdentifier entryId, Supplier<? extends CacheEntry> entrySupplier) Returns aStorageLocation.ReservationHoldof aCacheEntrywith a 'hold' placed on it, preventing it from being automatically removed byreclaim(long)if theCacheEntryis one ofweakCacheEntriesuntil the hold is released byStorageLocation.ReservationHold.close().<T extends CacheEntry>
StorageLocation.ReservationHold<T>Returns aStorageLocation.ReservationHoldof aCacheEntrywith a 'hold' placed on it, preventing it from being automatically removed byreclaim(long)if theCacheEntryis one ofweakCacheEntriesuntil the hold is released byStorageLocation.ReservationHold.close().longlonglong<T extends CacheEntry>
TgetCacheEntry(CacheEntryIdentifier entryId) If aCacheEntryfor aCacheEntryIdentifierexists in eitherstaticCacheEntriesorweakCacheEntries, this method will return it.getLock()Exposes thelockused by theStorageLocationto allowCacheEntry.mount(StorageLocation)andCacheEntry.unmount()to synchronize operations with this location.getPath()The place where the files are stored<T extends CacheEntry>
TgetStaticCacheEntry(CacheEntryIdentifier entryId) intbooleanisReserved(CacheEntryIdentifier identifier) booleanisWeakReserved(CacheEntryIdentifier identifier) voidrelease(CacheEntry entry) booleanreserve(CacheEntry entry) Reserves space to store the givenCacheEntry, returning true if sucessful and false if already reserved, or unable to be reserved.booleanreserveWeak(CacheEntry entry) Reserves space to store a 'weak' reservation for a givenCacheEntry.voidreset()Unmounts all static and weakly held cache entries and resets stats and size tracking.voidsetAreWeakEntriesEphemeral(boolean areWeakEntriesEphemeral) Sets whether weak cache entries should be retained after all holds are released.
-
Constructor Details
-
StorageLocation
-
-
Method Details
-
getLock
Exposes thelockused by theStorageLocationto allowCacheEntry.mount(StorageLocation)andCacheEntry.unmount()to synchronize operations with this location. Callers MUST pay attention to the type of lock they are using if planning to call any other methods of this class to ensure deadlocks are not possible. -
getPath
The place where the files are stored -
setAreWeakEntriesEphemeral
public void setAreWeakEntriesEphemeral(boolean areWeakEntriesEphemeral) Sets whether weak cache entries should be retained after all holds are released. If true, weak references are removed and unmounted immediately after all holds are released -
getStaticCacheEntry
-
getCacheEntry
If aCacheEntryfor aCacheEntryIdentifierexists in eitherstaticCacheEntriesorweakCacheEntries, this method will return it. Additionally,StorageLocation.WeakCacheEntrywill be marked as visited to reduce the chance that they are evicted during future calls toreclaim(long). -
isReserved
-
isWeakReserved
-
reserve
Reserves space to store the givenCacheEntry, returning true if sucessful and false if already reserved, or unable to be reserved. -
reserveWeak
Reserves space to store a 'weak' reservation for a givenCacheEntry. Returns true if already reserved or was able to be successfully reserved, or false if unable to be reserved. This method is intended for use during 'bootstrapping'. To use weak cache entries in a query engine useaddWeakReservationHold(CacheEntryIdentifier, Supplier)oraddWeakReservationHoldIfExists(CacheEntryIdentifier), which places a hold on cache entries to prevent eviction until the hold is released. -
addWeakReservationHoldIfExists
@Nullable public <T extends CacheEntry> StorageLocation.ReservationHold<T> addWeakReservationHoldIfExists(CacheEntryIdentifier entryId) Returns aStorageLocation.ReservationHoldof aCacheEntrywith a 'hold' placed on it, preventing it from being automatically removed byreclaim(long)if theCacheEntryis one ofweakCacheEntriesuntil the hold is released byStorageLocation.ReservationHold.close(). Callers must call close on the returned object.This method only returns already existing entries, if callers want to insert a new entry if it doesn't already exist, use
addWeakReservationHold(CacheEntryIdentifier, Supplier) -
addWeakReservationHold
@Nullable public <T extends CacheEntry> StorageLocation.ReservationHold<T> addWeakReservationHold(CacheEntryIdentifier entryId, Supplier<? extends CacheEntry> entrySupplier) Returns aStorageLocation.ReservationHoldof aCacheEntrywith a 'hold' placed on it, preventing it from being automatically removed byreclaim(long)if theCacheEntryis one ofweakCacheEntriesuntil the hold is released byStorageLocation.ReservationHold.close(). Callers must call close on the returned object.If the entry already exists, this method will return it, else it will create a new entry if there is space available.
-
release
Removes an item fromstaticCacheEntries, reducingcurrSizeBytesbyCacheEntry.getSize(). If the cache entry exists inweakCacheEntries, it is left in place to be removed byreclaim(long)instead. -
getWeakEntryCount
public int getWeakEntryCount() -
reset
public void reset()Unmounts all static and weakly held cache entries and resets stats and size tracking. Currently only for testing. -
getWeakStats
-
resetStaticStats
-
resetWeakStats
-
availableSizeBytes
public long availableSizeBytes() -
currentSizeBytes
public long currentSizeBytes() -
currentWeakSizeBytes
public long currentWeakSizeBytes()
-