A read that finds no .meta file keeps nothing in memory, so the
existing test no longer reaches the step that keeps a type StoreVariant
put there. This one writes a .meta file with a different content type
after the store, as one not yet rewritten by it would hold, and checks
that the read leaves the stored type in memory.
Model: opus-5-5
VariantStorage.LoadWithMeta now returns an empty content type when the
.meta file is missing or unreadable, and GetVariant serves
application/octet-stream in that case without keeping it in memory.
Memory now only ever holds a content type read from a .meta file or
passed to StoreVariant, so a read that ran before a store wrote the
.meta file can no longer leave the wrong type in memory, however it
interleaves with the store, other reads and eviction.
Model: opus-5-5
A read that finds a variant in memory but cannot open its file removes
it from memory. When that happens after StoreVariant has added the
variant's content type, a read that opened the variant file before the
store wrote its .meta file finds memory empty and keeps
application/octet-stream there, so every later hit serves the image
with it. The test runs the store, the failed read and the read without
a .meta file in that order, then checks a later hit. It fails now.
Model: opus-5-5
Lookup again counts a variant as present only when its file exists.
Treating a variant held in memory as present saved one check of the
disk, but no test covered it, and GetVariant opens the file anyway.
Model: opus-5-5
GetVariant now adds the content type it read from a .meta file only
when memory holds none for the variant, so a type StoreVariant added
meanwhile is not replaced. A read that found no .meta file yet still
gets application/octet-stream for that one request, as before this
change, but no longer leaves it in memory for later hits.
Model: opus-5-5
A GetVariant that begins before StoreVariant finishes can find the
variant file but not yet its .meta file, and so reads
application/octet-stream. When it adds that to memory after the store
added the real type, the wrong type is served to every later hit. The
part of GetVariant that runs after its check of memory moves, unchanged,
into loadVariantWithMeta, so the test can run it after a store. The
test fails now.
Model: opus-5-5
Cache.metaCache was declared and never used, so every hit read and
parsed the variant's .meta file. It is now an LRU of up to 10,000
content types (hashicorp/golang-lru/v2), filled by StoreVariant and by
GetVariant after it reads a .meta file. For a variant it holds, Lookup
skips the disk check and GetVariant skips the .meta read; the variant
file is still opened and its size taken from it. Eviction removes the
entry before deleting the files, and GetVariant removes it when the
file will not open, so a missing variant is never served. The cap is a
constant, not a setting. README.md describes it.
Model: opus-5-5
Tests for keeping each variant's content type in memory. A second hit
must still get the stored content type after the variant's .meta file
is deleted, whether the first came from storing the variant or from
reading it after a restart; this fails now. A variant removed by
EvictToLimit, or whose file was deleted from disk, must be a miss and
must not be served, and concurrent stores, reads and evictions run
under the race detector; these pass now and guard the change.
Model: opus-5-5