123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)(* Copyright (c) 2018-2021 Nomadic Labs. <contact@nomadic-labs.com> *)(* Copyright (c) 2018-2020 Tarides <contact@tarides.com> *)(* Copyright (c) 2020 Metastate AG <hello@metastate.dev> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)includeContext_dump_intf(*****************************************************************************)typeerror+=|System_write_errorofstring|Context_not_foundofBytes.t|System_read_errorofstring|Inconsistent_context_dump|Restore_context_failurelet()=letopenData_encodinginregister_error_kind`Permanent~id:"context_dump.writing_error"~title:"Writing error"~description:"Cannot write in file for context dump"~pp:(funppfs->Format.fprintfppf"Unable to write file for context dumping: %s"s)(obj1(req"context_dump_no_space"string))(functionSystem_write_errors->Somes|_->None)(funs->System_write_errors);register_error_kind`Permanent~id:"context_dump.context_not_found"~title:"Context not found"~description:"Cannot find context corresponding to hash"~pp:(funppfmb->Format.fprintfppf"No context with hash: %s"(Bytes.to_stringmb))(obj1(req"context_not_found"bytes))(functionContext_not_foundmb->Somemb|_->None)(funmb->Context_not_foundmb);register_error_kind`Permanent~id:"context_dump.system_read_error"~title:"System read error"~description:"Failed to read file"~pp:(funppfuerr->Format.fprintfppf"Error while reading file for context dumping: %s"uerr)(obj1(req"system_read_error"string))(functionSystem_read_errore->Somee|_->None)(fune->System_read_errore);register_error_kind`Permanent~id:"context_dump.inconsistent_context_dump"~title:"Inconsistent context dump"~description:"Error while reading context dump"~pp:(funppf()->Format.fprintfppf"Failed to read context dump. The provided file is inconsistent.")empty(functionInconsistent_context_dump->Some()|_->None)(fun()->Inconsistent_context_dump);register_error_kind`Permanent~id:"context_dump.restore_context_failure"~title:"Failed to restore context"~description:"Internal error while restoring the context"~pp:(funppf()->Format.fprintfppf"Internal error while restoring the context.")empty(functionRestore_context_failure->Some()|_->None)(fun()->Restore_context_failure)(* IO toolkit. *)letrecread_stringrbuf~len=letopenLwt_result_syntaxinletfd,buf,ofs,total=!rbufinifBytes.lengthbuf-ofs<lenthen(letblen=Bytes.lengthbuf-ofsinletneu=Bytes.create(blen+1_000_000)inBytes.blitbufofsneu0blen;let*!bread=Lwt_unix.readfdneublen1_000_000intotal:=!total+bread;ifbread=0thentzfailInconsistent_context_dumpelseletneu=ifbread<>1_000_000thenBytes.subneu0(blen+bread)elseneuinrbuf:=(fd,neu,0,total);read_stringrbuf~len)elseletres=Bytes.sub_stringbufofsleninrbuf:=(fd,buf,ofs+len,total);returnresletread_mbytesrbufb=letopenLwt_result_syntaxinlet*string=read_stringrbuf~len:(Bytes.lengthb)inBytes.blit_stringstring0b0(Bytes.lengthb);return_unitletget_int64rbuf=letopenLwt_result_syntaxinlet*s=read_string~len:8rbufinreturn@@EndianString.BigEndian.get_int64s0moduleMake(I:Dump_interface)=structtypecommand=|Root|Blobofbytes|InodeofI.Snapshot.inode|Eocof{info:I.commit_info;parents:I.Commit_hash.tlist}|Eof(* Command encoding. *)letblob_encoding=letopenData_encodingincase~title:"blob"(Tag(Char.code'b'))bytes(functionBlobb->Someb|_->None)(functionb->Blobb)letinode_encoding=letopenData_encodingincase~title:"inode"(Tag(Char.code'i'))I.Snapshot.encoding(functionInodeb->Someb|_->None)(functionb->Inodeb)leteof_encoding=letopenData_encodingincase~title:"eof"(Tag(Char.code'e'))empty(functionEof->Some()|_->None)(fun()->Eof)letroot_encoding=letopenData_encodingincase~title:"root"(Tag(Char.code'r'))empty(functionRoot->Some()|_->None)(fun()->Root)leteoc_encoding=letopenData_encodingincase~title:"eoc"(Tag(Char.code'c'))(obj2(req"info"I.commit_info_encoding)(req"parents"(listI.Commit_hash.encoding)))(functionEoc{info;parents}->Some(info,parents)|_->None)(fun(info,parents)->Eoc{info;parents})letcommand_encoding=Data_encoding.union~tag_size:`Uint8[blob_encoding;eoc_encoding;root_encoding;eof_encoding;inode_encoding]letget_mbytesrbuf=letopenLwt_result_syntaxinlet*size=get_int64rbufinletb=Bytes.create(Int64.to_intsize)inlet*()=read_mbytesrbufbinreturnbletget_commandrbuf=letopenLwt_result_syntaxinlet*bytes=get_mbytesrbufinreturn(Data_encoding.Binary.of_bytes_exncommand_encodingbytes)(* Restoring *)letrestore_context_fdindex~expected_context_hash~fd~nb_context_elements~in_memory~progress_display_mode=letopenLwt_result_syntaxinletread=ref0inletrbuf=ref(fd,Bytes.empty,0,read)in(* Editing the repository *)letimport_t=I.v_import~in_memoryindexinletsave_inode=I.save_inodeindeximport_tinletadd_inodei=let*!tree=save_inodeiinmatchtreewith|None->tzfailRestore_context_failure|Sometree->returntreeinletrestore()=letfirst_pass()=let*r=get_commandrbufinmatchrwith|Root->return_unit|_->tzfailInconsistent_context_dumpinletrecsecond_passbatchctxtcontext_hashnotify=let*!()=notify()inlet*c=get_commandrbufinmatchcwith|Inodei->let*tree=add_inode(Inodei)insecond_passbatch(I.update_contextctxttree)context_hashnotify|Blobdata->let*tree=add_inode(Blobdata)insecond_passbatch(I.update_contextctxttree)context_hashnotify|Eoc{info;parents}->(let*!b=I.set_context~info~parentsctxtcontext_hashinmatchbwith|false->tzfailInconsistent_context_dump|true->return_unit)|_->tzfailInconsistent_context_dumpinletcheck_eof()=let*e=get_commandrbufinmatchewith|Eof->I.close_importimport_tindex;return_unit|_->tzfailInconsistent_context_dumpinlet*()=first_pass()inlet*()=Animation.display_progress~every:1000~progress_display_mode~pp_print_step:(funfmti->Format.fprintffmt"Writing context: %dK/%dK (%d%%) elements, %s read"(i/1_000)(nb_context_elements/1_000)(100*i/nb_context_elements)(if!read>1_048_576thenFormat.asprintf"%dMiB"(!read/1_048_576)elseFormat.asprintf"%dKiB"(!read/1_024)))(funnotify->I.batchindex(funbatch->second_passbatch(I.make_contextindex)expected_context_hashnotify))inlet*()=check_eof()inreturn_unitinLwt.catch(fun()->restore())(function|Unix.Unix_error(e,_,_)->tzfail@@System_read_error(Unix.error_messagee)|err->Lwt.reraiseerr)end