Skip to content

Commit 9cde2eb

Browse files
authored
feat(*): major updates to the keyvalue interfaces (#30)
1 parent 0bce169 commit 9cde2eb

File tree

13 files changed

+574
-469
lines changed

13 files changed

+574
-469
lines changed

.github/workflows/main.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ jobs:
1313
- uses: actions/checkout@v3
1414
- name: ensure `./wit/deps` are in sync
1515
run: |
16-
curl -Lo 'wit-deps' https://github.com/bytecodealliance/wit-deps/releases/download/v0.3.3/wit-deps-x86_64-unknown-linux-musl
16+
curl -Lo 'wit-deps' https://github.com/bytecodealliance/wit-deps/releases/download/v0.3.5/wit-deps-x86_64-unknown-linux-musl
1717
chmod +x wit-deps
1818
./wit-deps lock --check
19-
- uses: WebAssembly/wit-abi-up-to-date@v16
19+
- uses: WebAssembly/wit-abi-up-to-date@v17
2020
with:
21-
worlds: 'keyvalue keyvalue-handle-watch'
22-
wit-bindgen: '0.13.0'
21+
worlds: 'imports keyvalue-handle-watch'
22+
wit-bindgen: '0.16.0'

README.md

Lines changed: 72 additions & 291 deletions
Large diffs are not rendered by default.

keyvalue.md renamed to imports.md

Lines changed: 146 additions & 49 deletions
Large diffs are not rendered by default.

keyvalue-handle-watch.md

Lines changed: 142 additions & 51 deletions
Large diffs are not rendered by default.

wit/atomic.wit

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
/// A keyvalue interface that provides atomic operations.
2+
///
3+
/// Atomic operations are single, indivisible operations. When a fault causes
4+
/// an atomic operation to fail, it will appear to the invoker of the atomic
5+
/// operation that the action either completed successfully or did nothing
6+
/// at all.
27
interface atomic {
38
/// A keyvalue interface that provides atomic operations.
49
use types.{bucket, error, key};
@@ -9,12 +14,18 @@ interface atomic {
914
/// If the key does not exist in the bucket, it creates a new key-value pair
1015
/// with the value set to the given delta.
1116
///
12-
/// If any other error occurs, it returns an error.
17+
/// If any other error occurs, it returns an `Err(error)`.
1318
increment: func(bucket: borrow<bucket>, key: key, delta: u64) -> result<u64, error>;
1419

15-
/// Atomically compare and swap the value associated with the key in the bucket.
16-
/// It returns a boolean indicating if the swap was successful.
20+
/// Compare-and-swap (CAS) atomically updates the value associated with the key
21+
/// in the bucket if the value matches the old value. This operation returns
22+
/// `Ok(true)` if the swap was successful, `Ok(false)` if the value did not match,
23+
///
24+
/// A successful CAS operation means the current value matched the `old` value
25+
/// and was replaced with the `new` value.
1726
///
18-
/// If the key does not exist in the bucket, it returns an error.
27+
/// If the key does not exist in the bucket, it returns `Ok(false)`.
28+
///
29+
/// If any other error occurs, it returns an `Err(error)`.
1930
compare-and-swap: func(bucket: borrow<bucket>, key: key, old: u64, new: u64) -> result<bool, error>;
2031
}

wit/batch.wit

Lines changed: 0 additions & 27 deletions
This file was deleted.

wit/error.wit

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1-
interface wasi-cloud-error {
1+
interface wasi-keyvalue-error {
22
/// An error resource type for keyvalue operations.
3+
///
4+
/// Common errors:
5+
/// - Connectivity errors (e.g. network errors): when the client cannot establish
6+
/// a connection to the keyvalue service.
7+
/// - Authentication and Authorization errors: when the client fails to authenticate
8+
/// or does not have the required permissions to perform the operation.
9+
/// - Data errors: when the client sends incompatible or corrupted data.
10+
/// - Resource errors: when the system runs out of resources (e.g. memory).
11+
/// - Internal errors: unexpected errors on the server side.
12+
///
313
/// Currently, this provides only one function to return a string representation
414
/// of the error. In the future, this will be extended to provide more information
515
/// about the error.

wit/eventual-batch.wit

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/// A keyvalue interface that provides eventually consistent batch operations.
2+
///
3+
/// A batch operation is an operation that operates on multiple keys at once.
4+
///
5+
/// Batch operations are useful for reducing network round-trip time. For example,
6+
/// if you want to get the values associated with 100 keys, you can either do 100 get
7+
/// operations or you can do 1 batch get operation. The batch operation is
8+
/// faster because it only needs to make 1 network call instead of 100.
9+
///
10+
/// A batch operation does not guarantee atomicity, meaning that if the batch
11+
/// operation fails, some of the keys may have been modified and some may not.
12+
/// Transactional operations are being worked on and will be added in the future to
13+
/// provide atomicity.
14+
///
15+
/// Data consistency in a key value store refers to the gaurantee that once a
16+
/// write operation completes, all subsequent read operations will return the
17+
/// value that was written.
18+
///
19+
/// The level of consistency in batch operations is **eventual consistency**, the same
20+
/// with the readwrite interface. This interface does not guarantee strong consistency,
21+
/// meaning that if a write operation completes, subsequent read operations may not return
22+
/// the value that was written.
23+
interface eventual-batch {
24+
/// A keyvalue interface that provides batch get operations.
25+
use types.{bucket, error, key, incoming-value, outgoing-value};
26+
27+
/// Get the values associated with the keys in the bucket. It returns a list of
28+
/// incoming-value that can be consumed to get the value associated with the key.
29+
///
30+
/// If any of the keys do not exist in the bucket, it returns a `none` value for
31+
/// that key in the list.
32+
///
33+
/// Note that the key-value pairs are guaranteed to be returned in the same order
34+
///
35+
/// MAY show an out-of-date value if there are concurrent writes to the bucket.
36+
///
37+
/// If any other error occurs, it returns an `Err(error)`.
38+
get-many: func(bucket: borrow<bucket>, keys: list<key>) -> result<list<option<incoming-value>>, error>;
39+
40+
/// Get all the keys in the bucket. It returns a list of keys.
41+
///
42+
/// Note that the keys are not guaranteed to be returned in any particular order.
43+
///
44+
/// If the bucket is empty, it returns an empty list.
45+
///
46+
/// MAY show an out-of-date list of keys if there are concurrent writes to the bucket.
47+
///
48+
/// If any error occurs, it returns an `Err(error)`.
49+
keys: func(bucket: borrow<bucket>) -> result<list<key>, error>;
50+
51+
/// Set the values associated with the keys in the bucket. If the key already
52+
/// exists in the bucket, it overwrites the value.
53+
///
54+
/// Note that the key-value pairs are not guaranteed to be set in the order
55+
/// they are provided.
56+
///
57+
/// If any of the keys do not exist in the bucket, it creates a new key-value pair.
58+
///
59+
/// If any other error occurs, it returns an `Err(error)`. When an error occurs, it
60+
/// does not rollback the key-value pairs that were already set. Thus, this batch operation
61+
/// does not guarantee atomicity, implying that some key-value pairs could be
62+
/// set while others might fail.
63+
///
64+
/// Other concurrent operations may also be able to see the partial results.
65+
set-many: func(bucket: borrow<bucket>, key-values: list<tuple<key, borrow<outgoing-value>>>) -> result<_, error>;
66+
67+
/// Delete the key-value pairs associated with the keys in the bucket.
68+
///
69+
/// Note that the key-value pairs are not guaranteed to be deleted in the order
70+
/// they are provided.
71+
///
72+
/// If any of the keys do not exist in the bucket, it skips the key.
73+
///
74+
/// If any other error occurs, it returns an `Err(error)`. When an error occurs, it
75+
/// does not rollback the key-value pairs that were already deleted. Thus, this batch operation
76+
/// does not guarantee atomicity, implying that some key-value pairs could be
77+
/// deleted while others might fail.
78+
///
79+
/// Other concurrent operations may also be able to see the partial results.
80+
delete-many: func(bucket: borrow<bucket>, keys: list<key>) -> result<_, error>;
81+
}

wit/eventual.wit

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/// A keyvalue interface that provides eventually consistent CRUD operations.
2+
///
3+
/// A CRUD operation is an operation that acts on a single key-value pair.
4+
///
5+
/// The value in the key-value pair is defined as a `u8` byte array and the intention
6+
/// is that it is the common denominator for all data types defined by different
7+
/// key-value stores to handle data, ensuring compatibility between different
8+
/// key-value stores. Note: the clients will be expecting serialization/deserialization overhead
9+
/// to be handled by the key-value store. The value could be a serialized object from
10+
/// JSON, HTML or vendor-specific data types like AWS S3 objects.
11+
///
12+
/// Data consistency in a key value store refers to the gaurantee that once a
13+
/// write operation completes, all subsequent read operations will return the
14+
/// value that was written.
15+
///
16+
/// The level of consistency in readwrite interfaces is **eventual consistency**,
17+
/// which means that if a write operation completes successfully, all subsequent
18+
/// read operations will eventually return the value that was written. In other words,
19+
/// if we pause the updates to the system, the system eventually will return
20+
/// the last updated value for read.
21+
interface eventual {
22+
/// A keyvalue interface that provides simple read and write operations.
23+
use types.{bucket, error, incoming-value, key, outgoing-value};
24+
25+
/// Get the value associated with the key in the bucket.
26+
///
27+
/// The value is returned as an option. If the key-value pair exists in the
28+
/// bucket, it returns `Ok(value)`. If the key does not exist in the
29+
/// bucket, it returns `Ok(none)`.
30+
///
31+
/// If any other error occurs, it returns an `Err(error)`.
32+
get: func(bucket: borrow<bucket>, key: key) -> result<option<incoming-value>, error>;
33+
34+
/// Set the value associated with the key in the bucket. If the key already
35+
/// exists in the bucket, it overwrites the value.
36+
///
37+
/// If the key does not exist in the bucket, it creates a new key-value pair.
38+
///
39+
/// If any other error occurs, it returns an `Err(error)`.
40+
set: func(bucket: borrow<bucket>, key: key, outgoing-value: borrow<outgoing-value>) -> result<_, error>;
41+
42+
/// Delete the key-value pair associated with the key in the bucket.
43+
///
44+
/// If the key does not exist in the bucket, it does nothing.
45+
///
46+
/// If any other error occurs, it returns an `Err(error)`.
47+
delete: func(bucket: borrow<bucket>, key: key) -> result<_, error>;
48+
49+
/// Check if the key exists in the bucket.
50+
///
51+
/// If the key exists in the bucket, it returns `Ok(true)`. If the key does
52+
/// not exist in the bucket, it returns `Ok(false)`.
53+
///
54+
/// If any other error occurs, it returns an `Err(error)`.
55+
exists: func(bucket: borrow<bucket>, key: key) -> result<bool, error>;
56+
}

wit/handle-watch.wit

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
/// A keyvalue interface that provides handle-watch operations.
2+
///
3+
/// This interface is used to provide event-driven mechanisms to handle
4+
/// keyvalue changes.
25
interface handle-watch {
36
/// A keyvalue interface that provides handle-watch operations.
47
use types.{bucket, key, incoming-value};
58

6-
/// Handle the set event for the given bucket and key.
7-
/// It returns a incoming-value that can be consumed to get the value.
9+
/// Handle the `set` event for the given bucket and key.
10+
/// It returns a `incoming-value` that represents the new value being set.
11+
/// The new value can be consumed by the handler.
812
on-set: func(bucket: bucket, key: key, incoming-value: borrow<incoming-value>);
913

10-
/// Handle the delete event for the given bucket and key.
14+
/// Handle the `delete` event for the given bucket and key.
15+
/// It returns a `key` that represents the key being deleted.
1116
on-delete: func(bucket: bucket, key: key);
1217
}

0 commit comments

Comments
 (0)