wasm_snapshot_store (wasm v0.3.0)
View SourceA directory of snapshot images, keyed by what makes one valid.
Shaped on wasm_code_cache, which is the existing precedent for a build
artifact kept on disk and looked up by identity: a flat directory named by app
env, absent meaning off, one file per key, write to a temporary name and
rename, and a total size past which the oldest go. The policy itself is
wasm_file_cache, shared with that module.
application:set_env(wasm, snapshot_dir, "/var/cache/wasm/images").Off unless that is set, and the directory is as trusted as your release.
That is the same concession wasm_code_cache makes, and it carries further
here: a cache entry is code, which a release already trusts, while an image is
guest state laid into a live runtime. What bounds the damage is that every
field is validated on the way in and a table slot may name only a function the
module has, which is containment rather than authentication.
What the key covers, and the one thing it deliberately does not
An image is a runtime after init() ran against a particular environment,
so the key has to cover the environment and not only the module. It is the
module hash, the format's own ABI, the adapter's version, and the adapter's
compatibility key -- and that last one is where a preopened directory, an
argument list or a set of environment variables has to be accounted for. An
adapter that leaves it undefined cannot be cached, because there would be
nothing distinguishing two images captured from different worlds.
It does not cover the OTP release, the emulator flavour or the machine's
architecture, all three of which wasm_code_cache:key/6 includes. That is the
difference between the two artifacts rather than an oversight: a .beam is
genuinely specific to an emulator, while an image is bytes, integers and
indices, and one that would not load on another machine could not be moved.
Summary
Functions
Where images live, or undefined, which means the store is off.
The key an image is filed under.
The image filed under this key, for a module the caller names.
The cap in force, in bytes.
Remove every image, and every half-written one.
File an image, or do nothing.
Functions
-spec dir() -> undefined | file:filename().
Where images live, or undefined, which means the store is off.
-spec key(binary(), binary(), term(), pos_integer()) -> binary() | undefined.
The key an image is filed under.
undefined when the adapter supplied no compatibility key, which the caller
must read as "do not cache this" rather than as a key of its own.
-spec lookup(binary() | undefined, wasm:module_()) -> {ok, wasm:snapshot()} | miss.
The image filed under this key, for a module the caller names.
Every failure is a miss. A corrupt file, one written by another build, one
naming another module: none of them is an error, because the caller's answer to
all of them is the same and it is to capture instead. wasm_code_cache states
that contract for its own reads; this one keeps it.
-spec max_bytes() -> non_neg_integer().
The cap in force, in bytes.
Resolved on every store through application:get_env/3, so a change is in
force from the next one and there is nothing cached to invalidate at boot. It
is reported rather than left implicit because a setting nobody can read back is
a setting nobody can tell is being used. wasm_jit's resolve_max_heap_words
and wasm_jit:compile_limits/0 exist for the same reason.
A value that cannot be a size -- negative, a float, an atom -- answers the
default and warns once. Taking it literally would mean a cap of 0 deleting
every image on the next store.
-spec purge() -> ok.
Remove every image, and every half-written one.
For tests, and for a release that wants a clean start -- and for an operator
who has just lowered max_snapshot_dir_bytes and wants the directory to shrink
now rather than at the next store.
-spec store(binary() | undefined, wasm:snapshot(), term()) -> ok.
File an image, or do nothing.
Answers ok whatever happens, because a store that failed is a miss next time
and there is nothing a caller could usefully do about it. An unwritable
directory should not fail a worker that has a perfectly good image in memory.