This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
5
unikernel/duniverse/mirage-kv/.gitignore
vendored
Normal file
5
unikernel/duniverse/mirage-kv/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
_build
|
||||
*.install
|
||||
.merlin
|
||||
_opam
|
||||
*~
|
||||
90
unikernel/duniverse/mirage-kv/CHANGES.md
Normal file
90
unikernel/duniverse/mirage-kv/CHANGES.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
### v6.1.1 (2023-03-29)
|
||||
|
||||
* Leave it up to implementations how to interpret `last_modified` for
|
||||
dictionaries, or even not implement it (then returning ``Error
|
||||
(`Value_expected _)``. The previous definition was not well founded when the
|
||||
dictionary doesn't contain any values directly, and some implementations
|
||||
implements `last_modified` differently from the description on dictionaries.
|
||||
(reported in #41, fixed in #42 by @reynir)
|
||||
* Leave it up to implemetations how to interpret `digest` for dictionaries,
|
||||
or even not implement it (returning ``Error (`Value_expected _)``.
|
||||
(reported mirage/ocaml-tar#111, fixed in #43 by @reynir)
|
||||
|
||||
### v6.1.0 (2023-01-31)
|
||||
|
||||
* Mirage_kv.Key.add now raises Invalid_argument (instead of Failure). Document
|
||||
that it raises (#40 @reynir)
|
||||
|
||||
### v6.0.1 (2022-12-15)
|
||||
|
||||
* Specify in RO.list that the returned list consists of keys being absolute, and
|
||||
kinds (#38 #39 @reynir @hannesm)
|
||||
* BREAKING: Before 6.0.0, the return type of RO.list consisted of a string and
|
||||
kind list, where the string was relative. Now it is absolute.
|
||||
|
||||
### v6.0.0 (2022-12-12)
|
||||
|
||||
* Use ptime directly for RO.last_modified, instead of the int * int64 pair
|
||||
(#34)
|
||||
* Add RW.allocate to allocate a key and fill it with zero bytes (#34)
|
||||
* RO.list: return Key.t instead of string (#37, fixes #33)
|
||||
* Introduce a custom error for RW.rename with a source which is a prefix of
|
||||
destination (#37, fixes #31)
|
||||
* Use Optint.Int63.t for RO.size, RO.get_partial, RO.set_partial (#37, fixes #32)
|
||||
* Remove RW.batch (#37, fixes #29 #36, discussed at the MirageOS meeting in
|
||||
November, and on the mirageos-devel mailing list in January 2022)
|
||||
* Key.pp: escape the entire string, not individual fragments (#35)
|
||||
|
||||
### v5.0.0 (2022-09-07)
|
||||
|
||||
* Add `get_partial` and `size` to the RO interface (@palainp #28, review by
|
||||
@yomimono @hannesm)
|
||||
* Add `set_partial` and `rename` to the RW interface (@palainp #28, review by
|
||||
@yomimono @hannesm)
|
||||
* Mirage_kv.Key.pp: escape binary keys (#30 @hannesm)
|
||||
|
||||
### v4.0.1 (2022-02-28)
|
||||
|
||||
* Return `/` for `parent /` and `basename /` (@yomimono, @talex5, #25)
|
||||
|
||||
### v4.0.0 (2021-11-15)
|
||||
|
||||
* Remove Mirage_kv_lwt module (#24 @hannesm)
|
||||
* remove mirage-device dependency (#24 @hannesm)
|
||||
* Adapt to fmt 0.8.7 dependency (#23 @MisterDA)
|
||||
|
||||
### v3.0.1 (2019-11-04)
|
||||
|
||||
* provide deprecated Mirage_kv_lwt for smooth transition (#21 @hannesm)
|
||||
|
||||
### v3.0.0 (2019-10-22)
|
||||
|
||||
* remove mirage-kv-lwt (#19 @hannesm)
|
||||
* specialise mirage-kv on Lwt.t and value being string (#19 @hannesm)
|
||||
* raise lower OCaml bound to 4.06.0 (#19 @hannesm)
|
||||
|
||||
### v2.0.0 (2019-02-24)
|
||||
|
||||
* Major revision of the `RO` signature:
|
||||
- values are of type `string`
|
||||
- keys are segments instead of a string
|
||||
- `read` is now named `get`, and does no longer take an offset and length
|
||||
- the new function `list` is provided
|
||||
- the new functions `last_modified` and `digest` are provided
|
||||
* A module `Key` is provided with convenience functions to build keys
|
||||
* An `RW` signature is provided, extending `RO` with
|
||||
- a function `set` to replace a value
|
||||
- a function `remove` to remove a key
|
||||
- `batch` to batch operations
|
||||
|
||||
### v1.1.1 (2017-06-29)
|
||||
|
||||
* Remove `open Result` statements (and drop support to 4.02)
|
||||
|
||||
### v1.1.0 (2017-05-26)
|
||||
|
||||
* Port to Jbuilder.
|
||||
|
||||
### v1.0.0 (2016-12-27)
|
||||
|
||||
* First release, import `V1.KV_RO` and `V1_LWT.KV_RO` from mirage-types.
|
||||
11
unikernel/duniverse/mirage-kv/LICENSE.md
Normal file
11
unikernel/duniverse/mirage-kv/LICENSE.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
10
unikernel/duniverse/mirage-kv/Makefile
Normal file
10
unikernel/duniverse/mirage-kv/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
.PHONY: build clean test
|
||||
|
||||
build:
|
||||
dune build
|
||||
|
||||
test:
|
||||
dune runtest
|
||||
|
||||
clean:
|
||||
dune clean
|
||||
29
unikernel/duniverse/mirage-kv/README.md
Normal file
29
unikernel/duniverse/mirage-kv/README.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
## mirage-kv — MirageOS signatures for key/value devices
|
||||
|
||||
mirage-kv provides the [Mirage_kv.RO][ro] and [Mirage_kv.RW][rw]
|
||||
signatures the MirageOS key/value devices should implement.
|
||||
|
||||
mirage-kv is distributed under the ISC license.
|
||||
|
||||
[ro]: https://mirage.github.io/mirage-kv/mirage-kv/Mirage_kv/module-type-RO/index.html
|
||||
[rw]: https://mirage.github.io/mirage-kv/mirage-kv/Mirage_kv/module-type-RW/index.html
|
||||
|
||||
[](https://travis-ci.org/mirage/mirage-kv)
|
||||
|
||||
## Installation
|
||||
|
||||
mirage-kv can be installed with `opam`:
|
||||
|
||||
opam install mirage-kv
|
||||
|
||||
If you don't use `opam` consult the [`opam`](opam) file for build
|
||||
instructions.
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation and API reference is generated from the source
|
||||
interfaces. API docs for both [mirage-kv][doc-mirage-kv]
|
||||
can be consulted online or via `odig
|
||||
doc mirage-kv`.
|
||||
|
||||
[doc-mirage-kv]: http://docs.mirage.io/mirage-kv/
|
||||
1
unikernel/duniverse/mirage-kv/VERSION
Normal file
1
unikernel/duniverse/mirage-kv/VERSION
Normal file
|
|
@ -0,0 +1 @@
|
|||
6.1.1
|
||||
3
unikernel/duniverse/mirage-kv/dune-project
Normal file
3
unikernel/duniverse/mirage-kv/dune-project
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
(lang dune 1.0)
|
||||
(name mirage-kv)
|
||||
(version v6.1.1)
|
||||
30
unikernel/duniverse/mirage-kv/mirage-kv.opam
Normal file
30
unikernel/duniverse/mirage-kv/mirage-kv.opam
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
version: "6.1.1"
|
||||
opam-version: "2.0"
|
||||
maintainer: "Thomas Gazagnaire <thomas@gazagnaire.org>"
|
||||
authors: ["Thomas Gazagnaire <thomas@gazagnaire.org>" "Stefanie Schirmer" "Hannes Mehnert"]
|
||||
homepage: "https://github.com/mirage/mirage-kv"
|
||||
doc: "https://mirage.github.io/mirage-kv/"
|
||||
license: "ISC"
|
||||
dev-repo: "git+https://github.com/mirage/mirage-kv.git"
|
||||
bug-reports: "https://github.com/mirage/mirage-kv/issues"
|
||||
tags: ["org:mirage"]
|
||||
|
||||
build: [
|
||||
["dune" "subst"] {dev}
|
||||
["dune" "build" "-p" name "-j" jobs]
|
||||
["dune" "runtest" "-p" name] {with-test}
|
||||
]
|
||||
depends: [
|
||||
"ocaml" {>= "4.08.0"}
|
||||
"dune"
|
||||
"fmt" {>= "0.8.7"}
|
||||
"lwt" {>= "4.0.0"}
|
||||
"optint" {>= "0.2.0"}
|
||||
"ptime" {>= "1.0.0"}
|
||||
"alcotest" {with-test & >= "0.8.1"}
|
||||
]
|
||||
synopsis: "MirageOS signatures for key/value devices"
|
||||
description: """
|
||||
mirage-kv provides the `Mirage_kv.RO` and `Mirage_kv.RW`
|
||||
signatures the MirageOS key/value devices should implement.
|
||||
"""
|
||||
4
unikernel/duniverse/mirage-kv/src/dune
Normal file
4
unikernel/duniverse/mirage-kv/src/dune
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
(library
|
||||
(name mirage_kv)
|
||||
(public_name mirage-kv)
|
||||
(libraries fmt optint lwt ptime))
|
||||
95
unikernel/duniverse/mirage-kv/src/mirage_kv.ml
Normal file
95
unikernel/duniverse/mirage-kv/src/mirage_kv.ml
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
(*
|
||||
* Copyright (c) 2011-2015 Anil Madhavapeddy <anil@recoil.org>
|
||||
* Copyright (c) 2013-2015 Thomas Gazagnaire <thomas@gazagnaire.org>
|
||||
* Copyright (c) 2013 Citrix Systems Inc
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*)
|
||||
|
||||
module Key = struct
|
||||
|
||||
type t = string list
|
||||
(* Store the path as a reverse list to optimise basename and (/)
|
||||
operations *)
|
||||
|
||||
let err_invalid_segment x = Fmt.kstr invalid_arg "%S is not a valid segment" x
|
||||
|
||||
let check_segment x =
|
||||
String.iter (function '/' -> err_invalid_segment x | _ -> ()) x;
|
||||
x
|
||||
|
||||
let empty = []
|
||||
let v s = List.filter ((<>)"") @@ List.rev (String.split_on_char '/' s)
|
||||
let add t v = (check_segment v) :: t
|
||||
let ( / ) = add
|
||||
let append x y = y @ x
|
||||
let ( // ) = append
|
||||
let segments = List.rev
|
||||
let basename = function | [] -> "" | hd::_ -> hd
|
||||
let parent = function | _::tl -> tl | [] -> []
|
||||
let compare = compare
|
||||
let equal = (=)
|
||||
let to_string k = "/" ^ String.concat "/" (List.rev k)
|
||||
let pp ppf k = Fmt.string ppf (String.escaped (to_string k))
|
||||
end
|
||||
|
||||
type key = Key.t
|
||||
|
||||
type error = [
|
||||
| `Not_found of key
|
||||
| `Dictionary_expected of key
|
||||
| `Value_expected of key
|
||||
]
|
||||
|
||||
let pp_error ppf = function
|
||||
| `Not_found k -> Fmt.pf ppf "Cannot find the key %a" Key.pp k
|
||||
| `Dictionary_expected k ->
|
||||
Fmt.pf ppf "Expecting a dictionary for the key %a" Key.pp k
|
||||
| `Value_expected k ->
|
||||
Fmt.pf ppf "Expecting a value for the key %a" Key.pp k
|
||||
|
||||
module type RO = sig
|
||||
type nonrec error = private [> error]
|
||||
val pp_error: error Fmt.t
|
||||
type t
|
||||
val disconnect: t -> unit Lwt.t
|
||||
type key = Key.t
|
||||
val exists: t -> key -> ([`Value | `Dictionary] option, error) result Lwt.t
|
||||
val get: t -> key -> (string, error) result Lwt.t
|
||||
val get_partial: t -> key -> offset:Optint.Int63.t -> length:int -> (string, error) result Lwt.t
|
||||
val list: t -> key -> ((key * [`Value | `Dictionary]) list, error) result Lwt.t
|
||||
val last_modified: t -> key -> (Ptime.t, error) result Lwt.t
|
||||
val digest: t -> key -> (string, error) result Lwt.t
|
||||
val size: t -> key -> (Optint.Int63.t, error) result Lwt.t
|
||||
end
|
||||
|
||||
type write_error = [ error | `No_space | `Rename_source_prefix of key * key | `Already_present of key ]
|
||||
|
||||
let pp_write_error ppf = function
|
||||
| #error as e -> pp_error ppf e
|
||||
| `No_space -> Fmt.string ppf "No space left on device"
|
||||
| `Rename_source_prefix (src, dest) ->
|
||||
Fmt.pf ppf "Rename: source %a is prefix of destination %a"
|
||||
Key.pp src Key.pp dest
|
||||
| `Already_present k -> Fmt.pf ppf "Key %a is already present" Key.pp k
|
||||
|
||||
module type RW = sig
|
||||
include RO
|
||||
type nonrec write_error = private [> write_error]
|
||||
val pp_write_error: write_error Fmt.t
|
||||
val allocate : t -> key -> ?last_modified:Ptime.t -> Optint.Int63.t -> (unit, write_error) result Lwt.t
|
||||
val set: t -> key -> string -> (unit, write_error) result Lwt.t
|
||||
val set_partial: t -> key -> offset:Optint.Int63.t -> string -> (unit, write_error) result Lwt.t
|
||||
val remove: t -> key -> (unit, write_error) result Lwt.t
|
||||
val rename: t -> source:key -> dest:key -> (unit, write_error) result Lwt.t
|
||||
end
|
||||
255
unikernel/duniverse/mirage-kv/src/mirage_kv.mli
Normal file
255
unikernel/duniverse/mirage-kv/src/mirage_kv.mli
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
(*
|
||||
* Copyright (c) 2011-2015 Anil Madhavapeddy <anil@recoil.org>
|
||||
* Copyright (c) 2013-2015 Thomas Gazagnaire <thomas@gazagnaire.org>
|
||||
* Copyright (c) 2013 Citrix Systems Inc
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*)
|
||||
|
||||
(** MirageOS signatures for key/value devices
|
||||
|
||||
{e v6.1.1 } *)
|
||||
|
||||
(** {2 Mirage_kv} *)
|
||||
|
||||
(** MirageOS key-value stores are nested dictionaries, associating
|
||||
structured {{!Key}keys} to either dictionaries or values. *)
|
||||
|
||||
module Key: sig
|
||||
|
||||
(** {2 Structured keys} *)
|
||||
|
||||
type t
|
||||
(** The type for structured keys. *)
|
||||
|
||||
val empty: t
|
||||
(** [empty] is the empty key. It refers to the top-level
|
||||
dictionary. *)
|
||||
|
||||
val v : string -> t
|
||||
(** [v s] is the string [s] as a key. A key ["/foo/bar"] is
|
||||
decomposed into the segments ["foo"] and ["bar"]. The initial
|
||||
["/"] is always ignored so ["foo/bar"] and ["/foo/bar"] are
|
||||
equal. *)
|
||||
|
||||
val add : t -> string -> t
|
||||
(** [add t s] is the concatenated key [t/s].
|
||||
|
||||
@raise Invalid_argument if [s] contains ['/']. *)
|
||||
|
||||
val ( / ) : t -> string -> t
|
||||
(** [t / x] is [add t x].
|
||||
|
||||
@raise Invalid_argument if [s] contains ['/']. *)
|
||||
|
||||
val append : t -> t -> t
|
||||
(** [append x y] is the concatenated key [x/y]. *)
|
||||
|
||||
val ( // ) : t -> t -> t
|
||||
(** [x // y] is [append x y]. *)
|
||||
|
||||
val segments : t-> string list
|
||||
(** [segments t] is [t]'s list of segments. *)
|
||||
|
||||
val basename : t -> string
|
||||
(** [basename t] is the last segment of [t]. [basename empty] is
|
||||
the empty string [""]. *)
|
||||
|
||||
val parent : t -> t
|
||||
(** [parent t] is the key without the last segment. [parent empty]
|
||||
is [empty].
|
||||
|
||||
For any [t], the invariant have [parent t / basename t] is [t].
|
||||
*)
|
||||
|
||||
val compare : t-> t -> int
|
||||
(** The comparison function for keys. *)
|
||||
|
||||
val equal : t -> t -> bool
|
||||
(** The equality function for keys. *)
|
||||
|
||||
val pp : t Fmt.t
|
||||
(** The pretty printer for keys. *)
|
||||
|
||||
val to_string: t -> string
|
||||
(** [to_string t] is the string representation of [t]. ["/"] is used
|
||||
as separator between segements and it always starts with
|
||||
["/"]. *)
|
||||
|
||||
end
|
||||
|
||||
type key = Key.t
|
||||
(** The type for keys. *)
|
||||
|
||||
type error = [
|
||||
| `Not_found of key (** key not found *)
|
||||
| `Dictionary_expected of key (** key does not refer to a dictionary. *)
|
||||
| `Value_expected of key (** key does not refer to a value. *)
|
||||
]
|
||||
(** The type for errors. *)
|
||||
|
||||
val pp_error: error Fmt.t
|
||||
(** [pp_error] is the pretty-printer for errors. *)
|
||||
|
||||
module type RO = sig
|
||||
|
||||
(** {2 Read-only key-value stores} *)
|
||||
|
||||
type nonrec 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) 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) 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:Optint.Int63.t -> length:int -> (string, error) 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 -> ((key * [`Value | `Dictionary]) list, error) result Lwt.t
|
||||
(** [list t k] is the list of entries and their types in the
|
||||
dictionary referenced by [k] in [t]. The returned keys are all absolute
|
||||
(i.e. [Key.add k entry]).
|
||||
|
||||
The result is [Error (`Dictionary_expected k)] if [k] refers to a
|
||||
value in [t]. *)
|
||||
|
||||
val last_modified: t -> key -> (Ptime.t, error) result Lwt.t
|
||||
(** [last_modified t k] is the last time the value bound to [k] in
|
||||
[t] has been modified.
|
||||
|
||||
When the value bound to [k] is a dictionary, the implementation is free
|
||||
to decide how to compute a last modified timestamp, or return [Error
|
||||
(`Value_expected _)]. *)
|
||||
|
||||
val digest: t -> key -> (string, error) 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 implementation is
|
||||
allowed to return [Error (`Value_expected _)]. Otherwise, the [digest] is a
|
||||
unique and deterministic digest of its entries. *)
|
||||
|
||||
val size: t -> key -> (Optint.Int63.t, error) result Lwt.t
|
||||
(** [size t k] is the size of [k] in [t]. *)
|
||||
|
||||
|
||||
end
|
||||
|
||||
type write_error = [
|
||||
| error
|
||||
| `No_space (** No space left on the device. *)
|
||||
| `Rename_source_prefix of key * key (** The source is a prefix of destination in rename. *)
|
||||
| `Already_present of key (** The key is already present. *)
|
||||
]
|
||||
|
||||
val pp_write_error: write_error Fmt.t
|
||||
(** [pp_write_error] is the pretty-printer for write errors. *)
|
||||
|
||||
module type RW = sig
|
||||
|
||||
(** {2 Read-write Stores} *)
|
||||
|
||||
(** The functions {!set} and {!remove} will cause a flush in
|
||||
the underlying storage layer every time, which can degrade
|
||||
performance. *)
|
||||
|
||||
include RO
|
||||
|
||||
type nonrec 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 allocate : t -> key -> ?last_modified:Ptime.t -> Optint.Int63.t ->
|
||||
(unit, write_error) result Lwt.t
|
||||
(** [allocate t key ~last_modified size] allocates space for [key] in [t] with
|
||||
the provided [size] and [last_modified]. This is useful for e.g.
|
||||
append-only backends that could still use {!set_partial}. The data will
|
||||
be filled with 0. If [key] already exists, [Error (`Already_present key)]
|
||||
is returned. If there's not enough space, [Error `No_space] is returned.
|
||||
*)
|
||||
|
||||
val set: t -> key -> string -> (unit, write_error) result Lwt.t
|
||||
(** [set t k v] replaces the binding [k -> v] in [t].
|
||||
|
||||
Durability is guaranteed. *)
|
||||
|
||||
val set_partial: t -> key -> offset:Optint.Int63.t -> string -> (unit, write_error) 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) 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. *)
|
||||
|
||||
val rename: t -> source:key -> dest:key -> (unit, write_error) 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].
|
||||
The result id [Error (`Rename_source_prefix (source, dest))] if [source]
|
||||
is a prefix of [dest], and [source] is a directory.
|
||||
*)
|
||||
end
|
||||
4
unikernel/duniverse/mirage-kv/test/dune
Normal file
4
unikernel/duniverse/mirage-kv/test/dune
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
(test
|
||||
(name test)
|
||||
(package mirage-kv)
|
||||
(libraries mirage-kv alcotest))
|
||||
50
unikernel/duniverse/mirage-kv/test/test.ml
Normal file
50
unikernel/duniverse/mirage-kv/test/test.ml
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
open Mirage_kv
|
||||
|
||||
let key = Alcotest.testable Key.pp Key.equal
|
||||
|
||||
let path_v () =
|
||||
let check s e = Alcotest.(check string) s e Key.(to_string @@ v s) in
|
||||
check "/foo/bar" "/foo/bar";
|
||||
check "/foo" "/foo";
|
||||
check "/" "/";
|
||||
check "foo/bar" "/foo/bar";
|
||||
check "" "/"
|
||||
|
||||
let path_add () =
|
||||
let check p b exp =
|
||||
let f = p ^ "/" ^ b in
|
||||
let vp = Key.v p in
|
||||
Alcotest.(check string) f exp Key.(to_string @@ vp / b);
|
||||
Alcotest.(check key) f vp Key.(parent @@ vp / b);
|
||||
Alcotest.(check string) f b Key.(basename @@ vp / b)
|
||||
in
|
||||
let check_exn p b =
|
||||
try
|
||||
let _ = Key.(v p / b) in
|
||||
Alcotest.failf "%s is not a valid segment, should fail" b
|
||||
with Invalid_argument _ -> ()
|
||||
in
|
||||
check "" "bar" "/bar";
|
||||
check "/" "foo" "/foo";
|
||||
check "/foo" "bar" "/foo/bar";
|
||||
check "/foo/bar" "toto" "/foo/bar/toto";
|
||||
check_exn "" "foo/bar"
|
||||
|
||||
let path_append () =
|
||||
let check x y =
|
||||
let f = x ^ "/" ^ y in
|
||||
let vf = Key.v f in
|
||||
Alcotest.(check key) f vf Key.(v x // v y);
|
||||
Alcotest.(check string) x Key.(basename vf) Key.(basename @@ v y)
|
||||
in
|
||||
check "" "/foo/bar";
|
||||
check "/foo" "bar";
|
||||
check "/foo/bar" "/toto/foox/ko"
|
||||
|
||||
let () = Alcotest.run "mirage-kv" [
|
||||
"path", [
|
||||
"Path.v" , `Quick, path_v;
|
||||
"Path.add_seg", `Quick, path_add;
|
||||
"Path.append" , `Quick, path_append;
|
||||
]
|
||||
]
|
||||
Loading…
Add table
Add a link
Reference in a new issue