// The `wasi:keyvalue/cache` interface defines the operations of a single
// instance of a "cache", which is a non-durable, weakly-consistent key-value
// store. "Non-durable" means that caches are allowed and expected to
// arbitrarily discard key-value entries. "Weakly-consistent" means that there
// are essentially no guarantees that operations will agree on their results: a
// get following a set may not observe the set value; multiple gets may observe
// different previous set values; etc. The only guarantee is that values are
// not materialized "out of thin air": if a `get` returns a value, that value
// was passed to a `set` operation at some point in time in the past.
// Additionally, caches MUST make a best effort to respect the supplied
// Time-to-Live values (within the usual limitations around time in a
// distributed setting).
interface cache {
use wasi:io/poll@0.2.3.{pollable};
use types.{key, incoming-value, outgoing-value, error};
// The `get` operation returns the value passed by a previous `set` for the
// same key within the given TTL or none if there is no such value.
get: func(k: key) -> future-get-result;
// This block defines a special resource type used by `get` to emulate
// `future<result<option<incoming-value>,error>>`. In the return value
// of the `get` method, the outer `option` returns `none` when the pollable
// is not yet ready and the inner `option` returns `none` when the
// requested key wasn't present.
resource future-get-result {
future-get-result-get: func() -> option<result<option<incoming-value>, error>>;
listen-to-future-get-result: func() -> pollable;
}
// The `exists` operation returns whether a value was previously `set` for
// the given key within the TTL.
exists: func(k: key) -> future-exists-result;
// This block defines a special resource type used by `exists` to emulate
// `future<result<bool,error>>`.
resource future-exists-result {
future-exists-result-get: func() -> option<result<bool, error>>;
listen-to-future-exists-result: func() -> pollable;
}
// The `set` operation sets the given value for the given key for the given
// time-to-live (TTL) duration, if supplied, specified in milliseconds. If
// a TTL is not supplied, the key may be kept indefinitely (as-if a very
// large TTL were used). If the key is already present in the cache, the
// value is updated in-place. In the common case of computing and caching a
// value if the given key is not already in the cache, consider using
// `get-or-set` (below) intead of separate `get` and `set` operations.
set: func(k: key, v: borrow<outgoing-value>, TTL-ms: option<u32>) -> future-result;
// This block defines a special resource type used by `set` and `delete` to
// emulate `future<result<_,error>>`.
resource future-result {
future-result-get: func() -> option<result<_, error>>;
listen-to-future-result: func() -> pollable;
}
// The `get-or-set` operation asynchronously returns one of two cases
// enumerated by `get-or-set-entry`: in the `occupied` case, the given key
// already has a value present in the cache; in the `vacant` case, there
// was no value and the caller should write a value into the returned
// `vacancy`. This operation allows multiple concurrent `get-or-set`
// invocations to rendezvous such that only one invocation receives the
// `vacant` result while all other invocations wait until the vacancy is
// filled before receiving an `occupied` result. Implementations are not
// required to implement this rendezvous or to rendezvous in all possible
// cases.
variant get-or-set-entry {
occupied(incoming-value),
vacant(vacancy)
}
get-or-set: func(k: key) -> future-get-or-set-result;
// This block defines a special resource type used by `get-or-set` to
// emulate `future<result<get-or-set-entry,error>>`.
resource future-get-or-set-result {
future-get-or-set-result-get: func() -> option<result<get-or-set-entry, error>>;
listen-to-future-get-or-set-result: func() -> pollable;
}
// The following block defines the `vacancy` resource type. (When resource
// types are added, the `u32` type aliases can be replaced by proper
// `resource` types.) When the caller of `get-or-set` receives a `vacancy`,
// they must either call the `fill` method or drop the `vacancy` to
// indicate an error that prevents calling `fill`. An implementation MAY
// have a timeout that drops a vacancy that hasn't been filled in order
// to unblock other waiting `get-or-set` callers.
resource vacancy {
vacancy-fill: func(TTL-ms: option<u32>) -> outgoing-value;
}
// The `delete` operation removes any value with the given key from the
// cache. Like all cache operations, `delete` is weakly ordered and thus
// concurrent `get` calls may still see deleted keys for a period of time.
// Additionally, due to weak ordering, concurrent `set` calls for the same
// key may or may not get deleted.
delete: func(k: key) -> future-result;
}