123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336(*
* Copyright (c) 2013 Louis Gesbert <louis.gesbert@ocamlpro.com>
* Copyright (c) 2013-2017 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!ImportopenSmoduleProof=structtype('hash,'step,'value)t=|Blindedof'hash|Valuesof('step*'value)list|Inodeof{length:int;proofs:(int*('hash,'step,'value)t)list}(* TODO(craigfe): fix [ppx_irmin] for recursive types with type parameters. *)letthash_tstep_tvalue_t=letopenTypeinmu(funt->variant"proof"(funblindedvaluesinode->function|Blindedx1->blindedx1|Valuesx1->valuesx1|Inode{length;proofs}->inode(length,proofs))|~case1"Blinded"hash_t(funx1->Blindedx1)|~case1"Values"[%typ:(step*value)list](funx1->Valuesx1)|~case1"Inode"[%typ:int*(int*t)list](fun(length,proofs)->Inode{length;proofs})|>sealv)endmoduletypeS=sig(** {1 Node values} *)typet[@@derivingirmin](** The type for node values. *)typemetadata[@@derivingirmin](** The type for node metadata. *)typehash[@@derivingirmin](** The type for keys. *)typestep[@@derivingirmin](** The type for steps between nodes. *)typevalue=[`Nodeofhash|`Contentsofhash*metadata][@@derivingirmin](** The type for either (node) keys or (contents) keys combined with their
metadata. *)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.
{2 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. *)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:t(** [empty] is the empty node. *)valis_empty:t->bool(** [is_empty t] is true iff [t] is {!empty}. *)vallength:t->int(** [length t] is the number of entries in [t]. *)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 {{!Node.S.contents} contents}. The edge
between the node and the contents is labeled by a {{!Node.S.step} 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. *)valdefault:metadata(** [default] is the default metadata value. *)(** {1 Proofs} *)typenonrecproof=(hash,step,value)Proof.t[@@derivingirmin](** The type for proof trees. *)valto_proof:t->proofvalof_proof:proof->tendmoduletypeMaker=functor(H:Hash.S)(P:sigtypestep[@@derivingirmin]end)(M:METADATA)->Swithtypemetadata=M.tandtypehash=H.tandtypestep=P.stepmoduletypeSTORE=sigincludeCONTENT_ADDRESSABLE_STOREmodulePath: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. *)(** [Key] provides base functions for node keys. *)moduleKey:Hash.TYPEDwithtypet=keyandtypevalue=valuemoduleMetadata:METADATA(** [Metadata] provides base functions for node metadata. *)(** [Val] provides base functions for node values. *)moduleVal:Swithtypet=valueandtypehash=keyandtypemetadata=Metadata.tandtypestep=Path.stepmoduleContents:Contents.STOREwithtypekey=Val.hash(** [Contents] is the underlying contents store. *)endmoduletypeGRAPH=sig(** {1 Node Graphs} *)type'at(** The type for store handles. *)typemetadata(** The type for node metadata. *)typecontents(** The type of user-defined contents. *)typenode(** The type for node values. *)typestep(** The type of steps. A step is used to pass from one node to another. *)typepath(** The type of store paths. A path is composed of {{!step} steps}. *)typevalue=[`Nodeofnode|`Contentsofcontents*metadata](** The type for store values. *)valempty:[>write]t->nodeLwt.t(** The empty node. *)valv:[>write]t->(step*value)list->nodeLwt.t(** [v t n] is a new node containing [n]. *)vallist:[>read]t->node->(step*value)listLwt.t(** [list t n] is the contents of the node [n]. *)valfind:[>read]t->node->path->valueoptionLwt.t(** [find t n p] is the contents of the path [p] starting form [n]. *)valadd:[>read_write]t->node->path->value->nodeLwt.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->path->nodeLwt.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:nodelist->max:nodelist->nodelistLwt.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:nodelist->max:nodelist->?node:(node->unitLwt.t)->?contents:(contents->unitLwt.t)->?edge:(node->node->unitLwt.t)->?skip_node:(node->boolLwt.t)->?skip_contents:(contents->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. *)(** {1 Value Types} *)valmetadata_t:metadataType.t(** [metadat_t] is the value type for {!metadata}. *)valcontents_t:contentsType.t(** [contents_t] is the value type for {!contents}. *)valnode_t:nodeType.t(** [node_t] is the value type for {!node}. *)valstep_t:stepType.t(** [step_t] is the value type for {!step}. *)valpath_t:pathType.t(** [path_t] is the value type for {!path}. *)valvalue_t:valueType.t(** [value_t] is the value type for {!value}. *)endmoduletypeNode=sigmoduleProof:sigtype('hash,'step,'value)t=('hash,'step,'value)Proof.t=|Blindedof'hash|Valuesof('step*'value)list|Inodeof{length:int;proofs:(int*('hash,'step,'value)t)list;}[@@derivingirmin]endmoduletypeS=SmoduletypeMaker=MakermoduleMake:Maker(** [Make] provides a simple node implementation, parameterized by the
contents and notes keys [K], paths [P] and metadata [M]. *)(** v1 serialisation *)moduleV1(N:Swithtypestep=string):sigincludeSwithtypehash=N.hashandtypestep=N.stepandtypemetadata=N.metadatavalimport:N.t->tvalexport:t->N.tendmoduletypeSTORE=STORE(** [STORE] specifies the signature for node stores. *)(** [Store] creates node stores. *)moduleStore(C:Contents.STORE)(P:Path.S)(M:METADATA)(N:sigincludeCONTENT_ADDRESSABLE_STOREwithtypekey=C.keymoduleKey:Hash.Swithtypet=keymoduleVal:Swithtypet=valueandtypehash=keyandtypemetadata=M.tandtypestep=P.stepend):STOREwithtype'at='aC.t*'aN.tandtypekey=N.keyandtypevalue=N.valueandmodulePath=PandmoduleMetadata=MandtypeKey.t=N.keyandmoduleVal=N.ValmoduletypeGRAPH=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=N.Contents.keyandtypemetadata=N.Metadata.tandtypenode=N.keyandtypestep=N.Path.stepandtypepath=N.Path.tmoduleNo_metadata:METADATAwithtypet=unitend