package irmin-layers

  1. Overview
  2. Docs

Parameters

module Node : Irmin.Private.Node.S with type metadata = Metadata.t and type hash = Hash.t and type step = Path.step

Signature

include Irmin.S with type key = Path.t with type contents = Contents.t with type branch = Branch.t with type hash = Hash.t with type step = Path.step with type metadata = Metadata.t with type Key.step = Path.step

Irmin stores

Irmin stores are tree-like read-write stores with extended capabilities. They allow an application (or a collection of applications) to work with multiple local states, which can be forked and merged programmatically, without having to rely on a global state. In a way very similar to version control systems, Irmin local states are called branches.

There are two kinds of store in Irmin: the ones based on persistent named branches and the ones based temporary detached heads. These exist relative to a local, larger (and shared) store, and have some (shared) contents. This is exactly the same as usual version control systems, that the informed user can see as an implicit purely functional data-structure.

type repo

The type for Irmin repositories.

type t

The type for Irmin stores.

type step = Path.step

The type for key steps.

type key = Path.t

The type for store keys. A key is a sequence of steps.

type metadata = Metadata.t

The type for store metadata.

type contents = Contents.t

The type for store contents.

type node

The type for store nodes.

type tree

The type for store trees.

type hash = Hash.t

The type for object hashes.

type commit

Type for commit identifiers. Similar to Git's commit SHA1s.

type branch = Branch.t

Type for persistent branch names. Branches usually share a common global namespace and it's the user's responsibility to avoid name clashes.

type slice

Type for store slices.

type lca_error = [
  1. | `Max_depth_reached
  2. | `Too_many_lcas
]

The type for errors associated with functions computing least common ancestors

type ff_error = [
  1. | `No_change
  2. | `Rejected
  3. | lca_error
]

The type for errors for fast_forward.

module Repo : sig ... end

Repositories.

val empty : repo -> t Lwt.t

empty repo is a temporary, empty store. Becomes a normal temporary store after the first update.

val master : repo -> t Lwt.t

master repo is a persistent store based on r's master branch. This operation is cheap, can be repeated multiple times.

val of_branch : repo -> branch -> t Lwt.t

of_branch r name is a persistent store based on the branch name. Similar to master, but use name instead Branch.S.master.

val of_commit : commit -> t Lwt.t

of_commit c is a temporary store, based on the commit c.

Temporary stores do not have stable names: instead they can be addressed using the hash of the current commit. Temporary stores are similar to Git's detached heads. In a temporary store, all the operations are performed relative to the current head and update operations can modify the current head: the current stores's head will automatically become the new head obtained after performing the update.

val repo : t -> repo

repo t is the repository containing t.

val tree : t -> tree Lwt.t

tree t is t's current tree. Contents is not allowed at the root of the tree.

module Status : sig ... end
val status : t -> Status.t

status t is t's status. It can either be a branch, a commit or empty.

module Head : sig ... end

Managing the store's heads.

module Hash : Irmin.Hash.S with type t = hash

Object hashes.

module Commit : sig ... end

Commit defines immutable objects to describe store updates.

module Contents : sig ... end

Contents provides base functions for the store's contents.

module Tree : sig ... end

Managing store's trees.

Reads

val kind : t -> key -> [ `Contents | `Node ] option Lwt.t

kind is Tree.kind applied to t's root tree.

val list : t -> key -> (step * tree) list Lwt.t

list t is Tree.list applied to t's root tree.

val mem : t -> key -> bool Lwt.t

mem t is Tree.mem applied to t's root tree.

val mem_tree : t -> key -> bool Lwt.t

mem_tree t is Tree.mem_tree applied to t's root tree.

val find_all : t -> key -> (contents * metadata) option Lwt.t

find_all t is Tree.find_all applied to t's root tree.

val find : t -> key -> contents option Lwt.t

find t is Tree.find applied to t's root tree.

val get_all : t -> key -> (contents * metadata) Lwt.t

get_all t is Tree.get_all applied on t's root tree.

val get : t -> key -> contents Lwt.t

get t is Tree.get applied to t's root tree.

val find_tree : t -> key -> tree option Lwt.t

find_tree t is Tree.find_tree applied to t's root tree.

val get_tree : t -> key -> tree Lwt.t

get_tree t k is Tree.get_tree applied to t's root tree.

val hash : t -> key -> hash option Lwt.t

hash t k

Udpates

type write_error = [
  1. | Irmin.Merge.conflict
  2. | `Too_many_retries of int
  3. | `Test_was of tree option
]

The type for write errors.

  • Merge conflict.
  • Concurrent transactions are competing to get the current operation committed and too many attemps have been tried (livelock).
  • A "test and set" operation has failed and the current value is v instead of the one we were waiting for.
val set : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> t -> key -> contents -> (unit, write_error) Stdlib.result Lwt.t

set t k ~info v sets k to the value v in t. Discard any previous results but ensure that no operation is lost in the history.

This function always uses Metadata.default as metadata. Use set_tree with `Contents (c, m) for different ones.

The result is Error `Too_many_retries if the concurrent operations do not allow the operation to commit to the underlying storage layer (livelock).

val set_exn : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> t -> key -> contents -> unit Lwt.t

set_exn is like set but raise Failure _ instead of using a result type.

val set_tree : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> t -> key -> tree -> (unit, write_error) Stdlib.result Lwt.t

set_tree is like set but for trees.

val set_tree_exn : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> t -> key -> tree -> unit Lwt.t

set_tree is like set_exn but for trees.

val remove : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> t -> key -> (unit, write_error) Stdlib.result Lwt.t

remove t ~info k remove any bindings to k in t.

The result is Error `Too_many_retries if the concurrent operations do not allow the operation to commit to the underlying storage layer (livelock).

val remove_exn : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> t -> key -> unit Lwt.t

remove_exn is like remove but raise Failure _ instead of a using result type.

val test_and_set : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> t -> key -> test:contents option -> set:contents option -> (unit, write_error) Stdlib.result Lwt.t

test_and_set ~test ~set is like set but it atomically checks that the tree is test before modifying it to set.

This function always uses Metadata.default as metadata. Use test_and_set_tree with `Contents (c, m) for different ones.

The result is Error (`Test t) if the current tree is t instead of test.

The result is Error `Too_many_retries if the concurrent operations do not allow the operation to commit to the underlying storage layer (livelock).

val test_and_set_exn : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> t -> key -> test:contents option -> set:contents option -> unit Lwt.t

test_and_set_exn is like test_and_set but raise Failure _ instead of using a result type.

val test_and_set_tree : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> t -> key -> test:tree option -> set:tree option -> (unit, write_error) Stdlib.result Lwt.t

test_and_set_tree is like test_and_set but for trees.

val test_and_set_tree_exn : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> t -> key -> test:tree option -> set:tree option -> unit Lwt.t

test_and_set_tree_exn is like test_and_set_exn but for trees.

val merge : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> old:contents option -> t -> key -> contents option -> (unit, write_error) Stdlib.result Lwt.t

merge ~old is like set but merge the current tree and the new tree using old as ancestor in case of conflicts.

This function always uses Metadata.default as metadata. Use merge_tree with `Contents (c, m) for different ones.

The result is Error (`Conflict c) if the merge failed with the conflict c.

The result is Error `Too_many_retries if the concurrent operations do not allow the operation to commit to the underlying storage layer (livelock).

val merge_exn : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> old:contents option -> t -> key -> contents option -> unit Lwt.t

merge_exn is like merge but raise Failure _ instead of using a result type.

val merge_tree : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> old:tree option -> t -> key -> tree option -> (unit, write_error) Stdlib.result Lwt.t

merge_tree is like merge_tree but for trees.

val merge_tree_exn : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> info:Irmin.Info.f -> old:tree option -> t -> key -> tree option -> unit Lwt.t

merge_tree is like merge_tree but for trees.

val with_tree : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> ?strategy:[ `Set | `Test_and_set | `Merge ] -> info:Irmin.Info.f -> t -> key -> (tree option -> tree option Lwt.t) -> (unit, write_error) Stdlib.result Lwt.t

with_tree t k ~info f replaces atomically the subtree v under k in the store t by the contents of the tree f v, using the commit info info ().

If v = f v and allow_empty is unset (default) then, the operation is a no-op.

If v != f v and no other changes happen concurrently, f v becomes the new subtree under k. If other changes happen concurrently to that operations, the semantics depend on the value of strategy:

  • if strategy = `Set, use set and discard any concurrent updates to k.
  • if strategy = `Test_and_set (default), use test_and_set and ensure that no concurrent operations are updating k.
  • if strategy = `Merge, use merge and ensure that concurrent updates and merged with the values present at the beginning of the transaction.

Note: Irmin transactions provides snapshot isolation guarantees: reads and writes are isolated in every transaction, but only write conflicts are visible on commit.

val with_tree_exn : ?retries:int -> ?allow_empty:bool -> ?parents:commit list -> ?strategy:[ `Set | `Test_and_set | `Merge ] -> info:Irmin.Info.f -> t -> key -> (tree option -> tree option Lwt.t) -> unit Lwt.t

with_tree_exn is like with_tree but raise Failure _ instead of using a return type.

Clones

val clone : src:t -> dst:branch -> t Lwt.t

clone ~src ~dst makes dst points to Head.get src. dst is created if needed. Remove the current contents en dst if src is empty.

Watches

type watch

The type for store watches.

val watch : t -> ?init:commit -> (commit Irmin.Diff.t -> unit Lwt.t) -> watch Lwt.t

watch t f calls f every time the contents of t's head is updated.

Note: even if f might skip some head updates, it will never be called concurrently: all consecutive calls to f are done in sequence, so we ensure that the previous one ended before calling the next one.

val watch_key : t -> key -> ?init:commit -> ((commit * tree) Irmin.Diff.t -> unit Lwt.t) -> watch Lwt.t

watch_key t key f calls f every time the key's value is added, removed or updated. If the current branch is deleted, no signal is sent to the watcher.

val unwatch : watch -> unit Lwt.t

unwatch w disable w. Return once the w is fully disabled.

Merges and Common Ancestors.

type 'a merge = info:Irmin.Info.f -> ?max_depth:int -> ?n:int -> 'a -> (unit, Irmin.Merge.conflict) Stdlib.result Lwt.t

The type for merge functions.

val merge_into : into:t -> t merge

merge_into ~into i t merges t's current branch into x's current branch using the info i. After that operation, the two stores are still independent. Similar to git merge <branch>.

val merge_with_branch : t -> branch merge

Same as merge but with a branch ID.

val merge_with_commit : t -> commit merge

Same as merge but with a commit ID.

val lcas : ?max_depth:int -> ?n:int -> t -> t -> (commit list, lca_error) Stdlib.result Lwt.t

lca ?max_depth ?n msg t1 t2 returns the collection of least common ancestors between the heads of t1 and t2 branches.

  • max_depth is the maximum depth of the exploration (default is max_int). Return Error `Max_depth_reached if this depth is exceeded.
  • n is the maximum expected number of lcas. Stop the exploration as soon as n lcas are found. Return Error `Too_many_lcas if more lcas are found.
val lcas_with_branch : t -> ?max_depth:int -> ?n:int -> branch -> (commit list, lca_error) Stdlib.result Lwt.t

Same as lcas but takes a branch ID as argument.

val lcas_with_commit : t -> ?max_depth:int -> ?n:int -> commit -> (commit list, lca_error) Stdlib.result Lwt.t

Same as lcas but takes a commit ID as argument.

History

module History : Graph.Sig.P with type V.t = commit

An history is a DAG of heads.

val history : ?depth:int -> ?min:commit list -> ?max:commit list -> t -> History.t Lwt.t

history ?depth ?min ?max t is a view of the history of the store t, of depth at most depth, starting from the t's head (or from max if the head is not set) and stopping at min if specified.

val last_modified : ?depth:int -> ?n:int -> t -> key -> commit list Lwt.t

last_modified ?number c k is the list of the last number commits that modified key, in ascending order of date. depth is the maximum depth to be explored in the commit graph, if any. Default value for number is 1.

module Branch : sig ... end

Manipulate branches.

module Key : Irmin.Path.S with type t = key and type step = step with type step = Path.step

Key provides base functions for the stores's paths.

module Metadata : sig ... end

Metadata provides base functions for node metadata.

Value Types

val step_t : step Irmin.Type.t

step_t is the value type for step.

val key_t : key Irmin.Type.t

key_t is the value type for key.

val metadata_t : metadata Irmin.Type.t

metadata_t is the value type for metadata.

val contents_t : contents Irmin.Type.t

contents_t is the value type for contents.

val node_t : node Irmin.Type.t

node_t is the value type for node.

val tree_t : tree Irmin.Type.t

tree_t is the value type for tree.

val commit_t : repo -> commit Irmin.Type.t

commit_t r is the value type for commit.

val branch_t : branch Irmin.Type.t

branch_t is the value type for branch.

val slice_t : slice Irmin.Type.t

slice_t is the value type for slice.

val kind_t : [ `Contents | `Node ] Irmin.Type.t

kind_t is the value type for values returned by kind.

val lca_error_t : lca_error Irmin.Type.t

lca_error_t is the value type for lca_error.

val ff_error_t : ff_error Irmin.Type.t

ff_error_t is the value type for ff_error.

val write_error_t : write_error Irmin.Type.t

write_error_t is the value type for write_error.

module Private : sig ... end

Private functions, which might be used by the backends.

type Irmin__.S.remote +=
  1. | E of Private.Sync.endpoint
    (*

    Extend the remote type with endpoint.

    *)

Converters to private types

val to_private_node : node -> Private.Node.value Tree.or_error Lwt.t
val of_private_node : repo -> Private.Node.value -> node
val to_private_commit : commit -> Private.Commit.value

to_private_commit c is the private commit object associated with the commit c.

val of_private_commit : repo -> Private.Commit.value -> commit

of_private_commit r c is the commit associated with the private commit object c.

val save_contents : [> Irmin.Perms.write ] Private.Contents.t -> contents -> hash Lwt.t

Save a content into the database

val save_tree : ?clear:bool -> repo -> [> Irmin.Perms.write ] Private.Contents.t -> [> Irmin.Perms.read_write ] Private.Node.t -> tree -> hash Lwt.t

Save a tree into the database. Does not do any reads. If clear is set (it is by default), the tree cache will be cleared after the save.

val freeze : ?min:commit list -> ?max:commit list -> ?squash:bool -> ?copy_in_upper:bool -> ?min_upper:commit list -> ?recovery:bool -> repo -> unit Lwt.t

freeze ?min ?max ?squash ?copy_in_upper ?min_upper ?recovery t launches an asynchronous freezing operation on the repo t to reduce the size of the upper layer and discard unnecessary branches of objects (i.e. commits, nodes and contents).

Let o be the set of objects reachable from the max commits and bounded by the min commits. During the freeze, all objects in o are copied to the lower layer, if there is one. Setting squash to true is equivalent to setting min to max. min defaults to the empty list and max defaults to the head commits of the repo.

Let o' be the set of objects reachable from the max commits and bounded by the min_upper commits. When the freeze is over, if copy_in_upper is true, then the new upper layer will only contain the objects of o', otherwise the new upper layer will be empty. min_upper defaults to the empty list and copy_in_upper defaults to the repo's configuration.

If recovery is true then the function will first try to recover from a previously interrupted freeze. See needs_recovery.

If a freeze is already ongoing, the behavior depends on the freeze_throttle configuration of the repo:

  • When `Overcommit_memory, the function returns without launching a new freeze.
  • When `Cancel_existing, the function blocks until the ongoing freeze safely cancels and then a new one is started afterwards. The time spent doing the canceled freeze is not completely wasted, objects copied to the lower layer will not have to be copied again, but objects copied to the next upper layer are discarded from that layer.
  • When `Block_writes, the function blocks until the ongoing freeze ends and then a new one is started afterwards.
type store_handle =
  1. | Commit_t : hash -> store_handle
  2. | Node_t : hash -> store_handle
  3. | Content_t : hash -> store_handle
val layer_id : repo -> store_handle -> [ `Upper0 | `Upper1 | `Lower ] Lwt.t

layer_id t store_handle returns the layer where an object, identified by its hash, is stored.

val async_freeze : repo -> bool

async_freeze t returns true if there is an ongoing freeze. To be used with caution, as a freeze can start (or stop) just after the test. It is helpful when a single freeze is called, to check whether it completed or not.

val self_contained : ?min:commit list -> max:commit list -> repo -> unit Lwt.t

self_contained min max t copies the commits in the range of min, max from lower into upper, in order to make the upper self contained. If min is missing then only the max commits are copied.

val check_self_contained : ?heads:commit list -> repo -> ([> `Msg of string ], [> `Msg of string ]) Stdlib.result Lwt.t

check_self_contained ?heads checks that the current upper layer of a store is self contained.

val needs_recovery : repo -> bool

needs_recovery repo detects if an ongoing freeze was interrupted during the last node crash. If it returns true then the next call to freeze needs to have its recovery flag set.

module PrivateLayer : sig ... end

These modules should not be used. They are exposed purely for testing purposes.

OCaml

Innovation. Community. Security.