package irmin

  1. Overview
  2. Docs
Legend:
Library
Module
Module type
Parameter
Class
Class type

Branch-consistent stores.

Branch-consistent stores

Branch-consistent stores are hierarchical 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 BC store in Irmin: persistent named branches and 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.

Persistent Branches

A persistent branch always has a unique ID, which is typically a string (the branch name). Thus, in order to use a persistent branch, you need to provide its name: see the of_branch_id function.

type commit_id

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

type branch_id

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.

module Repo : sig ... end

A repository contains a set of branches.

A branch-consistent store is a hierarchical read-write store.

include HRW

Hierarchical read-write stores

Hierarchical read-write stores are read-write stores using paths as keys. They are a very simplified abstraction of filesystems.

include RW

Read-write stores

include RO

Read-only stores

type t

Type for stores.

type key

Type for keys.

type value

Type for values.

val read : t -> key -> value option Lwt.t

Read a value from the store.

val read_exn : t -> key -> value Lwt.t

Same as read but raise Invalid_argument if the key does not exist.

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

Check if a key exists.

val iter : t -> (key -> value Lwt.t -> unit Lwt.t) -> unit Lwt.t

iter t fn call the function fn on all t's keys and values.

val update : t -> key -> value -> unit Lwt.t

update t k v replaces the contents of k by v in t. If k is not already defined in t, create a fresh binding. Raise Invalid_argument if k is the empty path.

val compare_and_set : t -> key -> test:value option -> set:value option -> bool Lwt.t

compare_and_set t key ~test ~set sets key to set only if the current value of key is test and in that case returns true. If the current value of key is different, it returns false. None means that the value does not have to exist or is removed.

Note: The operation is guaranteed to be atomic.

val remove : t -> key -> unit Lwt.t

remove t k remove the key k in t.

val list : t -> key -> key list Lwt.t

list t k list the sub-paths of the path k in t.

val remove_rec : t -> key -> unit Lwt.t

Same as RW.remove but removes all the sub-paths recursively.

val master : 'a Task.f -> Repo.t -> ('a -> t) Lwt.t

master repo task is a function returning fresh store handles within the repository repo, with fresh tasks computed using task. The result is a persistent branch using the

ef.S.master

reference. This operation is cheap, can be repeated multiple times.

val repo : t -> Repo.t

repo t is the repository containing t.

val task : t -> task

task t is the task associated to the store handle t.

val of_branch_id : 'a Task.f -> branch_id -> Repo.t -> ('a -> t) Lwt.t

of_branch_id t name is the persistent branch named name. Similar to master, but use name instead Ref.S.master.

val name : t -> branch_id option Lwt.t

name t is t's branch name. Return None if t is not persistent.

val name_exn : t -> branch_id Lwt.t

Same as name but raise Invalid_argument if t is not persistent.

val update_branch : t -> branch_id -> unit Lwt.t

update_branch t src updates t's contents with the contents of the branch named src. Can cause data losses as it discard the current contents. Similar to git reset --hard <src>.

val merge_branch : t -> ?max_depth:int -> ?n:int -> branch_id -> unit Merge.result Lwt.t

merge_branch t other merges the contents of the branch named other into t. Similar to git merge <other>.

val merge_branch_exn : t -> ?max_depth:int -> ?n:int -> branch_id -> unit Lwt.t

Same as merge_branch but raise Merge.Conflict in case of conflict.

Temporary Stores

Temporary stores do not have stable names: instead they can be addressed using the hash of the current commit. These hashes are called heads in Irmin. 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 while performing the update.

Temporary stores are created using the BC.of_head function.

val empty : 'a Task.f -> Repo.t -> ('a -> t) Lwt.t

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

val of_commit_id : 'a Task.f -> commit_id -> Repo.t -> ('a -> t) Lwt.t

Create a temporary store, using the given commit_id. The store will not persist as it has no persistent branch name.

val head : t -> commit_id option Lwt.t

head t is the current head of the store t. This works for both persistent and temporary stores. In the case of a persistent branch, this involves getting the the head associated with the branch's ID, so this may block. In the case of a temporary store, it simply returns the current head. Returns None if the store has no contents. Similar to git rev-parse HEAD.

val head_exn : t -> commit_id Lwt.t

Same as head but raise Invalid_argument if the store does not have any contents.

val head_ref : t -> [ `Branch of branch_id | `Head of commit_id | `Empty ]

head_ref t is the branch ID that this store tracks (for persistent stores), the current head commit (for temporary stores), or `Empty for empty temporary stores.

val update_head : t -> commit_id -> unit Lwt.t

update_head t h updates t's contents with the contents of the commit_id h. Can cause data loss as it discards the current contents. Similar to git reset --hard <hash>.

val fast_forward_head : t -> ?max_depth:int -> ?n:int -> commit_id -> bool Lwt.t

fast_forward_head t h is similar to update_head but the t's head is updated to h only if h is stricly in the future of t's current head. Return false if it is not the case. If present, max_depth or n are used to limit the search space of the lowest common ancestors (see lcas).

val compare_and_set_head : t -> test:commit_id option -> set:commit_id option -> bool Lwt.t

Same as update_head but check that the value is test before updating to set. Use update or merge instead if possible.

val merge_head : t -> ?max_depth:int -> ?n:int -> commit_id -> unit Merge.result Lwt.t

merge_head t ?max_head ?n commit_id merges the contents of the commit associated to commit_id into t. max_depth is the maximal depth used for getting the lowest common ancestor. n is the maximum number of lowest common ancestors. If present, max_depth or n are used to limit the search space of the lowest common ancestors (see lcas).

val merge_head_exn : t -> ?max_depth:int -> ?n:int -> commit_id -> unit Lwt.t

Same as merge_head but raise Merge.Conflict in case of a conflict.

val watch_head : t -> ?init:commit_id -> (commit_id diff -> unit Lwt.t) -> (unit -> unit Lwt.t) Lwt.t

watch_branch t f calls f every time the contents of t's reference is updated. Do nothing if t is not persistent. Return a clean-up function to remove the watch handler.

Note: even 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_id * value) -> ((commit_id * value) diff -> unit Lwt.t) -> (unit -> unit Lwt.t) 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.

Clones and Merges

val clone : 'a Task.f -> t -> branch_id -> [ `Ok of 'a -> t | `Duplicated_branch | `Empty_head ] Lwt.t

Clone the store t, using the given branch name. Return Duplicated_branch if a branch with the same name already exists and Empty_head if t has no head.

val clone_force : 'a Task.f -> t -> branch_id -> ('a -> t) Lwt.t

Same as clone but delete and update the existing branch if a branch with the same name already exists.

val merge : 'a -> ?max_depth:int -> ?n:int -> ('a -> t) -> into:('a -> t) -> unit Merge.result Lwt.t

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

val merge_exn : 'a -> ?max_depth:int -> ?n:int -> ('a -> t) -> into:('a -> t) -> unit Lwt.t

FIXME Same as merge but raise Merge.Conflict in case of a conflict.

val lcas : 'a -> ?max_depth:int -> ?n:int -> ('a -> t) -> ('a -> t) -> [ `Ok of commit_id list | `Max_depth_reached | `Too_many_lcas ] 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 `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 `Too_many_lcas if more lcas are found.
val lcas_branch : t -> ?max_depth:int -> ?n:int -> branch_id -> [ `Ok of commit_id list | `Max_depth_reached | `Too_many_lcas ] Lwt.t

Same as lcas but takes a branch ID as argument.

val lcas_head : t -> ?max_depth:int -> ?n:int -> commit_id -> [ `Ok of commit_id list | `Max_depth_reached | `Too_many_lcas ] Lwt.t

Same as lcas but takes a commit_id as argument.

History

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

An history is a DAG of heads.

val history : ?depth:int -> ?min:commit_id list -> ?max:commit_id 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 max (or from the t's head if the list of heads is empty) and stopping at min if specified.

OCaml

Innovation. Community. Security.