org.hd.d.pg2k.svrCore.datasource.simpleCache
Class CachedFile

java.lang.Object
  extended by org.hd.d.pg2k.svrCore.datasource.simpleCache.CachedFile
All Implemented Interfaces:
java.io.ObjectInputValidation, java.io.Serializable, java.lang.Cloneable, java.lang.Comparable<CachedFile>

final class CachedFile
extends java.lang.Object
implements java.lang.Comparable<CachedFile>, java.io.Serializable, java.io.ObjectInputValidation, java.lang.Cloneable

Object representing one (partially) cached file on disc. This is immutable, serialisable, and totally ordered.

The natural sort order is LRU (Least-Recently Used) first, with ties (which should be very rare) broken by increasing cached length (ignoring thumbnails, etc) (to represent the cost expended getting the data to cache), and then exhibit name.

This carries the minimum that need be known about each file on disc.

The item is immutable to avoid causing difficulties when already inserted in a sorted collection.

We store the timestamp of the original source exhibit file; if it doesn't match the current exhibit timestamp then this cache entry and its cached data has to be regarded as invalidated and discarded.

Package-visible only.


Field Summary
private static boolean _TE_USE_CLONE
          If true, touchedEntry() used clone() rather than a constructor.
(package private)  long cachedLength
          The initial portion cached on disc (bytes); never negative.
(package private)  long lastAccessed
          The time last written or read; non-negative.
(package private) static int MAX_EMPTY_ENTRY_BYTES_ON_DISC
          Rough estimate of maximum space required for new empty cache entry.
(package private)  Name.ExhibitFull name
          The official name of the exhibit; never null and always a valid exhibit name.
private static long serialVersionUID
          My serialisation version number.
(package private)  long timestamp
          The master-exhibit timestamp; strictly positive.
(package private)  int tnBytes
          The size of the serialised thumbnail object, zero if none; never negative.
 
Constructor Summary
private CachedFile(Name.ExhibitFull _name, long _ts, long _len, long _lastA, int _tnBytes)
          Creates a raw entry given all the data about the entry.
 
Method Summary
(package private)  long calcDiscSpace()
          Calculate the disc space taken up by this exhibit cache entry all told.
private  CachedFile cloneMe()
          Clone the object; does not throw CloneNotSupportedException.
 int compareTo(CachedFile other)
          Total ordering: oldest first, then smallest first, then by name.
 boolean equals(java.lang.Object o)
          Equality relies on comparison, ie on last-access time, cached length and name.
(package private)  CachedFile extendCacheFile(java.io.File cacheDir, long dataStart, java.nio.ByteBuffer data)
          Extend given cache file on disc and return new CachedFile.
(package private)  CachedFile fixup(CachedFile rec, SimpleLoggerIF logger)
          Fixes-up in-memory cached meta-data for exhibit with that from disc.
(package private)  CachedFile getCachedData(java.io.File cacheDir, int start, java.nio.ByteBuffer buf, boolean quick)
          Return data chunk from cached file in the result argument.
(package private) static long getCachedDataLength(java.io.File cacheDir, Name.ExhibitFull exhibitName)
          Recovers the actual on-disc cached exhibit prefix length, or 0 if not present.
 long getLastAccessed()
          The time last written or read; non-negative.
(package private)  ExhibitThumbnails getThumbnails(java.io.File cacheDir)
          Returns thumbnails; never null.
 int hashCode()
          The hash depends on the timestamp.
(package private)  boolean hasThumbnails()
          Do we have thumbnails? True if the thumbnails file is non-zero length.
(package private)  boolean isEquivalent(CachedFile other)
          Returns true if this exhibit's metadata is essentially equivalent to another one.
(package private) static CachedFile makeNewDiscCacheFile(java.io.File cacheDir, Name.ExhibitFull name, long exhibitStamp)
          Make a new file on disc and return its CachedFile; never null.
private  void readObject(java.io.ObjectInputStream in)
          Deserialise.
(package private) static CachedFile recoverExtantCachedFileDetails(java.io.File cacheDir, Name.ExhibitFull exhibitName)
          Recovers an approximate entry for an extant cached file; never null.
(package private)  CachedFile saveThumbnails(java.io.File cacheDir, ExhibitThumbnails tns)
          Add a thumbnail file and return a new in-memory cache entry.
 java.lang.String toString()
          Generate human-readable summary of state.
(package private)  CachedFile touchedEntry()
          Make touched cache file entry.
(package private)  CachedFile touchedEntry(long newLastAccessedTimestamp)
          Make touched cache file entry.
 void validateObject()
          Validate fields/state.
(package private)  CachedFile zapData(java.io.File cacheDir)
          Remove any exhibit data and return a new in-memory cache entry.
(package private)  void zapMe(java.io.File cacheDir)
          Used to zap my disc files, including all auxiliary files for this exhibit.
(package private)  CachedFile zapThumbnails(java.io.File cacheDir)
          Remove any thumbnail file and return a new in-memory cache entry.
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
 

Field Detail

name

final Name.ExhibitFull name
The official name of the exhibit; never null and always a valid exhibit name.


timestamp

final long timestamp
The master-exhibit timestamp; strictly positive.


cachedLength

final long cachedLength
The initial portion cached on disc (bytes); never negative.


lastAccessed

long lastAccessed
The time last written or read; non-negative. We will use setLastModified(System.currentTimeMillis()) to enforce our notion of `now', since the filesystem may be mounted from a remote server with a different clock to ours.

We only do the setLastModified() when writing to the filesystem anyway, or in the special case of reading the first byte of an exhibit. We do this to save (synchronous) disc traffic updating timestamps when in fact this should all be in the metadata and is only needed if that is lost for some reason.

Logically final, but made mutable for touchedEntry() to be able to overwrite in a cloned copy.

May be zero if only metadata but no exhibit data is present.


tnBytes

final int tnBytes
The size of the serialised thumbnail object, zero if none; never negative.


_TE_USE_CLONE

private static final boolean _TE_USE_CLONE
If true, touchedEntry() used clone() rather than a constructor.

See Also:
Constant Field Values

MAX_EMPTY_ENTRY_BYTES_ON_DISC

static final int MAX_EMPTY_ENTRY_BYTES_ON_DISC
Rough estimate of maximum space required for new empty cache entry. This assumes a maximum-length exhibit name and no data nor thumbnail for the exhibit.

This should approximately match what calcDiscSpace() should produce for such an exhibit, but the values may not be exactly the same.


serialVersionUID

private static final long serialVersionUID
My serialisation version number.

See Also:
Constant Field Values
Constructor Detail

CachedFile

private CachedFile(Name.ExhibitFull _name,
                   long _ts,
                   long _len,
                   long _lastA,
                   int _tnBytes)
            throws java.lang.IllegalArgumentException
Creates a raw entry given all the data about the entry. The name must be a syntactically-correct exhibit name.

Should not be called directly from outside the class.

Throws:
java.lang.IllegalArgumentException
Method Detail

getLastAccessed

public long getLastAccessed()
The time last written or read; non-negative. May be zero if no exhibit data is cached.


isEquivalent

boolean isEquivalent(CachedFile other)
Returns true if this exhibit's metadata is essentially equivalent to another one. This insists that everything but the last-accessed timestamp is correct.

The result is false if the argument is null.


hasThumbnails

boolean hasThumbnails()
Do we have thumbnails? True if the thumbnails file is non-zero length. Does not prove that we can load and/or use the thumbnail file even if this returns true.


getThumbnails

final ExhibitThumbnails getThumbnails(java.io.File cacheDir)
                               throws java.io.IOException
Returns thumbnails; never null. In case of difficulty, eg if thumbnails do not exist or cannot be deserialised, throws IOException.

We're fairly dumb about this, assuming that all arguments have been validated.

Throws:
java.io.IOException

getCachedData

CachedFile getCachedData(java.io.File cacheDir,
                         int start,
                         java.nio.ByteBuffer buf,
                         boolean quick)
                   throws java.io.IOException
Return data chunk from cached file in the result argument. This file must live in the usual place, in CACHE_EXDATA_DIR, and the name must be a syntactically-correct exhibit name.

We touch the file (set its stamp to 'now') to show that it has been used iff we retrieve the first byte otherwise we rely on the in-memory metadata to hold the last access time; this is a belt-and-braces measure in case we have to reconstruct the metadata from the disc cache for some reason.

This will throw an IOException or IllegalArgumentException if it cannot find the file or there is some other problem.

We're fairly dumb about this, assuming that everything has been checked elsewhere.

Parameters:
quick - be as fast as possible, eg don't update timestamps
Throws:
java.io.IOException

getCachedDataLength

static long getCachedDataLength(java.io.File cacheDir,
                                Name.ExhibitFull exhibitName)
Recovers the actual on-disc cached exhibit prefix length, or 0 if not present. Can be used to double-check the on-disc cached data length before adjusting it, but may be slow since it requires a real disc access. Use sparingly.

All arguments must be validated and safe before calling this routine; for speed it does no further validation.

Parameters:
cacheDir - non-null directory containing cache; never null
exhibitName - name of exhibit; syntactically valid, non-null
Returns:
length cached on disc; 0 if no data cached for this exhibit, eg cache file is absent

fixup

CachedFile fixup(CachedFile rec,
                 SimpleLoggerIF logger)
Fixes-up in-memory cached meta-data for exhibit with that from disc. Reconstructs a set of details for the exhibit from disc, makes sure that the record of the cached length and timestamps is OK, and returns a new record if not (else the original is returned).

In particular this returns a new item if:

This instance is not altered, nor is the disc-based data.

Does not access disc/filesystem.

TODO: Possibly discard all cached data for an exhibit with a changed timestamp.

Parameters:
rec - the meta-data as reconstructed from disc; never null

recoverExtantCachedFileDetails

static CachedFile recoverExtantCachedFileDetails(java.io.File cacheDir,
                                                 Name.ExhibitFull exhibitName)
                                          throws java.io.IOException
Recovers an approximate entry for an extant cached file; never null. This file must live in the usual place, in CACHE_EXDATA_DIR, and the name must be a syntactically-correct exhibit name.

This will throw an IOException or IllegalArgumentException if it cannot find the file or other data that it needs.

This does not adjust the in-memory records, nor alter anything on disc.

Returns:
synthesised cache record; never null
Throws:
java.io.IOException

touchedEntry

CachedFile touchedEntry()
Make touched cache file entry. This returns a new object identical to the old (this) one except that the last-accessed stamp is set to the current time of day.

This does not alter anything on disc.


touchedEntry

CachedFile touchedEntry(long newLastAccessedTimestamp)
Make touched cache file entry. This returns a new object identical to the old (this) one except that the last-accessed stamp is set to the time of day passed in (usually the current time of day).

This does not alter anything on disc.

This could construct a new object, but to save time and avoid the heavy lifting in the constructor, this uses clone().

Parameters:
newLastAccessedTimestamp - time to make touched version of descriptor with, strictly positive

cloneMe

private CachedFile cloneMe()
Clone the object; does not throw CloneNotSupportedException.


makeNewDiscCacheFile

static CachedFile makeNewDiscCacheFile(java.io.File cacheDir,
                                       Name.ExhibitFull name,
                                       long exhibitStamp)
                                throws java.io.IOException
Make a new file on disc and return its CachedFile; never null. This is passed the case base dir, the name of the exhibit to have a cache entry created, and the timestamp of the master exhibit itself.

No zero-length cache entry is created.

No thumbnail is created; any extant one is expunged.

This does not adjust the in-memory records.

Throws:
java.io.IOException

extendCacheFile

CachedFile extendCacheFile(java.io.File cacheDir,
                           long dataStart,
                           java.nio.ByteBuffer data)
                     throws java.io.IOException
Extend given cache file on disc and return new CachedFile. This is passed the cache base dir, the name of the exhibit to have a cache entry created, the start point of the new data and the data itself, which must be more than zero length.

Note that though the new data should normally be exactly at the end of the existing data, it is not an error, though probably inefficient, to start writing before the end of the existing data, since that indicates wasted effort re-cacheing data we already have.

It is an error to start writing at a point beyond the end of the existing cached data since we don't support "sparse" data and on some operating systems (eg UNIX) the gaps would be filled with zeros which we probably don't want.

If there is an overlap with the existing data, the old (overlapped) data is overwritten silently with the new. This may allow us to update parts in-situ to fix errors, and to silently handle partly-overlapping concurrent updates.

The cache file is extended with (the non-overlapping part of) the given data.

This does not adjust the in-memory records.

This must only be called when other cache write activity (such as removing entries) is locked out to avoid possible file corruption.

Throws:
java.io.IOException

zapThumbnails

CachedFile zapThumbnails(java.io.File cacheDir)
Remove any thumbnail file and return a new in-memory cache entry. This just zaps any thumbnail file and sets the thumbnail length to zero.

This does not mark the entry as updated on disc nor in the new record.

This does not adjust the in-memory records itself.


zapData

CachedFile zapData(java.io.File cacheDir)
Remove any exhibit data and return a new in-memory cache entry. This just zaps any exhibit data file and records the cached length as zero in the returned value.

This attempts to force a deletion even if the file is not obviously present, just to make best efforts to purge it, and we whinge (on System.err) if we cannot make it go away.

This does not mark the entry as updated on disc nor in the new record.

This does not adjust the in-memory records itself.


saveThumbnails

CachedFile saveThumbnails(java.io.File cacheDir,
                          ExhibitThumbnails tns)
                    throws java.io.IOException
Add a thumbnail file and return a new in-memory cache entry. This is not allowed if we already think we have a thumbnail or if there is a thumbnail file already on disc.

The thumbnail argument must be non-null.

This does not mark the entry as updated on disc or in the new record.

This does not adjust the in-memory records itself.

Throws:
java.io.IOException

equals

public final boolean equals(java.lang.Object o)
Equality relies on comparison, ie on last-access time, cached length and name.

Overrides:
equals in class java.lang.Object

hashCode

public final int hashCode()
The hash depends on the timestamp. Two objects can only be equal if their timestamps and cached lengths are.

Overrides:
hashCode in class java.lang.Object

compareTo

public final int compareTo(CachedFile other)
Total ordering: oldest first, then smallest first, then by name.

Specified by:
compareTo in interface java.lang.Comparable<CachedFile>

calcDiscSpace

final long calcDiscSpace()
Calculate the disc space taken up by this exhibit cache entry all told. This guesses a little for overheads such as the directory entry, rounding for allocation space on disc, etc, and aims to be slightly conservative.

This assumes a roughly UFS-like (UNIX File System) pattern of disc usage.


zapMe

final void zapMe(java.io.File cacheDir)
Used to zap my disc files, including all auxiliary files for this exhibit. Quietly ignores any errors.

This does not adjust the in-memory records.


toString

public java.lang.String toString()
Generate human-readable summary of state.

Overrides:
toString in class java.lang.Object

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.)

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

DHD Multimedia Gallery V1.60.69

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