Module type Mirage_kv.RW

Read-write Stores

There is a trade-off between durability and performance. If you want performance, use the batch operation with a chain of sets and removes. They will be applied on the underlying storage layer all at once. Otherwise set and remove will cause a flush in the underlying storage layer every time, which could degrade performance.

include RO

Read-only key-value stores

type nonrec error#row

The type for errors.

and error = private [>
| error
]

The type for errors.

val pp_error : error Fmt.t

pp_error is the pretty-printer for errors.

type t

The type representing the internal state of the key-value store.

val disconnect : t -> unit Lwt.t

Disconnect from the key-value store. While this might take some time to complete, it can never result in an error.

type key = Key.t

The type for keys.

val exists : t -> key -> ( [ `Value | `Dictionary ] option, error ) Stdlib.result Lwt.t

exists t k is Some `Value if k is bound to a value in t, Some `Dictionary if k is a prefix of a valid key in t and None if no key with that prefix exists in t.

exists answers two questions: does the key exist and is it referring to a value or a dictionary.

An error occurs when the underlying storage layer fails.

val get : t -> key -> ( string, error ) Stdlib.result Lwt.t

get t k is the value bound to k in t.

The result is Error (`Value_expected k) if k refers to a dictionary in t.

val get_partial : t -> key -> offset:int -> length:int -> ( string, error ) Stdlib.result Lwt.t

get_partial t k ~offset ~length is the length bytes wide value bound at offset of k in t.

If the size of k is less than offset, get_partial returns an empty string. If the size of k is less than offset+length, get_partial returns a short string. The result is Error (`Value_expected k) if k refers to a dictionary in t.

val list : t -> key -> ( (string * [ `Value | `Dictionary ]) list, error ) Stdlib.result Lwt.t

list t k is the list of entries and their types in the dictionary referenced by k in t.

The result is Error (`Dictionary_expected k) if k refers to a value in t.

val last_modified : t -> key -> ( int * int64, error ) Stdlib.result Lwt.t

last_modified t k is the last time the value bound to k in t has been modified.

The modification time (d, ps) is a span for the signed POSIX picosecond span d * 86_400e12 + ps. d is a signed number of POSIX days and ps a number of picoseconds in the range [0;86_399_999_999_999_999L].

When the value bound to k is a dictionary, the modification time is the latest modification of all entries in that dictionary. This behaviour is only one level deep and not recursive.

val digest : t -> key -> ( string, error ) Stdlib.result Lwt.t

digest t k is the unique digest of the value bound to k in t.

When the value bound to k is a dictionary, the digest is a unique and deterministic digest of its entries.

val size : t -> key -> ( int, error ) Stdlib.result Lwt.t

size t k is the size of k in t.

type nonrec write_error#row

The type for write errors.

and write_error = private [>
| write_error
]

The type for write errors.

val pp_write_error : write_error Fmt.t

The pretty-printer for pp_write_error.

val set : t -> key -> string -> ( unit, write_error ) Stdlib.result Lwt.t

set t k v replaces the binding k -> v in t.

Durability is guaranteed unless set is run inside an enclosing batch operation, where durability will be guaranteed at the end of the batch.

val set_partial : t -> key -> offset:int -> string -> ( unit, write_error ) Stdlib.result Lwt.t

set_partial t k offset v attempts to write v at offset in the value bound to k in t. If k contains directories that do not exist, set_partial will attempt to create them. If the size of k is less than offset, set_partial appends v at the end of k. If the size of k is greater than offset+length of v, set_partial leaves the last bytes of k unchanged.

The result is Error (`Value_expected k) if k refers to a dictionary in t.

val remove : t -> key -> ( unit, write_error ) Stdlib.result Lwt.t

remove t k removes any binding of k in t. If k was bound to a dictionary, the full dictionary will be removed.

Durability is guaranteed unless remove is run inside an enclosing batch operation, where durability will be guaranteed at the end of the batch.

val rename : t -> source:key -> dest:key -> ( unit, write_error ) Stdlib.result Lwt.t

rename t source dest rename source to dest in t. If source and dest are both bound to values in t, dest is removed and the binding of source is moved to dest. If dest is bound to a dictionary in t, source is moved inside dest. If source is bound to a dictionary, the full dictionary is moved.

The result is Error (`Not_found source) if source does not exists in t. The result is Error (`Value_expected source) if source is bound to a dictionary in t and dest is bound to a value in t.

val batch : t -> ?retries:int -> ( t -> 'a Lwt.t ) -> 'a Lwt.t

batch t f run f in batch. Ensure the durability of operations.

Since a batch is applied at once, the readings inside a batch will return the state before the entire batch. Concurrent operations will not affect other ones executed during the batch.

Batch applications can fail to apply if other operations are happening concurrently. In case of failure, f will run again with the most recent version of t. The result is Error `Too_many_retries if f is run for more then retries attemps (default is 13).