Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file store.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784(*
* Copyright (c) 2018-2022 Tarides <contact@tarides.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.
*)open!ImportincludeStore_intfmoduleMaker(Config:Conf.S)=structtypeendpoint=unitincludePack_key.Store_specmoduleMake(Schema:Irmin.Schema.Extended)=structopenstructmoduleP=Schema.PathmoduleM=Schema.MetadatamoduleC=Schema.ContentsmoduleB=Schema.BranchendmoduleH=Schema.HashmoduleIo=Io.UnixmoduleIndex=Pack_index.Make(H)moduleErrs=Io_errors.Make(Io)moduleFile_manager=File_manager.Make(Io)(Index)(Errs)moduleDict=Dict.Make(File_manager)moduleDispatcher=Dispatcher.Make(File_manager)moduleXKey=Pack_key.Make(H)moduleX=structmoduleHash=Htype'avalue={hash:H.t;kind:Pack_value.Kind.t;v:'a}[@@derivingirmin]moduleContents=structmodulePack_value=Pack_value.Of_contents(Config)(H)(XKey)(C)moduleCA=Pack_store.Make(File_manager)(Dict)(Dispatcher)(H)(Pack_value)(Errs)includeIrmin.Contents.Store_indexable(CA)(H)(C)endmoduleNode=structmoduleValue=Schema.Node(XKey)(XKey)moduleCA=structmoduleInter=Irmin_pack.Inode.Make_internal(Config)(H)(XKey)(Value)modulePack'=Pack_store.Make(File_manager)(Dict)(Dispatcher)(H)(Inter.Raw)(Errs)includeInode.Make_persistent(H)(Value)(Inter)(Pack')endincludeIrmin.Node.Generic_key.Store(Contents)(CA)(H)(CA.Val)(M)(P)endmoduleNode_portable=Node.CA.Val.PortablemoduleSchema=structincludeSchemamoduleNode=NodeendmoduleCommit=structmoduleValue=structincludeSchema.Commit(Node.Key)(XKey)moduleInfo=Schema.Infotypehash=Hash.t[@@derivingirmin]endmodulePack_value=Pack_value.Of_commit(H)(XKey)(Value)moduleCA=Pack_store.Make(File_manager)(Dict)(Dispatcher)(H)(Pack_value)(Errs)includeIrmin.Commit.Generic_key.Store(Schema.Info)(Node)(CA)(H)(Value)endmoduleCommit_portable=structmoduleHash_key=Irmin.Key.Of_hash(Hash)includeSchema.Commit(Hash_key)(Hash_key)letof_commit:Commit.Value.t->t=funt->letinfo=Commit.Value.infotandnode=Commit.Value.nodet|>XKey.to_hashandparents=Commit.Value.parentst|>List.mapXKey.to_hashinv~info~node~parentsmoduleInfo=Schema.Infotypehash=Hash.t[@@derivingirmin]endmoduleBranch=structmoduleKey=BmoduleVal=XKeymoduleAW=Atomic_write.Make_persistent(Key)(Val)includeAtomic_write.Closeable(AW)letv?fresh?readonlypath=AW.v?fresh?readonlypath>|=make_closeableendmoduleSlice=Irmin.Backend.Slice.Make(Contents)(Node)(Commit)moduleRemote=Irmin.Backend.Remote.None(Commit.Key)(B)moduleGc=Gc.Make(structmoduleAsync=Async.UnixmoduleFm=File_managermoduleErrs=ErrsmoduleDict=DictmoduleDispatcher=DispatchermoduleHash=Schema.HashmoduleContents_store=Contents.CAmoduleNode_value=Node.CA.Inter.ValmoduleNode_store=Node.CAmoduleCommit_value=Commit.ValuemoduleCommit_store=Commit.CAtypehash=Node_value.hashtypekey=Node_value.node_key[@@derivingirmin]end)moduleRepo=structtyperunning_gc={gc:Gc.t;use_auto_finalisation:bool}typet={lru:Lru.t;config:Irmin.Backend.Conf.t;contents:readContents.CA.t;node:readNode.CA.t;commit:readCommit.CA.t;branch:Branch.t;fm:File_manager.t;dict:Dict.t;dispatcher:Dispatcher.t;mutableduring_batch:bool;mutablerunning_gc:running_gcoption;}letpp_key=Irmin.Type.ppXKey.tletcontents_tt:'aContents.t=t.contentsletnode_tt:'aNode.t=(contents_tt,t.node)letcommit_tt:'aCommit.t=(node_tt,t.commit)letbranch_tt=t.branchletconfigt=t.configletvconfig=letroot=Irmin_pack.Conf.rootconfiginletfresh=Irmin_pack.Conf.freshconfiginletfm=letreadonly=Irmin_pack.Conf.readonlyconfiginifreadonlythenFile_manager.open_roconfig|>Errs.raise_if_errorelsematch(Io.classify_pathroot,fresh)with|`No_such_file_or_directory,_->File_manager.create_rw~overwrite:falseconfig|>Errs.raise_if_error|`Directory,true->File_manager.create_rw~overwrite:trueconfig|>Errs.raise_if_error|`Directory,false->File_manager.open_rwconfig|>Errs.raise_if_error|(`File|`Other),_->Errs.raise_error(`Not_a_directoryroot)inletdict=Dict.vfm|>Errs.raise_if_errorinletdispatcher=Dispatcher.vfm|>Errs.raise_if_errorinletlru=Lru.createconfiginletcontents=Contents.CA.v~config~fm~dict~dispatcher~lruinletnode=Node.CA.v~config~fm~dict~dispatcher~lruinletcommit=Commit.CA.v~config~fm~dict~dispatcher~lruinlet+branch=letroot=Conf.rootconfiginletfresh=Conf.freshconfiginletreadonly=Conf.readonlyconfiginletpath=Irmin_pack.Layout.V4.branch~rootinBranch.v~fresh~readonlypathinletduring_batch=falseinletrunning_gc=Nonein{config;contents;node;commit;branch;fm;dict;during_batch;running_gc;dispatcher;lru;}letflusht=File_manager.flush?hook:Nonet.fm|>Errs.raise_if_errorletfsynct=File_manager.fsynct.fm|>Errs.raise_if_errorletreloadt=File_manager.reloadt.fm|>Errs.raise_if_errormoduleGc=structletis_allowed{fm;_}=File_manager.gc_allowedfmletbehaviour{fm;_}=File_manager.gc_behaviourfmletcancelt=matcht.running_gcwith|Some{gc;_}->letcancelled=Gc.cancelgcint.running_gc<-None;cancelled|None->falseletdirect_commit_keytkey=letstate:_Pack_key.state=Pack_key.inspectkeyinmatchstatewith|Direct_->Okkey|Indexedh->(matchCommit.CA.index_direct_with_kindt.commithwith|None->Error(`Commit_key_is_dangling(Irmin.Type.to_stringXKey.tkey))|Some(k,_kind)->Okk)letstart~unlink~use_auto_finalisation~outputtcommit_key=letopenResult_syntaxin[%log.info"GC: Starting on %a"pp_keycommit_key];let*()=ift.during_batchthenError`Gc_forbidden_during_batchelseOk()inlet*commit_key=direct_commit_keytcommit_keyinletroot=Conf.roott.configinlet*()=ifnot(is_allowedt)thenError(`Gc_disallowed"Store does not support GC")elseOk()inletcurrent_generation=File_manager.generationt.fminletnext_generation=current_generation+1inletlower_root=Conf.lower_roott.configinlet*gc=Gc.v~root~lower_root~generation:next_generation~unlink~dispatcher:t.dispatcher~fm:t.fm~contents:t.contents~node:t.node~commit:t.commit~outputcommit_keyint.running_gc<-Some{gc;use_auto_finalisation};Ok()letstart_exn?(unlink=true)?(output=`Root)~use_auto_finalisationtcommit_key=matcht.running_gcwith|Some_->[%log.info"Repo is alreadying running GC. Skipping."];Lwt.returnfalse|None->(letresult=start~unlink~use_auto_finalisation~outputtcommit_keyinmatchresultwith|Ok_->Lwt.returntrue|Errore->Errs.raise_errore)letfinalise_exn?(wait=false)t=let*result=matcht.running_gcwith|None->Lwt.return_ok`Idle|Some{gc;_}->ift.during_batchthenLwt.return_error`Gc_forbidden_during_batchelseGc.finalise~waitgcinmatchresultwith|Ok(`Finalised_asx)->t.running_gc<-None;Lwt.returnx|Okwaited->Lwt.returnwaited|Errore->t.running_gc<-None;Errs.raise_erroreletis_finishedt=Option.is_nonet.running_gcleton_finalisetf=matcht.running_gcwith|None->()|Some{gc;_}->Gc.on_finalisegcflettry_auto_finalise_exnt=matcht.running_gcwith|None|Some{use_auto_finalisation=false;_}->Lwt.return_unit|Some{use_auto_finalisation=true;_}->let*_=finalise_exn~wait:falsetinLwt.return_unitletlatest_gc_targett=letpl=File_manager.(Control.payload(controlt.fm))inmatchpl.statuswith|From_v1_v2_post_upgrade_|Used_non_minimal_indexing_strategy|No_gc_yet->None|T1|T2|T3|T4|T5|T6|T7|T8|T9|T10|T11|T12|T13|T14|T15->assertfalse|Gced{latest_gc_target_offset=offset;_}whenoffset=Int63.zero->None|Gced{latest_gc_target_offset=offset;_}->(letentry=Commit.CA.read_and_decode_entry_prefix~off:offsett.dispatcherinmatchCommit.CA.Entry_prefix.total_entry_lengthentrywith|None->(* Commits on which this operation is supported have a
length in their header. *)assertfalse|Somelength->letkey=Pack_key.v_direct~offset~lengthentry.hashinSomekey)letcreate_one_commit_storetcommit_keypath=let()=matchIo.classify_pathpathwith|`Directory->()|`No_such_file_or_directory->Io.mkdirpath|>Errs.raise_if_error|_->Errs.raise_error`Invalid_layoutinletcommit_key=direct_commit_keytcommit_key|>Errs.raise_if_errorin(* The GC action here does not matter, since we'll not fully
finalise it *)let*launched=start_exn~use_auto_finalisation:false~output:(`Externalpath)tcommit_keyinlet()=ifnotlaunchedthenErrs.raise_error`Forbidden_during_gcinlet*gced=matcht.running_gcwith|None->assertfalse|Some{gc;_}->Gc.finalise_without_swapgcinletconfig=Irmin.Backend.Conf.addt.configConf.Key.rootpathinlet()=File_manager.create_one_commit_storet.fmconfiggcedcommit_key|>Errs.raise_if_errorinletbranch_path=Irmin_pack.Layout.V4.branch~root:pathinlet*branch_store=Branch.v~fresh:true~readonly:falsebranch_pathinlet*()=Branch.closebranch_storeinLwt.return_unitendletis_split_allowed=Gc.is_allowedletsplitt=letopenResult_syntaxinletreadonly=Irmin_pack.Conf.readonlyt.configinlet*()=ifnot(is_split_allowedt)thenError`Split_disallowedelseOk()inlet*()=ifreadonlythenError`Ro_not_allowedelseOk()inlet*()=ift.during_batchthenError`Split_forbidden_during_batchelseOk()inFile_manager.splitt.fmletsplit_exnrepo=splitrepo|>Errs.raise_if_errorletadd_volume_exnt=let()=ifIrmin_pack.Conf.readonlyt.configthenErrs.raise_error`Ro_not_allowed;ifGc.is_finishedt=falsethenErrs.raise_error`Add_volume_forbidden_during_gcinFile_manager.add_volumet.fm|>Errs.raise_if_errorletbatchtf=[%log.debug"[pack] batch start"];letreadonly=Irmin_pack.Conf.readonlyt.configinifreadonlythenErrs.raise_error`Ro_not_allowedelseletc0=Mtime_clock.counter()inlettry_finalise()=Gc.try_auto_finalise_exntinlet*_=try_finalise()int.during_batch<-true;letcontents=Contents.CA.castt.contentsinletnode=Node.CA.Pack.castt.nodeinletcommit=Commit.CA.castt.commitinletcontents:'aContents.t=contentsinletnode:'aNode.t=(contents,node)inletcommit:'aCommit.t=(node,commit)inleton_successres=lets=Mtime_clock.countc0|>Mtime.span_to_sin[%log.info"[pack] batch completed in %.6fs"s];t.during_batch<-false;File_manager.flusht.fm|>Errs.raise_if_error;let*_=try_finalise()inLwt.returnresinleton_failexn=t.during_batch<-false;[%log.info"[pack] batch failed. calling flush. (%s)"(Printexc.to_stringexn)];let()=matchFile_manager.flusht.fmwith|Ok()->()|Errorerr->[%log.err"[pack] batch failed and flush failed. Silencing flush \
fail. (%a)"(Irmin.Type.ppErrs.t)err]in(* Kill gc process in at_exit. *)raiseexninLwt.try_bind(fun()->fcontentsnodecommit)on_successon_failletcloset=(* Step 1 - Kill the gc process if it is running *)let_=Gc.canceltin(* Step 2 - Close the files *)let()=File_manager.closet.fm|>Errs.raise_if_errorinBranch.closet.branch>>=fun()->(* Step 3 - Close the in-memory abstractions *)Dict.closet.dict;Contents.CA.close(contents_tt)>>=fun()->Node.CA.close(snd(node_tt))>>=fun()->Commit.CA.close(snd(commit_tt))endendincludeIrmin.Of_backend(X)moduleIntegrity_checks=Checks.Integrity_checks(XKey)(X)(Index)letintegrity_check_inodes?headst=let*heads=matchheadswithNone->Repo.headst|Somem->Lwt.returnminlethashes=List.map(funx->`Commit(Commit.keyx))headsinletiter~pred_node~node~committ=Repo.iter~cache_size:1_000_000~min:[]~max:hashes~pred_node~node~committinletnodes=X.Repo.node_tt|>sndinletcheck=X.Node.CA.integrity_check_inodesnodesinletpred=Repo.default_pred_nodeinIntegrity_checks.check_inodes~iter~pred~checktletintegrity_check_always?ppf~auto_repairt=letcontents=X.Repo.contents_ttinletnodes=X.Repo.node_tt|>sndinletcommits=X.Repo.commit_tt|>sndinletcheck~kind~offset~lengthk=matchkindwith|`Contents->X.Contents.CA.integrity_check~offset~lengthkcontents|`Node->X.Node.CA.integrity_check~offset~lengthknodes|`Commit->X.Commit.CA.integrity_check~offset~lengthkcommitsinletindex=File_manager.indext.fminIntegrity_checks.check_always?ppf~auto_repair~checkindexletintegrity_check_minimal?ppf?headst=let*heads=matchheadswithNone->Repo.headst|Somem->Lwt.returnminlethashes=List.map(funx->`Commit(Commit.keyx))headsinletiter~contents~node~pred_node~pred_commitrepo=Repo.iter~cache_size:1_000_000~min:[]~max:hashes~contents~node~pred_node~pred_commitrepoinletcontents=X.Repo.contents_ttinletpred=X.Node.CA.Val.predinletrecompute_hash=X.Node.CA.Val.recompute_hashinletcheck~offset~lengthk=X.Contents.CA.integrity_check~offset~lengthkcontentsinIntegrity_checks.check_minimal?ppf~pred~iter~check~recompute_hashtletintegrity_check?ppf?heads~auto_repairt=letis_minimal=t.X.Repo.config|>Conf.indexing_strategy|>Irmin_pack.Indexing_strategy.is_minimalinletresult=ifis_minimalthenintegrity_check_minimal?ppf?headstelseintegrity_check_always?ppf~auto_repairt|>Lwt.returninresultmoduleStats_computation=structletpp_key=Irmin.Type.ppXKey.tlettraverse_inodes~dump_blob_paths_tocommitrepo=letmoduleStats=Checks.Stats(structtypenonrecstep=stepletstep_t=step_tmoduleHash=Hashend)inlett=Stats.v()inletpred_noderepok=X.Node.find(X.Repo.node_trepo)k>|=function|None->Fmt.failwith"key %a not found"pp_keyk|Somev->letwidth=X.Node.Val.lengthvinletnb_children=X.Node.CA.Val.nb_childrenvinletpreds=X.Node.CA.Val.predvinlet()=preds|>List.map(function|s,`Contentsh->(s,`Contents(XKey.to_hashh))|s,`Inodeh->(s,`Inode(XKey.to_hashh))|s,`Nodeh->(s,`Node(XKey.to_hashh)))|>Stats.visit_nodet(XKey.to_hashk)~width~nb_childreninList.rev_map(function|s,`Inodex->assert(s=None);`Nodex|_,`Nodex->`Nodex|_,`Contentsx->`Contentsx)predsin(* We are traversing only one commit. *)letpred_commitrepok=X.Commit.find(X.Repo.commit_trepo)k>|=function|None->[]|Somec->letnode=X.Commit.Val.nodecinStats.visit_committ(XKey.to_hashnode);[`Nodenode]inletpred_contents_repok=Stats.visit_contentst(XKey.to_hashk);Lwt.return[]in(* We want to discover all paths to a node, so we don't cache nodes
during traversal. *)let*()=Repo.breadth_first_traversal~cache_size:0~pred_node~pred_commit~pred_contents~max:[commit]repoinStats.pp_results~dump_blob_paths_tot;Lwt.return_unitletrun~dump_blob_paths_to~commitrepo=Printexc.record_backtracetrue;letkey=`Commit(Commit.keycommit)intraverse_inodes~dump_blob_paths_tokeyrepoendletstats=Stats_computation.runletreload=X.Repo.reloadletflush=X.Repo.flushletfsync=X.Repo.fsyncletis_split_allowed=X.Repo.is_split_allowedletsplit=X.Repo.split_exnletadd_volume=X.Repo.add_volume_exnletcreate_one_commit_store=X.Repo.Gc.create_one_commit_storemoduleGc=structtypemsg=[`Msgofstring]typeprocess_state=[`Idle|`Running|`FinalisedofStats.Latest_gc.stats]letcatch_errorscontexterror=leterr=matcherrorwith|Errors.Pack_errorerror->Fmt.str"Pack_error: %a"Errors.pp_base_errorerror|Irmin.Closed->"Irmin.Closed"|Irmin_pack.RO_not_allowed->"Irmin_pack.RO_not_allowed"|Unix.Unix_error(err,s1,s2)->letpp=Irmin.Type.ppIo.misc_error_tinFmt.str"Unix_error: %a"pp(err,s1,s2)|exn->raiseexninleterror_msg=Fmt.str"[%s] resulted in error: %s"contexterrinLwt.return_error(`Msgerror_msg)letmap_errorscontext(error:Errs.t)=leterr_msg=Fmt.str"[%s] resulted in error: %a"context(Irmin.Type.ppErrs.t)errorin`Msgerr_msgletfinalise_exn=X.Repo.Gc.finalise_exnletstart_exn?unlinkt=X.Repo.Gc.start_exn?unlink~use_auto_finalisation:falsetletstartrepocommit_key=trylet*started=X.Repo.Gc.start_exn~unlink:true~use_auto_finalisation:truerepocommit_keyinLwt.return_okstartedwithexn->catch_errors"Start GC"exnletis_finished=X.Repo.Gc.is_finishedletbehaviour=X.Repo.Gc.behaviourletwaitrepo=trylet*result=finalise_exn~wait:truerepoinmatchresultwith|`Running->assertfalse(* [~wait:true] should never return [Running] *)|`Idle->Lwt.return_okNone|`Finalisedstats->Lwt.return_ok@@Somestatswithexn->catch_errors"Wait for GC"exnletrun?(finished=fun_->Lwt.return_unit)repocommit_key=let*started=startrepocommit_keyinmatchstartedwith|Okr->ifrthenX.Repo.Gc.on_finaliserepo(funfinalisation_r->matchfinalisation_rwith|Ok_asstats->finishedstats|Errorerr->leterr_msg=map_errors"Finalise GC"errinfinished@@Errorerr_msg);Lwt.return_okr|Error_ase->Lwt.returneletis_allowed=X.Repo.Gc.is_allowedletcancelrepo=X.Repo.Gc.cancelrepoletlatest_gc_target=X.Repo.Gc.latest_gc_targetendmoduleTraverse_pack_file=Traverse_pack_file.Make(structmoduleFile_manager=File_managermoduleDispatcher=DispatchermoduleHash=HmoduleIndex=IndexmoduleInode=X.Node.CAmoduleDict=DictmoduleContents=X.Contents.Pack_valuemoduleCommit=X.Commit.Pack_valueend)lettraverse_pack_file=Traverse_pack_file.runlettest_traverse_pack_file=Traverse_pack_file.testmoduleSnapshot=structincludeX.Node.CA.Snapshottypet=Inodeofinode|BlobofBackend.Contents.Val.t[@@derivingirmin]moduleS=Snapshot.Make(structmoduleHash=HmoduleInode=X.Node.CAmoduleContents_pack=X.Contents.CAmoduleFm=File_managermoduleDispatcher=Dispatcherend)includeSmoduleExport=structletiter?on_diskrepof~root_key=[%log.debug"Iterate over a tree"];letcontents=X.Repo.contents_trepoinletnodes=X.Repo.node_trepo|>sndinletexport=S.Export.vrepo.configcontentsnodesinletf_contentsx=f(Blobx)inletf_nodesx=f(Inodex)inmatchroot_keywith|`Contents_->Fmt.failwith"[root_key] cannot be of type contents"|`Nodekey->let*total=Export.run?on_diskexportf_contentsf_nodes(key,Pack_value.Kind.Inode_v2_root)inExport.closeexport|>Errs.raise_if_error;Lwt.returntotalendletexport=Export.itermoduleImport=structtypeprocess=Import.tletv?on_diskrepo=letcontents=X.Repo.contents_trepoinletnodes=X.Repo.node_trepo|>sndinletlog_size=Conf.index_log_sizerepo.configinImport.v?on_disklog_sizecontentsnodesletsave_eltprocesselt=matcheltwith|Blobx->Import.save_contentsprocessx|Inodex->Import.save_inodesprocessxletcloseprocessrepo=flushrepo;fsyncrepo;Import.closeprocessendendmoduleInternal=structmoduleIo=IomoduleErrs=ErrsmoduleIndex=IndexmoduleFile_manager=File_managerletfile_manager(repo:X.Repo.t)=repo.fmmoduleDict=Dictletdict(repo:X.Repo.t)=repo.dictmoduleDispatcher=Dispatcherletdispatcher(repo:X.Repo.t)=repo.dispatchermoduleXKey=XKeyletsuffix_commit_memrepokey=X.Commit.CA.unsafe_find~check_integrity:false(snd(X.Repo.commit_trepo))key|>Option.is_someletsuffix_node_memrepokey=X.Node.CA.unsafe_find~check_integrity:false(snd(X.Repo.node_trepo))key|>Option.is_someletsuffix_contents_memrepokey=X.Contents.CA.unsafe_find~check_integrity:false(X.Repo.contents_trepo)key|>Option.is_someletkill_gc(repo:X.Repo.t)=match(repo.running_gc:X.Repo.running_gcoption)with|None->false|Some{gc;_}->(tryX.Gc.cancelgcwithUnix.Unix_error(Unix.ESRCH,"kill",_)->false)endendend