diff --git a/imports.md b/imports.md index ca31a78..103db60 100644 --- a/imports.md +++ b/imports.md @@ -23,20 +23,50 @@ the common denominator for all data types defined by different key-value stores ensuring compatibility between different key-value stores. Note: the clients will be expecting serialization/deserialization overhead to be handled by the key-value store. The value could be a serialized object from JSON, HTML or vendor-specific data types like AWS S3 objects.

-

Data consistency in a key value store refers to the guarantee that once a write operation -completes, all subsequent read operations will return the value that was written.

-

Any implementation of this interface must have enough consistency to guarantee "reading your -writes." In particular, this means that the client should never get a value that is older than -the one it wrote, but it MAY get a newer value if one was written around the same time. These -guarantees only apply to the same client (which will likely be provided by the host or an -external capability of some kind). In this context a "client" is referring to the caller or -guest that is consuming this interface. Once a write request is committed by a specific client, -all subsequent read requests by the same client will reflect that write or any subsequent -writes. Another client running in a different context may or may not immediately see the result -due to the replication lag. As an example of all of this, if a value at a given key is A, and -the client writes B, then immediately reads, it should get B. If something else writes C in -quick succession, then the client may get C. However, a client running in a separate context may -still see A or B

+

Consistency

+

An implementation of this interface MUST be eventually consistent, but is not required to +provide any consistency guaranteeds beyond that. Practically speaking, eventual consistency is +among the weakest of consistency models, guaranteeing only that values will not be produced +"from nowhere", i.e. any value read is guaranteed to have been written to that key at some +earlier time. Beyond that, there are no guarantees, and thus a portable component must neither +expect nor rely on anything else.

+

In the future, additional interfaces may be added to wasi:keyvalue with stronger guarantees, +which will allow components to express their requirements by importing whichever interface(s) +provides matching (or stronger) guarantees. For example, a component requiring strict +serializability might import a (currently hypothetical) strict-serializable-store interface +with a similar signature to store but with much stronger semantic guarantees. On the other +end, a host might either support implementations of both the store and +strict-serializable-store or just the former, in which case the host would immediately reject +a component which imports the unsupported interface.

+

Here are a few examples of behavior which a component developer might wish to rely on but which +are NOT guaranteed by an eventually consistent system (e.g. a distributed system composed of +multiple replicas, each of which may receive writes in a different order, making no attempt to +converge on a global consensus):

+ +

Durability

+

This interface does not currently make any hard guarantees about the durability of values +stored. A valid implementation might rely on an in-memory hash table, the contents of which are +lost when the process exits. Alternatively, another implementation might synchronously persist +all writes to disk -- or even to a quorum of disk-backed nodes at multiple locations -- before +returning a result for a set call. Finally, a third implementation might persist values +asynchronously on a best-effort basis without blocking set calls, in which case an I/O error +could occur after the component instance which originally made the call has exited.

+

Future versions of wasi:keyvalue may provide ways to query and control the durability and +consistency provided by the backing implementation.


Types

variant error

@@ -74,7 +104,7 @@ there are no more keys to fetch.

resource bucket

A bucket is a collection of key-value pairs. Each key-value pair is stored as a entry in the bucket, and the bucket itself acts as a collection of all these entries.

-

It is worth noting that the exact terminology for bucket in key-value stores can very +

It is worth noting that the exact terminology for bucket in key-value stores can vary depending on the specific implementation. For example:

  1. Amazon DynamoDB calls a collection of key-value pairs a table
  2. @@ -85,7 +115,13 @@ depending on the specific implementation. For example:

  3. Memcached calls a collection of key-value pairs a slab
  4. Azure Cosmos DB calls a collection of key-value pairs a container
-

In this interface, we use the term bucket to refer to a collection of key-value pairs

+

In this interface, we use the term bucket to refer to a connection to a collection of +key-value pairs.

+

Note that opening two bucket resources using the same identifier MAY result in connections +to two separate replicas in a distributed database, and that writes to one of those +resources are not guaranteed to be readable from the other resource promptly (or ever, in +the case of a replica failure or message reordering). See the Consistency section of the +store interface documentation for details.

Functions

open: func

Get the bucket with the specified identifier.

diff --git a/watch-service.md b/watch-service.md index a65115a..05d90bf 100644 --- a/watch-service.md +++ b/watch-service.md @@ -21,20 +21,50 @@ the common denominator for all data types defined by different key-value stores ensuring compatibility between different key-value stores. Note: the clients will be expecting serialization/deserialization overhead to be handled by the key-value store. The value could be a serialized object from JSON, HTML or vendor-specific data types like AWS S3 objects.

-

Data consistency in a key value store refers to the guarantee that once a write operation -completes, all subsequent read operations will return the value that was written.

-

Any implementation of this interface must have enough consistency to guarantee "reading your -writes." In particular, this means that the client should never get a value that is older than -the one it wrote, but it MAY get a newer value if one was written around the same time. These -guarantees only apply to the same client (which will likely be provided by the host or an -external capability of some kind). In this context a "client" is referring to the caller or -guest that is consuming this interface. Once a write request is committed by a specific client, -all subsequent read requests by the same client will reflect that write or any subsequent -writes. Another client running in a different context may or may not immediately see the result -due to the replication lag. As an example of all of this, if a value at a given key is A, and -the client writes B, then immediately reads, it should get B. If something else writes C in -quick succession, then the client may get C. However, a client running in a separate context may -still see A or B

+

Consistency

+

An implementation of this interface MUST be eventually consistent, but is not required to +provide any consistency guaranteeds beyond that. Practically speaking, eventual consistency is +among the weakest of consistency models, guaranteeing only that values will not be produced +"from nowhere", i.e. any value read is guaranteed to have been written to that key at some +earlier time. Beyond that, there are no guarantees, and thus a portable component must neither +expect nor rely on anything else.

+

In the future, additional interfaces may be added to wasi:keyvalue with stronger guarantees, +which will allow components to express their requirements by importing whichever interface(s) +provides matching (or stronger) guarantees. For example, a component requiring strict +serializability might import a (currently hypothetical) strict-serializable-store interface +with a similar signature to store but with much stronger semantic guarantees. On the other +end, a host might either support implementations of both the store and +strict-serializable-store or just the former, in which case the host would immediately reject +a component which imports the unsupported interface.

+

Here are a few examples of behavior which a component developer might wish to rely on but which +are NOT guaranteed by an eventually consistent system (e.g. a distributed system composed of +multiple replicas, each of which may receive writes in a different order, making no attempt to +converge on a global consensus):

+ +

Durability

+

This interface does not currently make any hard guarantees about the durability of values +stored. A valid implementation might rely on an in-memory hash table, the contents of which are +lost when the process exits. Alternatively, another implementation might synchronously persist +all writes to disk -- or even to a quorum of disk-backed nodes at multiple locations -- before +returning a result for a set call. Finally, a third implementation might persist values +asynchronously on a best-effort basis without blocking set calls, in which case an I/O error +could occur after the component instance which originally made the call has exited.

+

Future versions of wasi:keyvalue may provide ways to query and control the durability and +consistency provided by the backing implementation.


Types

variant error

@@ -72,7 +102,7 @@ there are no more keys to fetch.

resource bucket

A bucket is a collection of key-value pairs. Each key-value pair is stored as a entry in the bucket, and the bucket itself acts as a collection of all these entries.

-

It is worth noting that the exact terminology for bucket in key-value stores can very +

It is worth noting that the exact terminology for bucket in key-value stores can vary depending on the specific implementation. For example:

  1. Amazon DynamoDB calls a collection of key-value pairs a table
  2. @@ -83,7 +113,13 @@ depending on the specific implementation. For example:

  3. Memcached calls a collection of key-value pairs a slab
  4. Azure Cosmos DB calls a collection of key-value pairs a container
-

In this interface, we use the term bucket to refer to a collection of key-value pairs

+

In this interface, we use the term bucket to refer to a connection to a collection of +key-value pairs.

+

Note that opening two bucket resources using the same identifier MAY result in connections +to two separate replicas in a distributed database, and that writes to one of those +resources are not guaranteed to be readable from the other resource promptly (or ever, in +the case of a replica failure or message reordering). See the Consistency section of the +store interface documentation for details.

Functions

open: func

Get the bucket with the specified identifier.

diff --git a/wit/store.wit b/wit/store.wit index a35c2d4..5d999b8 100644 --- a/wit/store.wit +++ b/wit/store.wit @@ -7,22 +7,52 @@ /// ensuring compatibility between different key-value stores. Note: the clients will be expecting /// serialization/deserialization overhead to be handled by the key-value store. The value could be /// a serialized object from JSON, HTML or vendor-specific data types like AWS S3 objects. +/// +/// ## Consistency /// -/// Data consistency in a key value store refers to the guarantee that once a write operation -/// completes, all subsequent read operations will return the value that was written. -/// -/// Any implementation of this interface must have enough consistency to guarantee "reading your -/// writes." In particular, this means that the client should never get a value that is older than -/// the one it wrote, but it MAY get a newer value if one was written around the same time. These -/// guarantees only apply to the same client (which will likely be provided by the host or an -/// external capability of some kind). In this context a "client" is referring to the caller or -/// guest that is consuming this interface. Once a write request is committed by a specific client, -/// all subsequent read requests by the same client will reflect that write or any subsequent -/// writes. Another client running in a different context may or may not immediately see the result -/// due to the replication lag. As an example of all of this, if a value at a given key is A, and -/// the client writes B, then immediately reads, it should get B. If something else writes C in -/// quick succession, then the client may get C. However, a client running in a separate context may -/// still see A or B +/// An implementation of this interface MUST be eventually consistent, but is not required to +/// provide any consistency guaranteeds beyond that. Practically speaking, eventual consistency is +/// among the weakest of consistency models, guaranteeing only that values will not be produced +/// "from nowhere", i.e. any value read is guaranteed to have been written to that key at some +/// earlier time. Beyond that, there are no guarantees, and thus a portable component must neither +/// expect nor rely on anything else. +/// +/// In the future, additional interfaces may be added to `wasi:keyvalue` with stronger guarantees, +/// which will allow components to express their requirements by importing whichever interface(s) +/// provides matching (or stronger) guarantees. For example, a component requiring strict +/// serializability might import a (currently hypothetical) `strict-serializable-store` interface +/// with a similar signature to `store` but with much stronger semantic guarantees. On the other +/// end, a host might either support implementations of both the `store` and +/// `strict-serializable-store` or just the former, in which case the host would immediately reject +/// a component which imports the unsupported interface. +/// +/// Here are a few examples of behavior which a component developer might wish to rely on but which +/// are _NOT_ guaranteed by an eventually consistent system (e.g. a distributed system composed of +/// multiple replicas, each of which may receive writes in a different order, making no attempt to +/// converge on a global consensus): +/// +/// - Read-your-own-writes: eventual consistency does _NOT_ guarantee that a write to a given key +/// followed by a read from the same key will retrieve the same or newer value. +/// +/// - Convergence: eventual consistency does _NOT_ guarantee that any two replicas will agree on the +/// value for a given key -- even after all writes have had time to propagate to all replicas. +/// +/// - Last-write-wins: eventual consistency does _NOT_ guarantee that the most recent write will +/// take precendence over an earlier one; old writes may overwrite newer ones temporarily or +/// permanently. +/// +/// ## Durability +/// +/// This interface does not currently make any hard guarantees about the durability of values +/// stored. A valid implementation might rely on an in-memory hash table, the contents of which are +/// lost when the process exits. Alternatively, another implementation might synchronously persist +/// all writes to disk -- or even to a quorum of disk-backed nodes at multiple locations -- before +/// returning a result for a `set` call. Finally, a third implementation might persist values +/// asynchronously on a best-effort basis without blocking `set` calls, in which case an I/O error +/// could occur after the component instance which originally made the call has exited. +/// +/// Future versions of `wasi:keyvalue` may provide ways to query and control the durability and +/// consistency provided by the backing implementation. interface store { /// The set of errors which may be raised by functions in this package variant error { @@ -56,7 +86,7 @@ interface store { /// A bucket is a collection of key-value pairs. Each key-value pair is stored as a entry in the /// bucket, and the bucket itself acts as a collection of all these entries. /// - /// It is worth noting that the exact terminology for bucket in key-value stores can very + /// It is worth noting that the exact terminology for bucket in key-value stores can vary /// depending on the specific implementation. For example: /// /// 1. Amazon DynamoDB calls a collection of key-value pairs a table @@ -67,7 +97,14 @@ interface store { /// 6. Memcached calls a collection of key-value pairs a slab /// 7. Azure Cosmos DB calls a collection of key-value pairs a container /// - /// In this interface, we use the term `bucket` to refer to a collection of key-value pairs + /// In this interface, we use the term `bucket` to refer to a connection to a collection of + /// key-value pairs. + /// + /// Note that opening two `bucket` resources using the same identifier MAY result in connections + /// to two separate replicas in a distributed database, and that writes to one of those + /// resources are not guaranteed to be readable from the other resource promptly (or ever, in + /// the case of a replica failure or message reordering). See the `Consistency` section of the + /// `store` interface documentation for details. resource bucket { /// Get the value associated with the specified `key` ///