Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file mem.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484(*
* Copyright (c) 2013-2017 Thomas Gazagnaire <thomas@gazagnaire.org>
* and Romain Calascibetta <romain.calascibetta@gmail.com>
*
* 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.
*)letsrc=Logs.Src.create"git.mem"~doc:"logs git's memory back-end"moduleLog=(valLogs.src_logsrc:Logs.LOG)moduleSched=Carton.Make(structtype'at='aend)type'hasht={values:('hash,'hashValue.tLazy.t)Hashtbl.t;inflated:('hash,[`Commit|`Blob|`Tag|`Tree]*Cstruct.t)Hashtbl.t;refs:(Reference.t,[`Hof'hash|`RofReference.t])Hashtbl.t;root:Fpath.t;dotgit:Fpath.t;shallows:'hashShallow.t;mutablehead:'hashReference.contentsoption;}letbatch_write:typeuidpackindex.uidt->uid_ln:int->uid_rw:(string->uid)->map:(pack->pos:int64->int->Bigstringaf.t)->iter:(index->f:(uid->int64->unit)->unit)->pack->index->unit=funstore~uid_ln~uid_rw~map~iterpackindex->lettbl=Hashtbl.create0x100inletfuidoffset=Hashtbl.addtbluidoffsetiniterindex~f;letz=De.bigstring_createDe.io_buffer_sizeinletw=De.make_window~bits:15inletallocate_=winletpack=Carton.Dec.makepack~z~allocate~uid_ln~uid_rw(Hashtbl.findtbl)inletfuidoffset=letweight=Carton.Dec.weight_of_offset~mappack~weight:Carton.Dec.nulloffsetinletraw=Carton.Dec.make_raw~weightinletres=Carton.Dec.of_offset~mappackraw~cursor:offsetinletinflated=Cstruct.of_bigarray(Carton.Dec.rawres)~off:0~len:(Carton.Dec.lenres)inletkind=matchCarton.Dec.kindreswith|`A->`Commit|`B->`Tree|`C->`Blob|`D->`Taginifnot(Hashtbl.memstore.valuesuid)thenHashtbl.addstore.inflateduid(kind,inflated)initerindex~fletfailureffmt=Fmt.kstr(funerr->Failureerr)fmt(* XXX(dinosaure): a point about modules, functors and alias.
* The choice was made to _defunctorize_ any types to avoid to
* keep type equalities between resulted modules of application
* of some functors.
*
* With this such design, we are able to use values at any points
* of the code instead to get an error about incompatible types -
* even if we know they are equals.
*
* However, [git] is designed to re-export modules with the same
* name such as:
* value.ml -> used into mem.ml, mem.ml must export [Value]
*
* To solve that, we do: [module Value = Value.Make (Hash) ]
* However, we lost our module [value.ml]/[Value] with this. At this
* stage, we can consider that it's fine but we must need to keep
* an occurence to our [value.ml] to be able to _pattern-match_
* on our [Value.t] where constructor are defined into [value.ml]
* but they are not defined into [Value.Make (Hash)].
*
* For the second point, we decided to remove any new types produced
* by functors and due to the fact that arities are not the same between
* ['hash Value.t] and [Value.Make(Hash).t], at this stage, despite some
* hacks (like on used about [Reference]), we must open our [value.ml]
* at the beginning. *)moduleMake(Digestif:Digestif.S)=structtypehash=Digestif.ttypenonrect=hashttypegit_store=t(* XXX(dinosaure): fix type alias. *)openValueopenReferencemoduleHash=Hash.Make(Digestif)moduleValue=Value.Make(Hash)moduleReference=structtypehash=Digestif.tinclude(Reference:moduletypeofReferencewithtype'uidcontents:='uidReference.contents)typecontents=hashReference.contentsendtypeerror=[`Not_foundofHash.t|`Reference_not_foundofReference.t|`Cycle|`Msgofstring]letpp_errorppf=function|`Not_foundhash->Fmt.pfppf"%a not found"Hash.pphash|`Reference_not_foundr->Fmt.pfppf"%a not found"Reference.ppr|`Cycle->Fmt.pfppf"Got a reference cycle"|`Msgerr->Fmt.stringppferrletroot{root;_}=rootletdotgit{dotgit;_}=dotgitletv?dotgitroot=letdotgit=matchdotgitwithSomev->v|None->Fpath.(root/".git")inLwt.return_ok{values=Hashtbl.create1024;inflated=Hashtbl.create1024;refs=Hashtbl.create8;head=None;shallows=Shallow.make[];root;dotgit;}letresett=Log.info(funl->l"Reset memory store.");Hashtbl.resett.values;Hashtbl.resett.inflated;Hashtbl.resett.refs;t.head<-None;Log.debug(funl->l"Elements into refs: %d."(Hashtbl.lengtht.refs));Lwt.return_ok()letwritetvalue=Log.debug(funm->m"Write a new value into the store: %a."Value.ppvalue);lethash=Value.digestvalueinLog.debug(funm->m"Store %a."Hash.pphash);ifHashtbl.memt.valueshashthenLwt.return(Ok(hash,0))else(Hashtbl.addt.valueshash(lazyvalue);Lwt.return_ok(hash,Int64.to_int(Value.lengthvalue)))letdigestkindraw=letlen=Cstruct.lenrawinletctx=Hash.init()inlethdr=Fmt.str"%s %d\000%!"(matchkindwith|`Commit->"commit"|`Blob->"blob"|`Tree->"tree"|`Tag->"tag")leninletctx=Hash.feed_stringctxhdrinletctx=Hash.feed_bigstringctx(Cstruct.to_bigarrayraw)inHash.getctxletwrite_inflatedt~kindinflated=Log.debug(funm->m"Write inflated Git object.");lethash=digestkindinflatedinifHashtbl.memt.valueshashthenLwt.returnhashelseletvalue=lazy(matchValue.of_raw~kindinflatedwith|Error(`Msgerr)->letstr=Fmt.str"Value.of_raw(%a): %s"Hash.pphasherrinraise(Failurestr)|Okvalue->value)inHashtbl.addt.inflatedhash(kind,inflated);Hashtbl.addt.valueshashvalue;Lwt.returnhashletread_inflatedth=tryletvalue=Lazy.force(Hashtbl.findt.valuesh)inletkind=matchvaluewith|Commit_->`Commit|Blob_->`Blob|Tree_->`Tree|Tag_->`Taginletraw=Value.to_raw_without_headervalueinLwt.return_some(kind,Cstruct.of_stringraw)withNot_found->(tryletkind,raw=Hashtbl.findt.inflatedhinLwt.return_some(kind,raw)withNot_found->Lwt.return_none)letreadth=tryOk(Lazy.force(Hashtbl.findt.valuesh))withNot_found->(tryletkind,raw=Hashtbl.findt.inflatedhinmatchValue.of_raw~kindrawwith|Okv->Hashtbl.addt.valuesh(lazyv);Okv|Error(`Msgerr)->letstr=Fmt.str"Value.of_raw(%a): %s"Hash.ppherrinraise(Failurestr)withNot_found->Error(`Not_foundh))letkeyst=Hashtbl.fold(funk_l->k::l)t[]letlistt=Lwt.return(List.sort_uniqHash.compare(keyst.values@keyst.inflated))letmemth=Lwt.return(Hashtbl.memt.valuesh||Hashtbl.memt.inflatedh)letsizeth=letv=matchreadthwith|Ok(Blobv)->Ok(Value.Blob.lengthv)|Ok(Commit_|Tag_|Tree_)|Error_->(* TODO(dinosaure): shallow? *)Error(`Not_foundh)inLwt.returnvletread_exnth=matchreadthwith|Error_->Lwt.fail(failuref"%a not found"Hash.pph)|Okv->Lwt.returnvletcontentst=letopenLwt.Infixinlistt>>=funhashes->letres=List.fold_left(funacch->matchreadthwithOkv->(h,v)::acc|Error_->acc)[]hashesinLwt.returnresletreadth=matchreadthwith|Ok_asv->Lwt.returnv|Error_aserr->Lwt.returnerrletis_shallowedthash=Shallow.existst.shallows~equal:Hash.equalhashletshallowedt=Shallow.gett.shallowsletshallowthash=Shallow.appendt.shallowshashletunshallowthash=Shallow.removet.shallows~equal:Hash.equalhashmoduleTraverse=Traverse_bfs.Make(structmoduleHash=HashmoduleValue=Valuetypenonrect=git_storeletroot{root;_}=rootletread_exn=read_exnletis_shallowed=is_shallowedend)letfold=Traverse.foldletiter=Traverse.iter(* XXX(dinosaure): extraction of Git objects from a PACK file stored
into a [Cstruct.t] is not scheduled by any blocking _syscall_. In this
context, the best is to do the extraction without the [lwt] _monad_. *)letbatch_writet_~pck~idx=letopenLwt.Infixinletrecflatstreambuf=stream()>>=function|Somestr->Buffer.add_stringbufstr;flatstreambuf|None->Lwt.return(Buffer.contentsbuf)in(* TODO(dinosaure): do first-pass instead to store all into a [string]. *)flatpck(Buffer.create0x100)>>=funpck_contents->flatidx(Buffer.create0x100)>>=funidx_contents->letindex=Carton.Dec.Idx.make(Bigstringaf.of_string~off:0~len:(String.lengthidx_contents)idx_contents)~uid_ln:Hash.length~uid_rw:Hash.to_raw_string~uid_wr:Hash.of_raw_stringinletiterindex~f=letf~uid~offset~crc:_=fuidoffsetinCarton.Dec.Idx.iter~findexinletmappck_contents~poslen=letpos=Int64.to_intposinletlen=min(String.lengthpck_contents-pos)leninBigstringaf.of_string~off:pos~lenpck_contentsinbatch_writet~uid_ln:Hash.length~uid_rw:Hash.of_raw_string~map~iterpck_contentsindex;Lwt.return_ok()moduleRef=structmoduleGraph=Reference.Mapletlistt=Log.debug(funl->l"Ref.list.");letgraph,rest=Hashtbl.fold(funk->function|`Rptr->fun(a,r)->a,(k,ptr)::r|`Hhash->fun(a,r)->Graph.addkhasha,r)t.refs(Graph.empty,[])inletgraph=List.fold_left(funa(k,ptr)->tryletv=Graph.findptrainGraph.addkvawithNot_found->a)graphrestinletr=Graph.fold(funkva->(k,v)::a)graph[]inLwt.returnrletmemtr=Log.debug(funl->l"Ref.mem %a."Reference.ppr);trylet_=Hashtbl.findt.refsrinLwt.returntruewithNot_found->Lwt.returnfalseexceptionCycleletresolvetr=letrecgo~visitedr=Log.debug(funl->l"Ref.resolve %a."Reference.ppr);tryifList.exists(Reference.equalr)visitedthenraiseCycle;matchHashtbl.findt.refsrwith|`Hs->Log.debug(funl->l"Ref.resolve %a found: %a."Reference.pprHash.pps);Lwt.return_oks|`Rr'->letvisited=r::visitedingo~visitedr'with|Not_found->Log.err(funl->l"%a not found."Reference.ppr);Lwt.return_error(`Reference_not_foundr)|Cycle->Log.err(funl->l"Got a reference cycle");Lwt.return_error`Cycleingo~visited:[]rletreadtr=trymatchHashtbl.findt.refsrwith|`Hhash->Lwt.return_ok(Reference.uidhash)|`Rrefname->Lwt.return_ok(Reference.refrefname)withNot_found->Lwt.return_error(`Reference_not_foundr)letremovetr=Log.debug(funl->l"Ref.remove %a."Reference.ppr);Hashtbl.removet.refsr;Lwt.return_ok()letwritetrvalue=Log.debug(funl->l"Ref.write %a."Reference.ppr);lethead_contents=matchvaluewithUidhash->`Hhash|Refrefname->`RrefnameinHashtbl.replacet.refsrhead_contents;Lwt.return_ok()endlethas_global_watches=falselethas_global_checkout=falseendmoduleStore=Make(Digestif.SHA1)moduleSync(Git_store:Minimal.S)(HTTP:Smart_git.HTTP)=structletsrc=Logs.Src.create"git-mem.sync"~doc:"logs git-mem's sync event"moduleLog=(valLogs.src_logsrc:Logs.LOG)moduleIdx=Carton.Dec.Idx.M(Lwt)(Git_store.Hash)moduleIndex=structtype+'afiber='aLwt.tinclude(Idx:moduletypeofIdxwithtypefd:=Idx.fd)(* XXX(dinosaure): may be update [Carton.Dec.Idx.M], but it seems fine. *)type'ard=<rd:unit;..>as'atype'awr=<wr:unit;..>as'atype'amode=|Rd:<rd:unit>mode|Wr:<wr:unit>mode|RdWr:<rd:unit;wr:unit>modetype'mfd=Idx.fdletcreate:typea.mode:amode->t->uid->(afd,error)resultfiber=fun~mode:_tuid->createtuidletmove_~src:_~dst:_=assertfalseletmap__~pos:__=assertfalseendincludeSync.Make(Git_store.Hash)(Cstruct_append)(Index)(Git_store)(HTTP)letstream_of_cstruct?(chunk=0x1000)payload=letstream,emitter=Lwt_stream.create()inletfill()=letrecgopos=ifpos=Cstruct.lenpayloadthen(emitterNone;Lwt.return_unit)elseletlen=minchunk(Cstruct.lenpayload-pos)inlettmp=Bytes.createleninCstruct.blit_to_bytespayloadpostmp0len;emitter(Some(Bytes.unsafe_to_stringtmp));go(pos+len)ingo0inLwt.asyncfill;fun()->Lwt_stream.getstreamletfetch?(push_stdout=ignore)?(push_stderr=ignore)~ctxednstore?version?capabilities?deepenwant=lett_idx=Carton.Dec.Idx.Device.device()inlett_pck=Cstruct_append.device()inletindex=Carton.Dec.Idx.Device.createt_idxinletsrc=Cstruct_append.keyt_pckinletdst=Cstruct_append.keyt_pckinletcreate_idx_stream()=Carton.Dec.Idx.Device.projectt_idxindex|>Cstruct.of_bigarray|>stream_of_cstructinletcreate_pack_stream()=letpack=Cstruct_append.projectt_pckdstinstream_of_cstructpackinfetch~push_stdout~push_stderr~ctxednstore?version?capabilities?deepenwant~src~dst~idx:index~create_idx_stream~create_pack_streamt_pckt_idxend