123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476(*
* Copyright (c) 2013 Louis Gesbert <louis.gesbert@ocamlpro.com>
* Copyright (c) 2013-2022 Thomas Gazagnaire <thomas@gazagnaire.org>
*
* 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.
*)open!ImportmoduletypeCore=sig(** {1 Node values} *)typet[@@derivingirmin](** The type for node values. *)typemetadata[@@derivingirmin](** The type for node metadata. *)typecontents_key[@@derivingirmin](** The type for contents keys. *)typenode_key[@@derivingirmin](** The type for node keys. *)typestep[@@derivingirmin](** The type for steps between nodes. *)typevalue=[`Nodeofnode_key|`Contentsofcontents_key*metadata][@@derivingirmin](** The type for either (node) keys or (contents) keys combined with their
metadata. *)typehash[@@derivingirmin](** The type of hashes of values. *)valof_list:(step*value)list->t(** [of_list l] is the node [n] such that [list n = l]. *)vallist:?offset:int->?length:int->?cache:bool->t->(step*value)list(** [list t] is the contents of [t]. [offset] and [length] are used to
paginate results. *)valof_seq:(step*value)Seq.t->t(** [of_seq s] is the node [n] such that [seq n = s]. *)valseq:?offset:int->?length:int->?cache:bool->t->(step*value)Seq.t(** [seq t] is the contents of [t]. [offset] and [length] are used to paginate
results.
See {!caching} for an explanation of the [cache] parameter *)valempty:unit->t(** [empty ()] is the empty node. *)valis_empty:t->bool(** [is_empty t] is true iff [t] is {!val-empty}. *)vallength:t->int(** [length t] is the number of entries in [t]. *)valhash_exn:?force:bool->t->hash(** [hash_exn t] is the hash of [t].
Another way of computing it is [Hash.Typed(Hash)(Node).hash t] which
computes the pre-hash of [t] before hashing it using [Hash]. [hash_exn]
might be faster because the it may be optimised (e.g. it may use caching).
[hash_exn t] is [hash_exn ~force:true t] which is not expected to raise an
exception. [hash_exn ~force:false t] will raise [Not_found] if the hash
requires IOs to be computed. *)valclear:t->unit(** Cleanup internal caches. *)valfind:?cache:bool->t->step->valueoption(** [find t s] is the value associated with [s] in [t].
A node can point to user-defined {{!contents_key} contents}. The edge
between the node and the contents is labeled by a {!step}.
See {!caching} for an explanation of the [cache] parameter *)valadd:t->step->value->t(** [add t s v] is the node where [find t v] is [Some s] but is similar to [t]
otherwise. *)valremove:t->step->t(** [remove t s] is the node where [find t s] is [None] but is similar to [t]
otherwise. *)moduleMetadata:Metadata.Swithtypet=metadata(** Metadata functions. *)(** {2:caching caching}
[cache] regulates the caching behaviour regarding the node's internal data
which may be lazily loaded from the backend, depending on the node
implementation.
[cache] defaults to [true] which may greatly reduce the IOs and the
runtime but may also increase the memory consumption.
[cache = false] doesn't replace a call to [clear], it only prevents the
storing of new data, it doesn't discard the existing one. *)(** {1 Recursive Nodes} *)(** Some [Node] implementations (like [irmin-pack]'s inodes) can represent a
node as a set of nodes. One operation on such "high-level" node
corresponds to a sequence of recursive calls to the underlying
"lower-level" nodes. Note: theses [effects] are not in the Lwt monad on
purpose (so [Tree.hash] and [Tree.equal] are not in the Lwt monad as
well). *)typeeffect:=expected_depth:int->node_key->toption(** The type for read effects. *)valwith_handler:(effect->effect)->t->t(** [with_handler f] replace the current effect handler [h] by [f h]. [f h]
will be called for all the recursive read effects that are required by
recursive operations on nodes. .*)typehead:=[`Nodeof(step*value)list|`Inodeofint*(int*hash)list][@@derivingirmin]valhead:t->head(** Reveal the shallow internal structure of the node.
Only hashes and not keys are revealed in the [`Inode] case, this is
because these inodes might not be keyed yet. *)endmoduletypeS_generic_key=sigincludeCore(** @inline *)(** {2 merging} *)valmerge:contents:contents_keyoptionMerge.t->node:node_keyoptionMerge.t->tMerge.t(** [merge] is the merge function for nodes. *)exceptionDangling_hashof{context:string;hash:hash}endmoduletypeS=sigtypehash(** @inline *)includeS_generic_keywithtypehash:=hashandtypecontents_key=hashandtypenode_key=hashendmoduletypePortable=sigtypehash(** @inline *)includeCorewithtypehash:=hashandtypecontents_key=hashandtypenode_key=hashtypenodevalof_node:node->t(** {2 merging} *)valmerge:contents:contents_keyoptionMerge.t->node:node_keyoptionMerge.t->tMerge.t(** [merge] is the merge function for nodes. *)(** {1 Proofs} *)typeproof=[`Blindedofhash|`Valuesof(step*value)list|`Inodeofint*(int*proof)list][@@derivingirmin](** The type for proof trees. *)valto_proof:t->proofvalof_proof:depth:int->proof->toption(** [of_proof ~depth p] is [None] if [p] is corrupted or incompatible with
[depth]. It is [Some t] when [t] is a node if the operation succeeded.
[hash_exn t] never raises [Not_found] *)endopenstructmoduleS_is_a_generic_key(X:S):S_generic_key=XendmoduletypeMaker_generic_key=functor(Hash:Hash.S)(Path:sigtypestep[@@derivingirmin]end)(Metadata:Metadata.S)(Contents_key:Key.Swithtypehash=Hash.t)(Node_key:Key.Swithtypehash=Hash.t)->sigincludeS_generic_keywithtypemetadata=Metadata.tandtypestep=Path.stepandtypehash=Hash.tandtypecontents_key=Contents_key.tandtypenode_key=Node_key.tmodulePortable:Portablewithtypenode:=tandtypestep:=stepandtypemetadata:=metadataandtypehash:=hashendmoduletypeStore=sigincludeIndexable.SmodulePath:Path.S(** [Path] provides base functions on node paths. *)valmerge:[>read_write]t->keyoptionMerge.t(** [merge] is the 3-way merge function for nodes keys. *)moduleMetadata:Metadata.S(** [Metadata] provides base functions for node metadata. *)(** [Val] provides base functions for node values. *)moduleVal:S_generic_keywithtypet=valueandtypehash=hashandtypenode_key=keyandtypemetadata=Metadata.tandtypestep=Path.stepmoduleHash:Hash.Typedwithtypet=hashandtypevalue=valuemoduleContents:Contents.Storewithtypekey=Val.contents_key(** [Contents] is the underlying contents store. *)endmoduletypeGraph=sig(** {1 Node Graphs} *)type'at(** The type for store handles. *)typemetadata[@@derivingirmin](** The type for node metadata. *)typecontents_key[@@derivingirmin](** The type of user-defined contents. *)typenode_key[@@derivingirmin](** The type for node values. *)typestep[@@derivingirmin](** The type of steps. A step is used to pass from one node to another. *)typepath[@@derivingirmin](** The type of store paths. A path is composed of {{!step} steps}. *)typevalue=[`Nodeofnode_key|`Contentsofcontents_key*metadata][@@derivingirmin](** The type for store values. *)valempty:[>write]t->node_keyLwt.t(** The empty node. *)valv:[>write]t->(step*value)list->node_keyLwt.t(** [v t n] is a new node containing [n]. *)vallist:[>read]t->node_key->(step*value)listLwt.t(** [list t n] is the contents of the node [n]. *)valfind:[>read]t->node_key->path->valueoptionLwt.t(** [find t n p] is the contents of the path [p] starting form [n]. *)valadd:[>read_write]t->node_key->path->value->node_keyLwt.t(** [add t n p v] is the node [x] such that [find t x p] is [Some v] and it
behaves the same [n] for other operations. *)valremove:[>read_write]t->node_key->path->node_keyLwt.t(** [remove t n path] is the node [x] such that [find t x] is [None] and it
behhaves then same as [n] for other operations. *)valclosure:[>read]t->min:node_keylist->max:node_keylist->node_keylistLwt.t(** [closure t min max] is the unordered list of nodes [n] reachable from a
node of [max] along a path which: (i) either contains no [min] or (ii) it
ends with a [min].
{b Note:} Both [min] and [max] are subsets of [n]. *)valiter:[>read]t->min:node_keylist->max:node_keylist->?node:(node_key->unitLwt.t)->?contents:(contents_key->unitLwt.t)->?edge:(node_key->node_key->unitLwt.t)->?skip_node:(node_key->boolLwt.t)->?skip_contents:(contents_key->boolLwt.t)->?rev:bool->unit->unitLwt.t(** [iter t min max node edge skip rev ()] iterates in topological order over
the closure of [t].
It applies the following functions while traversing the graph: [node] on
the nodes; [edge n predecessor_of_n] on the directed edges; [skip_node n]
to not include a node [n], its predecessors and the outgoing edges of [n]
and [skip_contents c] to not include content [c].
If [rev] is true (the default) then the graph is traversed in the reverse
order: [node n] is applied only after it was applied on all its
predecessors; [edge n p] is applied after [node n]. Note that [edge n p]
is applied even if [p] is skipped. *)endmoduletypeSigs=sigmoduletypeS=S(** [Make] provides a simple node implementation, parameterized by hash, path
and metadata implementations. The contents and node values are addressed
directly by their hash. *)moduleMake(Hash:Hash.S)(Path:sigtypestep[@@derivingirmin]end)(Metadata:Metadata.S):Swithtypehash=Hash.tandtypemetadata=Metadata.tandtypestep=Path.step(** [Generic_key] generalises the concept of "node" to one that supports
object keys that are not strictly equal to hashes. *)moduleGeneric_key:sigmoduletypeS=S_generic_keymoduletypeMaker=Maker_generic_keymoduletypeCore=CoremoduleMake:MakermoduleMake_v2:Maker(** [Make_v2] provides a similar implementation as [Make] but the hash
computation is compatible with versions older than irmin.3.0 *)moduleStore(C:Contents.Store)(S:Indexable.S)(H:Hash.Swithtypet=S.hash)(V:Swithtypet=S.valueandtypehash=H.tandtypecontents_key=C.keyandtypenode_key=S.key)(M:Metadata.Swithtypet=V.metadata)(P:Path.Swithtypestep=V.step):Storewithtype'at='aC.t*'aS.tandtypekey=S.keyandtypehash=S.hashandtypevalue=S.valueandmodulePath=PandmoduleMetadata=MandmoduleVal=Vend(** v1 serialisation *)moduleV1(N:Generic_key.Swithtypestep=string):sigincludeGeneric_key.Swithtypecontents_key=N.contents_keyandtypenode_key=N.node_keyandtypestep=N.stepandtypemetadata=N.metadatavalimport:N.t->tvalexport:t->N.tendmodulePortable:sig(** Portable form of a node implementation that can be constructed from a
concrete representation and used in computing hashes. Conceptually, a
[Node.Portable.t] is a [Node.t] in which all internal keys have been
replaced with the hashes of the values they point to.
Computations over [Portable.t] values must commute with those over [t]s,
as in the following diagram:
{[
┌────────┐ ┌─────────┐ of_node ┌────────────────┐
│ Key │ │ Node │ ─────────> │ Node.Portable │
└────────┘ └─────────┘ └────────────────┘
│ │ add/remove │ │
to_hash └───────────> (+) add/remove │
│ ┌──────────────┼──────────────────────> (+)
v │ v v
┌────────┐ ┌─────────┐ ┌────────────────┐
│ Hash │ │ Node' │ ─────────> │ Node.Portable' │
└────────┘ └─────────┘ of_node └────────────────┘
]} *)(** A node implementation with hashes for keys is trivially portable: *)moduleOf_node(S:S):Portablewithtypenode:=S.tandtypet=S.tandtypestep=S.stepandtypemetadata=S.metadataandtypehash=S.hashmoduletypeS=PortableendmoduletypeStore=Store(** [Store] specifies the signature for node stores. *)(** [Store] creates node stores. *)moduleStore(C:Contents.Store)(S:Content_addressable.Swithtypekey=C.key)(H:Hash.Swithtypet=S.key)(V:Swithtypet=S.valueandtypehash=S.key)(M:Metadata.Swithtypet=V.metadata)(P:Path.Swithtypestep=V.step):Storewithtype'at='aC.t*'aS.tandtypekey=S.keyandtypevalue=S.valueandtypehash=H.tandmodulePath=PandmoduleMetadata=MandmoduleVal=VmoduletypeGraph=Graph(** [Graph] specifies the signature for node graphs. A node graph is a
deterministic DAG, labeled by steps. *)moduleGraph(N:Store):Graphwithtype'at='aN.tandtypecontents_key=N.Contents.keyandtypenode_key=N.keyandtypemetadata=N.Metadata.tandtypestep=N.Path.stepandtypepath=N.Path.tend