Class DiskPatternClipCache
Disk-backed IPatternClipCache: persists each computed S-101 pattern-fill priority clip result (see MapsuiDisplayListRenderer's PatternPriorityClipper) as a WKB sidecar file so that the cold first open of a previously-seen cell — including after a process restart — skips the multi-second NetTopologySuite overlay.
public sealed class DiskPatternClipCache : IPatternClipCache
- Inheritance
-
DiskPatternClipCache
- Implements
- Inherited Members
Remarks
The in-memory InMemoryPatternClipCache (step 1) only eliminates re-clip cost for re-renders of the same already-open dataset (e.g. Day/Dusk/Night palette switches). It cannot help the very first open of a cell — nothing is cached yet — and its state is lost on close/restart. This implementation closes that gap by persisting the clip geometry to disk.
The clip geometry is palette-independent (the palette only recolours
the raster tiles applied after clipping), so it is safe to persist
and reuse across palette/display re-renders. To make the on-disk key globally
unique — the GetOrCompute(string, Func<IReadOnlyList<(string PatternRef, int Priority, Geometry Geometry)>>) contract's key is only unique
within one processor's single in-memory slot — the S-101 processor composes a
fully-qualified key {datasetScope}|{portrayalKey} whose
datasetScope deterministically encodes the dataset content hash, the
clip parameters, the CRS, and the cache FormatVersion. Any
change to dataset content, clip parameters, or the serialization format
therefore yields a different filename and recomputes (auto-invalidation).
Robustness: any IO error, truncated/corrupt file, or FormatVersion mismatch is treated as a miss (the factory runs and overwrites the entry); failures never propagate to the caller. Writes are atomic (temp file + move) so a crash mid-write cannot leave a half-written entry that later deserializes incorrectly.
The cache is bounded by a total-bytes cap enforced with a least-recently-used eviction policy (see DiskCacheBudget). The cache directory is shared across every S-101 processor, so all instance methods are thread-safe; hits read and deserialize without a lock.
Constructors
DiskPatternClipCache(string, long)
Creates a disk-backed pattern-clip cache rooted at
cacheDirectory.
public DiskPatternClipCache(string cacheDirectory, long maxBytes)
Parameters
cacheDirectorystringDirectory under which clip sidecar files are stored. Created on first write if it does not exist. The directory is assumed to be private to this cache (the LRU sweep enumerates every
*.clipfile in it).maxByteslongSoft upper bound, in bytes, on the total size of all persisted clip files. After a write that exceeds it, the least-recently-used files are evicted until the total is at or below this cap. Must be positive.
Exceptions
- ArgumentException
cacheDirectoryis null or empty.- ArgumentOutOfRangeException
maxBytesis not positive.
Fields
FormatVersion
Version stamp for the on-disk serialization frame. It is written into
every cache file and verified on read; a mismatch is treated as a miss.
The S-101 processor also folds this value into the datasetScope
component of the cache key, so bumping it both renames future files and
rejects stale ones. Increment whenever the serialization frame or the
clip algorithm changes in a way that invalidates persisted geometry.
public const int FormatVersion = 1
Field Value
Properties
Hits
Number of GetOrCompute(string, Func<IReadOnlyList<(string PatternRef, int Priority, Geometry Geometry)>>) calls served from the cache (the expensive clip overlay was skipped). Exposed for diagnostics and tests.
public long Hits { get; }
Property Value
MaxBytes
Soft upper bound, in bytes, on the total size of the persisted entries.
public long MaxBytes { get; }
Property Value
Misses
Number of GetOrCompute(string, Func<IReadOnlyList<(string PatternRef, int Priority, Geometry Geometry)>>) calls that ran the factory (cache miss). Exposed for diagnostics and tests.
public long Misses { get; }
Property Value
TotalBytes
The total size, in bytes, of the persisted entries. The first call reads the cache directory if no write has done so yet.
public long TotalBytes { get; }
Property Value
Methods
Contains(string)
Whether an entry is persisted for key. Checks only
that the file exists: it neither reads nor validates the entry, and does
not mark it used.
public bool Contains(string key)
Parameters
keystringA key as passed to GetOrCompute(string, Func<IReadOnlyList<(string PatternRef, int Priority, Geometry Geometry)>>).
Returns
GetOrCompute(string, Func<IReadOnlyList<(string PatternRef, int Priority, Geometry Geometry)>>)
Returns the cached clipped pattern geometry for key,
invoking factory to compute and store it on a miss.
public IReadOnlyList<(string PatternRef, int Priority, Geometry Geometry)> GetOrCompute(string key, Func<IReadOnlyList<(string PatternRef, int Priority, Geometry Geometry)>> factory)
Parameters
keystringAn opaque key that fully identifies the clip inputs (for S-101 this is the mariner + ECDIS display-state portrayal cache key). The same key must always map to the same clip result.
factoryFunc<IReadOnlyList<(string PatternRef, int Priority, Geometry Geometry)>>Computes the clipped pattern geometry when the key is not cached. Only invoked on a miss.
Returns
- IReadOnlyList<(string PatternRef, int Priority, Geometry Geometry)>
The clipped pattern entries, each carrying its palette-independent pattern reference, drawing priority, and clipped geometry. On a hit the exact cached instances are returned.