// 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.0-rc-2023-11-10.{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,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. type future-get-result = u32; drop-future-get-result: func(f: future-get-result); future-get-result-get: func(f: future-get-result) -> option, error>>; listen-to-future-get-result: func(f: future-get-result) -> 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>`. type future-exists-result = u32; drop-future-exists-result: func(f: future-exists-result); future-exists-result-get: func(f: future-exists-result) -> option>; listen-to-future-exists-result: func(f: future-exists-result) -> 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: outgoing-value, TTL-ms: option) -> future-result; // This block defines a special resource type used by `set` and `delete` to // emulate `future>`. type future-result = u32; drop-future-result: func(f: future-result); future-result-get: func(f: future-result) -> option>; listen-to-future-result: func(f: future-result) -> 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>`. type future-get-or-set-result = u32; drop-future-get-or-set-result: func(f: future-get-or-set-result); future-get-or-set-result-get: func(f: future-get-or-set-result) -> option>; listen-to-future-get-or-set-result: func(f: future-get-or-set-result) -> 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. type vacancy = u32; drop-vacancy: func(v: vacancy); vacancy-fill: func(v: vacancy, TTL-ms: option) -> 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; }