org.hd.d.pg2k.svrCore.datasource
Class ExhibitDataSimpleCache.MetaData

java.lang.Object
  extended by org.hd.d.pg2k.svrCore.datasource.ExhibitDataSimpleCache.MetaData
All Implemented Interfaces:
java.io.ObjectInputValidation, java.io.Serializable
Enclosing class:
ExhibitDataSimpleCache

private static final class ExhibitDataSimpleCache.MetaData
extends java.lang.Object
implements java.io.Serializable, java.io.ObjectInputValidation

Cache meta-data class. Holds information about what exhibit data is cached on disc.

Is serialisable to be able to persist to disc and allow for a fast start-up.

Can be marked read-only to hold the cache in its current state.

This object is completely thread-safe and holds its instance lock to synchronise activity.

The names of all members affecting the state of cached exhibit data and meta-data start with `exhibit'.

All activity that actually affects disc operations must be passed the rwl and it will be held while disc I/O takes place, and most of these operations will throw and IOException. (Note that if the ExhibitDataSimpleCache instance lock must be held as well then it and the rwl must be grabbed in the appropriate order before one of these routines is called.)


Field Summary
private  java.util.Map<java.lang.Object,java.lang.Long> _beingExtended
          Thread-safe Map of which exhibits we are currently extending and when we started extending.
private  Tuple.Triple<java.io.File,java.lang.Long,java.lang.Long> _cFSBHWM_cache
          Cache of estimated usable free space in the underlying cache filesystem; initially null.
private  int _fullyCachedCount
          Cache of estimate of full-cached exhibits; non-negative.
private  java.util.Map<Name.ExhibitFull,ExhibitDataSimpleCache.CachedFile> cachedExhibits
          Set of cached exhibits, from full exhibit name to CachedFile entry; never null after construction/deserialisation.
private  java.util.SortedSet<ExhibitDataSimpleCache.CachedFile> exhibitsLRU
          LRU ordered set of the CachedFile values in cachedExhibits; never null after construction/deserialisation.
private static int MAX_CONC_EXT_WAIT_TIME_MS
          Approximate maximum time to wait for another thread to extend an exhibit cache entry (ms); strictly positive.
private static int MAX_FS_USABLE_SPACE_CACHE_MS
          Maximum time in ms that we may retain a cached 'usable filespace' estimate; strictly positive.
private static int MIN_FS_PERCENT_FREE
          Minimum percentage free in cache filesystem for us to expand the cache; non-negative in range ]100,0].
private  boolean needsSave
          If true, we need a save to disc (ie our state has changed).
private static boolean NEVER_REQUEST_UPSTREAM_CACHEING
          If true, we NEVER ask upstream to cache for us.
private  boolean readWrite
          If true, this cache meta-data is read/write.
private static long serialVersionUID
          My serial ID.
private  long totalBytes
          Estimated total bytes of disc used by cached entries.
private  long totalBytesHighWaterMark
          The highest value of totalBytes, ie the cache actual high-water mark; never negative.
private static boolean TRY_TO_RETAIN_TN_IN_PURGE
          If true then try to retain metadata and thumbnails of exhibits we purge.
private static boolean USE_EXTANT_DISC_ENTRY_ON_CREATE
          If true, when creating cache entry if data found on disc use it rather than refuse to build meta-data entry.
 
Constructor Summary
ExhibitDataSimpleCache.MetaData()
          Build an empty, read-only set of meta-data.
ExhibitDataSimpleCache.MetaData(AllExhibitProperties aepCurrent, java.io.File cacheDir, SimpleLoggerIF logger)
          Build a new meta-data set by examining the given cache directory.
 
Method Summary
private  boolean _exhibitRemoveLRUCacheEntry(java.util.concurrent.locks.ReentrantReadWriteLock rwl, java.io.File cacheDir, Name.ExhibitFull dontRemoveName, boolean justData, SimpleLoggerIF logger, StatsLogger.StatsConfig statsIDSCGEN)
          Remove the least-recently-used exhibit cache item, if any.
private  int _readRawDataStartFromCache(java.util.concurrent.locks.ReentrantReadWriteLock rwl, Name.ExhibitFull name, int dataStart, java.io.File cacheDir, java.nio.ByteBuffer buf, SimpleLoggerIF logger, StatsLogger.StatsConfig statsIDSCGEN)
          Fill as much as possible of the read request from disc cache, returning the number of bytes read; non-negative.
private  void _recomputeDerivedValues()
          This private routine updates all (transient) data derived from the primary cachedExhibits map.
private  void _remove(java.util.concurrent.locks.ReentrantReadWriteLock rwl, Name.ExhibitFull name)
          Remove cached-file details, adjusting cache data in situ; does nothing if not present.
private  void _setTotalBytes(long newTB)
          Set estimated total bytes of disc used by cached entries; never negative.
private  void _update(java.util.concurrent.locks.ReentrantReadWriteLock rwl, ExhibitDataSimpleCache.CachedFile newCf, SimpleLoggerIF logger)
          Update or add new cached-file details, adjusting cache data in situ.
(package private)  boolean canPrecache(java.io.File cacheDir)
          If true, some precaching may be possible, going by our generally-least-strict limit.
(package private)  boolean canPrecacheExhibitData(java.io.File cacheDir)
          If true, we can pre-cache data blocks for (new or existing) exhibits.
(package private)  boolean canPrecacheThumbnails(java.io.File cacheDir)
          If true, we can pre-cache thumbnails for (existing) exhibits.
(package private)  long computeFreeSpaceBelowHighWaterMark(java.io.File cacheDir)
          Compute available free space in cache (bytes); zero or negative if none.
(package private)  long computeFreeSpaceBelowLowWaterMark(java.io.File cacheDir)
          Compute current definite free-space in cache.
(package private)  long computeTargetHighWaterMark()
          Computes the target high-water mark (target maximum cache size); strictly positive.
(package private)  boolean exhibitCreateNewCacheEntry(java.util.concurrent.locks.ReentrantReadWriteLock rwl, java.io.File cacheDir, ExhibitStaticAttr esa, SimpleLoggerIF logger, StatsLogger.StatsConfig statsIDSCGEN)
          Create a new exhibit entry.
(package private)  ExhibitDataSimpleCache.CachedFile exhibitGetInfo(Name.ExhibitFull name)
          Get cached-file details for a given exhibit; null if exhibit not cached.
(package private)  ExhibitThumbnails exhibitGetThumbnails(java.util.concurrent.locks.ReentrantReadWriteLock rwl, java.io.File cacheDir, Name.ExhibitFull name, SimpleLoggerIF logger)
          Get the cached thumbnails for an exhibit, or null if none cached.
(package private)  boolean exhibitIsFullyLoaded(ExhibitStaticAttr esa)
          Check if the exhibit is fully loaded.
(package private)  ExhibitDataSimpleCache.CachedFile exhibitMarkAsAccessed(java.util.concurrent.locks.ReentrantReadWriteLock rwl, Name.ExhibitFull name, SimpleLoggerIF logger, java.io.File cacheDir)
          Mark exhibit as accessed (`touch' it) and returns the possibly-modified CachedFile record.
(package private)  void exhibitRead(java.util.concurrent.locks.ReentrantReadWriteLock rwl, java.lang.String fetchFromPeer, java.io.File cacheDir, Name.ExhibitFull name, SimpleExhibitPipelineIF upstream, AllExhibitImmutableData aeid, GenProps gp, int dataStart, java.nio.ByteBuffer buf, java.lang.Boolean dontCache, SimpleLoggerIF logger, StatsLogger.StatsConfig statsIDSCGEN)
          Reads data for an exhibit into the given buffer.
(package private)  boolean exhibitRemoveCacheEntry(java.util.concurrent.locks.ReentrantReadWriteLock rwl, java.io.File cacheDir, Name.ExhibitFull name, boolean justData, SimpleLoggerIF logger, StatsLogger.StatsConfig statsIDSCGEN)
          Remove an exhibit entry from cache, possibly including all its data and metadata.
(package private)  boolean exhibitSaveThumbnails(java.util.concurrent.locks.ReentrantReadWriteLock rwl, GenProps gp, java.io.File cacheDir, ExhibitStaticAttr esa, ExhibitThumbnails tns, SimpleLoggerIF logger, StatsLogger.StatsConfig statsIDSCGEN)
          Saves the thumbnails for an exhibit.
(package private)  int getFullyCachedCount(AllExhibitProperties aep, boolean force)
          Return estimated count of known-fully-cached exhibits; non-negative.
(package private)  java.util.Set<Name.ExhibitFull> getKnownExhibits()
          Get Set of exhibits on which metadata is currently held in this cache.
(package private)  boolean getNeedsSave()
          Get the 'needs to be saved to disc' value.
(package private)  long getTotalBytesCurrentlyUsedByCache()
          Get estimated total bytes of disc used by cached entries; never negative.
(package private)  long getTotalBytesHighWaterMark()
          Get the highest value of totalBytes, ie the cache actual high-water mark; never negative.
(package private)  boolean isEmpty()
          Is our meta-data store empty, ie no exhibits cached at all?
(package private)  boolean isEquivalent(ExhibitDataSimpleCache.MetaData other)
          Returns true if this metadata is essentially equivalent to another one.
(package private)  boolean isReadWrite()
          Get the `cache-is-read/write' value.
(package private)  boolean lotsFree(java.io.File cacheDir)
          Returns true if we have lots of disc space free.
(package private)  void mergeWithNewMetaData(ExhibitDataSimpleCache.MetaData newData, SimpleLoggerIF logger)
          Install info from new cache object in this one.
(package private)  void purge(java.util.concurrent.locks.ReentrantReadWriteLock rwl, GenProps gp, java.io.File cacheDir, long howMuch, Name.ExhibitFull dontPurgeName, SimpleLoggerIF logger, StatsLogger.StatsConfig statsIDSCGEN)
          Purges the cache of old entries to make space for new, if needed.
private  void readObject(java.io.ObjectInputStream in)
          Deserialise.
(package private)  void saveToDisc(java.io.File cacheDir, SimpleLoggerIF logger, StatsLogger.StatsConfig statsIDSCGEN)
          Save (serialise) to disc; throws IOException in case of difficulty.
(package private)  void setNeedsSave()
          Set the `needs to be saved to disc' value to be true.
(package private)  void setReadWrite(boolean rw)
          Set the `cache-is-read/write' value.
(package private)  int size()
          Get count of cached exhibits, including partially-cached ones; never negative.
(package private)  boolean someFree(java.io.File cacheDir)
          Returns true if we have some (not lots of) disc space free.
 void validateObject()
          Validate fields/state.
private  void writeObject(java.io.ObjectOutputStream oos)
          Write out a less-redundant form of our internal information.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

cachedExhibits

private transient java.util.Map<Name.ExhibitFull,ExhibitDataSimpleCache.CachedFile> cachedExhibits
Set of cached exhibits, from full exhibit name to CachedFile entry; never null after construction/deserialisation. We may like to optimise memory use by sharing the String values (etc) with those from AllExhibitImmutableData held elsewhere.

This is the primary store of data; other (transient) values are derived from it; this is saved to and restored from the serialised form in an efficient and defensive way.

This is a Hashtable for thread-safety.

Compound operations may be made atomic by a lock on this object, but no other lock may be taken while this happens.

Any access that updates this table should be under the instance lock.


exhibitsLRU

private transient java.util.SortedSet<ExhibitDataSimpleCache.CachedFile> exhibitsLRU
LRU ordered set of the CachedFile values in cachedExhibits; never null after construction/deserialisation. This should be exactly the same set as cachedExhibits.valueSet().

The least-recently-accessed items are first in this list, and are the first to be discarded if the cache becomes over-full.

This is not of itself thread-safe and all access must be under the instance lock.


totalBytes

private transient volatile long totalBytes
Estimated total bytes of disc used by cached entries. Computed as sum of estimates from CachedFile values.

Write access restricted to _setTotalBytes(); marked volatile to allow unlocked read access.


totalBytesHighWaterMark

private transient volatile long totalBytesHighWaterMark
The highest value of totalBytes, ie the cache actual high-water mark; never negative. Computed as sum of estimates from CachedFile values.

Write access restricted to _setTotalBytes() and by _setTotalBytesHighWaterMark() and must be under the instance lock.

Marked volatile to allow lock-free read access.


needsSave

private transient volatile boolean needsSave
If true, we need a save to disc (ie our state has changed). Is transient so always false when we recover from disc.

Is volatile (so accessed with no lock) only by setNeedsSave() (to set it true) and saveToDisc() (to clear it after a successful save to disc).


readWrite

private transient volatile boolean readWrite
If true, this cache meta-data is read/write. This can be used to pin the state of the cache while we compare it to on-disc state and/or while we are unsure of its veracity.

Is transient so that it is deserialised as false, and is also false on construction of a new empty MetaData instance; should only be set true after comparing with or recreating from, real disc state.

Is volatile so that it can be read without taking a lock.


USE_EXTANT_DISC_ENTRY_ON_CREATE

private static final boolean USE_EXTANT_DISC_ENTRY_ON_CREATE
If true, when creating cache entry if data found on disc use it rather than refuse to build meta-data entry. This is useful for co-existing with old cache mechanism.

See Also:
Constant Field Values

MIN_FS_PERCENT_FREE

private static final int MIN_FS_PERCENT_FREE
Minimum percentage free in cache filesystem for us to expand the cache; non-negative in range ]100,0]. Set to prevent accidental exhaustion of space in a shared filesystem (eg inducing transient write errors for us or other storage users, etc) due to incorrect usage estimates by us or unexpected use by others, and to avoid very poor performance from a nearly-full filesystem.

A value in the range 1-10 is probably good.

See Also:
Constant Field Values

_cFSBHWM_cache

private transient volatile Tuple.Triple<java.io.File,java.lang.Long,java.lang.Long> _cFSBHWM_cache
Cache of estimated usable free space in the underlying cache filesystem; initially null. Notes the cacheDir and time and free space of the last request.

It is in fact assumed that in general:

Marked volatile for thread-safe unlocked access.


MAX_FS_USABLE_SPACE_CACHE_MS

private static final int MAX_FS_USABLE_SPACE_CACHE_MS
Maximum time in ms that we may retain a cached 'usable filespace' estimate; strictly positive. If the file system in question doesn't contain much activity/data other than our cache, and we are checking mainly to deal gracefully with internal usage-estimation errors and from slowly-accumulated crud from our (and third-party) logs etc, then we could probably cache the value for hours at a time without great loss, but probably cacheing for tens of seconds would in practice eliminate much of the cost.

Pick a prime-ish value to minimise clashes with other activity...

See Also:
Constant Field Values

TRY_TO_RETAIN_TN_IN_PURGE

private static final boolean TRY_TO_RETAIN_TN_IN_PURGE
If true then try to retain metadata and thumbnails of exhibits we purge. Thumbnails in particular may be expensive to regenerate/fetch, and do not take much space.

See Also:
Constant Field Values

NEVER_REQUEST_UPSTREAM_CACHEING

private static final boolean NEVER_REQUEST_UPSTREAM_CACHEING
If true, we NEVER ask upstream to cache for us. If true, we try to avoid churning the master's cache even if it has lots of space, and we are assuming that our local caching is as good as it gets.

If false, we just ask it not to cache our precache requests which do not reflect explicit user requests, and assume that there will still be shared locality between different slaves or that it might be expensive for the master to fetch data.

Note that in either case, if data can be satisfied from the local cache then it will be, and if we have lots of space we might cache locally regardless.

See Also:
Constant Field Values

MAX_CONC_EXT_WAIT_TIME_MS

private static final int MAX_CONC_EXT_WAIT_TIME_MS
Approximate maximum time to wait for another thread to extend an exhibit cache entry (ms); strictly positive.


_beingExtended

private transient java.util.Map<java.lang.Object,java.lang.Long> _beingExtended
Thread-safe Map of which exhibits we are currently extending and when we started extending. Used to help reduce the probability of redundant concurrent fetches of the same data by multiple threads.

The key is a unique (new) String of the full exhibit name.

We notify on this key object instance when removing an entry.


serialVersionUID

private static final long serialVersionUID
My serial ID.

See Also:
Constant Field Values

_fullyCachedCount

private transient volatile int _fullyCachedCount
Cache of estimate of full-cached exhibits; non-negative. Private to getFullyCachedCount().

Marked volatile to allow thread-safe lock-free access.

Initially zero to force recomputation.

Not serialised.

Constructor Detail

ExhibitDataSimpleCache.MetaData

ExhibitDataSimpleCache.MetaData()
Build an empty, read-only set of meta-data.


ExhibitDataSimpleCache.MetaData

ExhibitDataSimpleCache.MetaData(AllExhibitProperties aepCurrent,
                                java.io.File cacheDir,
                                SimpleLoggerIF logger)
                          throws java.io.IOException
Build a new meta-data set by examining the given cache directory. This is understood not to be perfect, because, for example, the last-accessed time may not be available on disc and we may have to approximate with an available last-modified-time; generally this is used when:
  1. no persisted MetaData value is available, and we have to do the best we can, or,
  2. we want to load a copy of what is on disc to check that what we have in memory is not badly wrong.

No locks (ie especially the rwl or cache's instance lock) should be held while this is running.

This does not modify the disc.

The constructed object is marked as needing to be saved.

This relies in part on being able to find the data files for the cached (prefixes of) exhibits by their valid full exhibit names.

We do also explicitly attempt to recover any plausible entries corresponding to current AEP entries.

Thus we may miss entries which have no current data file, eg because we had zero bytes cached for that file, and may have to recover such data later as we run across it.

We do also explicitly attempt to recover any plausible entries corresponding to current AEP entries.

Parameters:
aepCurrent - reasonably current AEP as a hint for entries to look for; never null
cacheDir - the cache top-level directory; never null
logger - to log to; never null
Throws:
java.io.IOException - in case of major problems in reconstructing the cache state (minor problems will be ignored)
Method Detail

getKnownExhibits

java.util.Set<Name.ExhibitFull> getKnownExhibits()
Get Set of exhibits on which metadata is currently held in this cache. This takes a private atomic copy of the Set of exhibits for which we have some data, thumbnails, etc, in the cache.


getTotalBytesCurrentlyUsedByCache

long getTotalBytesCurrentlyUsedByCache()
Get estimated total bytes of disc used by cached entries; never negative.


_setTotalBytes

private void _setTotalBytes(long newTB)
Set estimated total bytes of disc used by cached entries; never negative.


getTotalBytesHighWaterMark

long getTotalBytesHighWaterMark()
Get the highest value of totalBytes, ie the cache actual high-water mark; never negative.


_recomputeDerivedValues

private void _recomputeDerivedValues()
This private routine updates all (transient) data derived from the primary cachedExhibits map. This is used after deserialisation, construction or insertion where it is easier to recompute such derived data from scratch than change it incrementally as usual.


getNeedsSave

boolean getNeedsSave()
Get the 'needs to be saved to disc' value. Always false after deserialisation and construction of a new instance.


setNeedsSave

void setNeedsSave()
Set the `needs to be saved to disc' value to be true.


saveToDisc

void saveToDisc(java.io.File cacheDir,
                SimpleLoggerIF logger,
                StatsLogger.StatsConfig statsIDSCGEN)
          throws java.io.IOException
Save (serialise) to disc; throws IOException in case of difficulty. Holds a lock on the metaData object while the save takes place; clears needsSave (to false) if the save appears to be successful.

FIXME: see if this and writeObject() should simply make the object read-only for the duration

Parameters:
cacheDir - specified the top-level cache directory; never null
Throws:
java.io.IOException

isReadWrite

boolean isReadWrite()
Get the `cache-is-read/write' value. Always false after deserialisation and after construction of a new instance.


setReadWrite

void setReadWrite(boolean rw)
Set the `cache-is-read/write' value. Only the cache-checking routines should call this at all.

Insists on grabbing the instance lock to block changes to this without the instance lock held.


size

int size()
Get count of cached exhibits, including partially-cached ones; never negative.


isEmpty

boolean isEmpty()
Is our meta-data store empty, ie no exhibits cached at all?


exhibitGetInfo

ExhibitDataSimpleCache.CachedFile exhibitGetInfo(Name.ExhibitFull name)
Get cached-file details for a given exhibit; null if exhibit not cached. This may incrementally verify cache data against the disc copy, though for performance reasons this may not happen very often.

This is thread-safe and does not need nor grab any cache locks, but to ensure this data remains valid during any compound operation, at least a read lock should usually be obtained.

Parameters:
name - the exhibit whose meta-data is required; never null

exhibitIsFullyLoaded

boolean exhibitIsFullyLoaded(ExhibitStaticAttr esa)
Check if the exhibit is fully loaded.

This does not grab any cache locks, but to ensure this data remains valid during any compound operation, at least a read lock should generally be obtained.

Parameters:
esa - the exhibit whose meta-data is required; never null
Returns:
false if no such exhibit or it is not fully loaded

_remove

private void _remove(java.util.concurrent.locks.ReentrantReadWriteLock rwl,
                     Name.ExhibitFull name)
Remove cached-file details, adjusting cache data in situ; does nothing if not present. The argument must not be null. Private to this instance.

Does not check the read/write status; should be checked before this is called.

Cache write lock must be held by current thread.


_update

private void _update(java.util.concurrent.locks.ReentrantReadWriteLock rwl,
                     ExhibitDataSimpleCache.CachedFile newCf,
                     SimpleLoggerIF logger)
Update or add new cached-file details, adjusting cache data in situ. The argument must not be null. Private to this instance.

Does not check the read/write status; should be checked before this is called.

Marks the meta-data as needing to be saved.

Cache write lock must be held by current thread.


isEquivalent

boolean isEquivalent(ExhibitDataSimpleCache.MetaData other)
Returns true if this metadata is essentially equivalent to another one. This has a sufficiently loose notion to allow for discrepancies in (for example) last-accessed timestamps which cannot be completely reconstructed from the disc copy, but vital differences are noted.

The result is false if the argument is null.


mergeWithNewMetaData

void mergeWithNewMetaData(ExhibitDataSimpleCache.MetaData newData,
                          SimpleLoggerIF logger)
                    throws java.lang.IllegalStateException
Install info from new cache object in this one. This would allow us to incorporate the results of a disc scan to see the actual state of the disc. (Usually the argument is the best-efforts reconstruction from the disc of the cache state, with the timestamps arbitrarily too old.)

This essentially throws away the old state and replaces it with that passed in, though this may do things such as retain the best notion of last-accessed timestamp from both.

Both this and the newData objects are locked for the duration of this operation.

The readWrite status is not altered or updated by this operation but needsSave may be; therefore both objects must be read-only before this is called.

Only the cache-checking routines should call this at all.

Throws:
java.lang.IllegalStateException

exhibitMarkAsAccessed

ExhibitDataSimpleCache.CachedFile exhibitMarkAsAccessed(java.util.concurrent.locks.ReentrantReadWriteLock rwl,
                                                        Name.ExhibitFull name,
                                                        SimpleLoggerIF logger,
                                                        java.io.File cacheDir)
                                                  throws java.io.IOException
Mark exhibit as accessed (`touch' it) and returns the possibly-modified CachedFile record. Returns null if the named exhibit does not exist in the cache at all, else never returns null.

This call does not access disc (ie affects in-memory status only), and silently does nothing if there is no entry for the named exhibit.

If this metadata not read-write, this action is silently vetoed as it is assumed not to be of vital importance.

This marks the last-accessed time in the MetaData as now, to be preserved on disc at some point in the future.

This MetaData object is marked as needing to be saved if an exhibit was `touched' successfully.

This is preferably used to:

This holds a write lock on the cache while updating state.

Parameters:
cacheDir - if not null then we force an update of a timestamp on disc as a backup in case the serialised metadata is lost; this causes extra disc traffic though not necessarily synchronous
Throws:
java.io.IOException

_exhibitRemoveLRUCacheEntry

private boolean _exhibitRemoveLRUCacheEntry(java.util.concurrent.locks.ReentrantReadWriteLock rwl,
                                            java.io.File cacheDir,
                                            Name.ExhibitFull dontRemoveName,
                                            boolean justData,
                                            SimpleLoggerIF logger,
                                            StatsLogger.StatsConfig statsIDSCGEN)
                                     throws java.io.IOException
Remove the least-recently-used exhibit cache item, if any. We won't remove the given named item if non-null; this may prevent us removing anything if it is the only cached item.

If the named item is the oldest then we'll remove the next oldest, if there is one.

Parameters:
justData - if true then we try to retain metadata/thumbnails
Returns:
true if we removed something
Throws:
java.io.IOException

exhibitRemoveCacheEntry

boolean exhibitRemoveCacheEntry(java.util.concurrent.locks.ReentrantReadWriteLock rwl,
                                java.io.File cacheDir,
                                Name.ExhibitFull name,
                                boolean justData,
                                SimpleLoggerIF logger,
                                StatsLogger.StatsConfig statsIDSCGEN)
                          throws java.io.IOException
Remove an exhibit entry from cache, possibly including all its data and metadata. Returns true if successful, false if not.

This will fail if the metaData is read only, or if an entry for the exhibit does not exist in the metadata and on disc.

Since these failures will be by returning false rather than by causing an exception then this can be used as a gentle unconditional way to make sure that an entry does not exist whether or not one did before.

This needs to access disc and so will need to hold the main write lock while it does so, grabbing the metaData instance lock inside the main lock where both need to be held simultaneously.

Can optionally attempt to just remove the exhibit data, leaving metadata and any thumbnails intact.

Parameters:
rwl - the main cache lock object; must not be null
justData - if true then we try to retain metadata/thumbnails
Throws:
java.io.IOException

exhibitCreateNewCacheEntry

boolean exhibitCreateNewCacheEntry(java.util.concurrent.locks.ReentrantReadWriteLock rwl,
                                   java.io.File cacheDir,
                                   ExhibitStaticAttr esa,
                                   SimpleLoggerIF logger,
                                   StatsLogger.StatsConfig statsIDSCGEN)
                             throws java.io.IOException
Create a new exhibit entry. Returns true if successful, false if not.

This will fail if the metaData is read only, or if an entry for the exhibit already exists in the metaData or on disc.

Since these failures will be by returning false rather than by causing an exception then this can be used as a gentle unconditional way to make sure that an entry does exist whether or not one did before.

This needs to access disc and so will need to grab a write lock on the main cache lock while it does so, grabbing the metaData instance lock inside the main lock where both need to be held simultaneously.

Marks the meta-data as needing to be saved if a new meta-data entry had to be created...

Parameters:
rwl - the main lock object; must not be null
esa - the basic info on the exhibit to have an entry created
Throws:
java.io.IOException - in case of serious problems accessing the on-disc cache state

computeTargetHighWaterMark

long computeTargetHighWaterMark()
Computes the target high-water mark (target maximum cache size); strictly positive. If we currently only have a default (zero-timestamp) genProps then we use the initial size of the cache as our high-water mark, ie do not allow the cache to expand.

We may further restict cache size to leave a given percentage free in the underlying filesystem.


computeFreeSpaceBelowLowWaterMark

long computeFreeSpaceBelowLowWaterMark(java.io.File cacheDir)
Compute current definite free-space in cache. This returns the amount of space that we have below the low-water mark; if this returns a positive number then the cache is within that low water mark and can be considered nowhere near full.

If we don't trust the GenProps value then the low-water mark is the current actual high-water mark for the cache, ie we try to maintain its size approximately.

Is synchronized to maintain consistency while working.


lotsFree

boolean lotsFree(java.io.File cacheDir)
Returns true if we have lots of disc space free. This means that usage is well below the low-water mark.

If we don't trust GenProps this always returns false.


someFree

boolean someFree(java.io.File cacheDir)
Returns true if we have some (not lots of) disc space free. This means that usage is below the low-water mark.

If we don't trust GenProps this always returns false.


computeFreeSpaceBelowHighWaterMark

long computeFreeSpaceBelowHighWaterMark(java.io.File cacheDir)
Compute available free space in cache (bytes); zero or negative if none. This ignores the purge state of the system and simply reports what space is available before the cache overflows.

This is thread-safe though may be expensive.


canPrecacheExhibitData

boolean canPrecacheExhibitData(java.io.File cacheDir)
If true, we can pre-cache data blocks for (new or existing) exhibits. POLICY: only true if we have (lots of) free space and the cache is read/write, and the server-slowdown factor is no greater than 2 (ie moderate or absent).


canPrecacheThumbnails

boolean canPrecacheThumbnails(java.io.File cacheDir)
If true, we can pre-cache thumbnails for (existing) exhibits. POLICY: only true if the free space is enough to store another thumbnail and fetch the data to do so first if necessary and the cache is read/write.

Basically we're prepared to go right up to the wire to generate thumbnails because they are so useful to the user.

We leave a little bit of wiggle room on space.


canPrecache

boolean canPrecache(java.io.File cacheDir)
If true, some precaching may be possible, going by our generally-least-strict limit. We will only allow precaching if we have a valid LocalProps value.


purge

void purge(java.util.concurrent.locks.ReentrantReadWriteLock rwl,
           GenProps gp,
           java.io.File cacheDir,
           long howMuch,
           Name.ExhibitFull dontPurgeName,
           SimpleLoggerIF logger,
           StatsLogger.StatsConfig statsIDSCGEN)
     throws java.io.IOException
Purges the cache of old entries to make space for new, if needed. This will do nothing unless the space used by the cache is above the low-water mark. We compute the low-water mark from GenProps, or from the actual high-water mark in the current use of the cache if the passed GenProps is the default (has a zero timestamp). (We attempt to roughly maintain the cache or possibly run it down slightly while waiting for GenProps to arrive.)

This will avoid purging the cache of the item passed to it by name in case it was a candidate for removal.

If the argument is zero this tries to ensure that space for at least one new (empty) exhibit cache entry to be created.

If greater than zero this tries to ensure that an existing cache entry can be extended by at least the given number of bytes (either for the exhibit data or for thumbnail data).

This grabs the cache write lock and instance lock.

This will fail if the cache is marked read-only.

Parameters:
howMuch - howMuch space we need to ensure is free; positive
Throws:
java.io.IOException

exhibitRead

void exhibitRead(java.util.concurrent.locks.ReentrantReadWriteLock rwl,
                 java.lang.String fetchFromPeer,
                 java.io.File cacheDir,
                 Name.ExhibitFull name,
                 SimpleExhibitPipelineIF upstream,
                 AllExhibitImmutableData aeid,
                 GenProps gp,
                 int dataStart,
                 java.nio.ByteBuffer buf,
                 java.lang.Boolean dontCache,
                 SimpleLoggerIF logger,
                 StatsLogger.StatsConfig statsIDSCGEN)
           throws java.io.IOException
Reads data for an exhibit into the given buffer. This will complain with an IOException if an attempt is made to read beyond the bounds of the exhibit, or if data is unavailable for any reason, or if the read is far too long to be sensibly handled, else the requested chunk of data is read into the caller's buffer.

This will extend the underlying cache entry if necessary (and possible) to satisfy the read, and may also apply read-ahead to maximise user-perceived performance.

If the metaData is read-only, then any (portion of the) read that cannot be satisfied from the cache is passed back up the pipeline.

This needs to access disc and so will need to hold the rwl while it does so, grabbing the metaData instance lock inside the rwl where both need to be held simultaneously.

Note that we control caching to suit our precaching and any downstream precache/random activity, so at this level we have a 3-way choice.

This may only mark a cache entry as accessed if dontCache is FALSE and we actually read from or add data to the cache, though we may mark it as updated at other times too.

Whenever we (easily) know that we can satisfy the request from cache, we only take a read lock to improve concurrency.

We return as soon as we have satisfied some part of the request so as minimise internal copying of data, etc.

Parameters:
rwl - the main cache lock object; must not be null
fetchFromPeer - if non-null and we need to extend the cache then we will try to do so from the mirror with the given tag
dontCache - if FALSE, then cache here if possible and ask upstream to cache; if null then cache locally but not upstream (this is our precaching activity); if TRUE then don't cache here or upstream (this is downstream precaching or random activity); note therefore that we ask upstream to cache unless dontCache is FALSE
Throws:
java.io.IOException - in case of serious problems accessing the on-disc cache state or if request is out of bounds of underlying exhibit or too big to handle

_readRawDataStartFromCache

private int _readRawDataStartFromCache(java.util.concurrent.locks.ReentrantReadWriteLock rwl,
                                       Name.ExhibitFull name,
                                       int dataStart,
                                       java.io.File cacheDir,
                                       java.nio.ByteBuffer buf,
                                       SimpleLoggerIF logger,
                                       StatsLogger.StatsConfig statsIDSCGEN)
                                throws java.io.IOException
Fill as much as possible of the read request from disc cache, returning the number of bytes read; non-negative. This is done grabbing a read lock on the entire cache, but no exclusive lock so that we can do multiple concurrent reads, ie so that we can queue concurrent reads at the OS/disc level for maximum throughput.

Likely to be heavily used, so efficiency is important here.

Throws:
java.io.IOException

exhibitGetThumbnails

ExhibitThumbnails exhibitGetThumbnails(java.util.concurrent.locks.ReentrantReadWriteLock rwl,
                                       java.io.File cacheDir,
                                       Name.ExhibitFull name,
                                       SimpleLoggerIF logger)
                                 throws java.io.IOException
Get the cached thumbnails for an exhibit, or null if none cached. This needs to access disc and so will need to hold the main cache while it does so, grabbing the metaData instance lock inside the main lock where both need to be held simultaneously.

If a problem is encountered deserialising thumbnails, the cache is not-read-only, and AUTO_REPAIR_DURING_IO is true, we may zap the offending serialised file to try to recreate it later.

We will need to hold a write lock if updating timestamps when accessing the thumbnails; this may greatly reduce concurrency.

Parameters:
rwl - the main cache lock object; must not be null
Throws:
java.io.IOException - in case of serious problems accessing the on-disc cache state

exhibitSaveThumbnails

boolean exhibitSaveThumbnails(java.util.concurrent.locks.ReentrantReadWriteLock rwl,
                              GenProps gp,
                              java.io.File cacheDir,
                              ExhibitStaticAttr esa,
                              ExhibitThumbnails tns,
                              SimpleLoggerIF logger,
                              StatsLogger.StatsConfig statsIDSCGEN)
                        throws java.io.IOException
Saves the thumbnails for an exhibit. Returns true if successful, false if not.

This will fail if the metaData is read only.

If the thumbnails argument is null, this will purge any extant thumbnails for this exhibit.

This will create a new zero-length exhibit entry if necessary.

Since these failures will be by returning false rather than by causing an exception then this can be used as a gentle unconditional way to make sure that an entry does exist whether or not one did before.

This needs to access disc and so will need to hold the main lock while it does so, grabbing the metaData instance lock inside the main lock where both need to be held simultaneously.

Note that this will have to grab a write lock.

Parameters:
rwl - the main lock object; must not be null
esa - the basic info on the exhibit to have an entry created
Throws:
java.io.IOException - in case of serious problems accessing the on-disc cache state

writeObject

private void writeObject(java.io.ObjectOutputStream oos)
                  throws java.io.IOException
Write out a less-redundant form of our internal information. Prevent (lazy-evaluation-caused) state changes while serialising by being synchronized.

The more-efficient on-the-wire format also makes defensive reading easier.

Throws:
java.io.IOException

readObject

private void readObject(java.io.ObjectInputStream in)
                 throws java.io.IOException,
                        java.lang.ClassNotFoundException
Deserialise.

Throws:
java.io.IOException
java.lang.ClassNotFoundException

validateObject

public void validateObject()
                    throws java.io.InvalidObjectException
Validate fields/state. Called in the constructor and possibly after de-serialising.

Barf if something bad is found. (Maybe allow some extra info in debug version.)

Assumes _recomputeDerivedValues() has been called before this is called since deserialisation or construction.

Specified by:
validateObject in interface java.io.ObjectInputValidation
Throws:
java.io.InvalidObjectException

getFullyCachedCount

int getFullyCachedCount(AllExhibitProperties aep,
                        boolean force)
Return estimated count of known-fully-cached exhibits; non-negative. It would be wise to force recomputation when a new AEP is loaded, or after a precacheing round is complete, or after any other major change in cache status.

Note that since the cached count is not serialised with the metadata then it will need to be recomputed when metadata is loaded/deserialised.

Even without a recomputation being forced, we may decide to do one if it seems that the value might be stale.

This will take time O(n) for an n-exhibit AEP to (re)compute its result, but does minimal or no locking, and none for the duration of the method, so is safe to launch in a background thread for example.

May be expensive (continually recomputing) if/while no exhibit is fully locally cached, but this is assumed to be unlikely in practice.

Parameters:
aep - if non-null, allow recomputation against this AEP
force - if true, force immediate recomputation against this AEP if non-null
Returns:
the estimate of exhibits whose data is entirely cached locally; the count does not take account of locally-recreatable data such as thumbnails, and may be too low or too high

DHD Multimedia Gallery V1.57.21

Copyright (c) 1996-2011, Damon Hart-Davis. All rights reserved.