package docteur-solo5
A simple read-only Key/Value from Git to MirageOS
Install
dune-project
Dependency
Authors
Maintainers
Sources
docteur-0.0.5.tbz
sha256=41bf2d7b493276f62cbdfa394c8f574727f1dee4c266dc94b587e7cad8cbcb8b
sha512=2be62425cd57c3a161d0346d29b9091045019446b16bacc298b101bf6861c5fcd5e6b19c71fb4e78be79dc182a3f79df3fcd81c2fc84ee618555ea21976d23fb
doc/src/docteur-solo5/fast.ml.html
Source file fast.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
(* * Copyright (c) 2011 Anil Madhavapeddy <anil@recoil.org> * Copyright (c) 2012 Citrix Systems Inc * Copyright (c) 2018 Martin Lucina <martin@lucina.net> * Copyright (c) 2021 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. *) let src = Logs.Src.create "pack" ~doc:"PACK file" module Log = (val Logs.src_log src : Logs.LOG) exception Unspecified of string let invalid_arg fmt = Fmt.kstr invalid_arg fmt let unspecified fmt = Fmt.kstr (fun str -> raise (Unspecified str)) fmt open Analyze open Solo5_os.Solo5 type solo5_block_info = { capacity : int64; block_size : int64 } external solo5_block_acquire : string -> solo5_result * int64 * solo5_block_info = "mirage_solo5_block_acquire" external solo5_block_read : int64 -> int64 -> Cstruct.buffer -> int -> int -> solo5_result = "mirage_solo5_block_read_3" let disconnect _id = Lwt.return_unit let read (handle, info) buf ~off ~len = assert (len <= Int64.to_int info.block_size - SHA1.length) ; let tmp = Bigstringaf.create (Int64.to_int info.block_size) in match solo5_block_read handle 0L tmp 0 (Int64.to_int info.block_size) with | SOLO5_R_OK -> Bigstringaf.blit_to_bytes tmp ~src_off:(SHA1.length + 8) buf ~dst_off:off ~len ; Scheduler.inj (Lwt.return len) | SOLO5_R_EINVAL -> invalid_arg "Block: read(): Invalid argument" | SOLO5_R_EUNSPEC -> unspecified "Block: read(): Unspecified error" | SOLO5_R_AGAIN -> assert false let get_block (handle, _info) pos buf off len = match solo5_block_read handle pos buf off len with | SOLO5_R_OK -> Ok () | SOLO5_R_AGAIN -> assert false | SOLO5_R_EINVAL -> invalid_arg "Block: read(): Invalid argument" | SOLO5_R_EUNSPEC -> unspecified "Block: read(): Unspecified error" type key = Mirage_kv.Key.t type error = [ `Invalid_store | `Msg of string | `Dictionary_expected of key | `Not_found of key | `Value_expected of key ] let pp_error ppf = function | `Invalid_store -> Fmt.pf ppf "Invalid store" | `Msg err -> Fmt.string ppf err | `Not_found key -> Fmt.pf ppf "%a not found" Mirage_kv.Key.pp key | `Dictionary_expected key -> Fmt.pf ppf "%a is not a directory" Mirage_kv.Key.pp key | `Value_expected key -> Fmt.pf ppf "%a is not a file" Mirage_kv.Key.pp key type t = { name : string; handle : int64; capacity : int64; block_size : int64; pack : (int64 * solo5_block_info, SHA1.t) Carton.Dec.t; buffers : (int64 * solo5_block_info) Analyze.buffers Lwt_pool.t; directories : SHA1.t Art.t; (* TODO(dinosaure): implements [prefix]. *) files : SHA1.t Art.t; } let connect ?(analyze = false) name = match solo5_block_acquire name with | SOLO5_R_AGAIN, _, _ -> assert false (* not returned by solo5_block_acquire *) | SOLO5_R_EINVAL, _, _ -> invalid_arg "Block: connect(%s): Invalid argument" name | SOLO5_R_EUNSPEC, _, _ -> unspecified "Block: connect(%s): Unspecified error" name | SOLO5_R_OK, handle, info -> ( let commit = Bigstringaf.create (Int64.to_int info.block_size) in match solo5_block_read handle 0L commit 0 (Int64.to_int info.block_size) with | SOLO5_R_OK -> ( let index = Bigstringaf.get_int64_le commit SHA1.length in let commit = Bigstringaf.substring commit ~off:0 ~len:SHA1.length in let commit = SHA1.of_raw_string commit in let ( >>? ) = Lwt_result.bind in match analyze with | true -> unpack (handle, info) ~read ~block_size:info.block_size ~get_block commit >>? fun (buffers, pack, directories, files) -> Lwt.return_ok { name; handle; capacity = info.capacity; block_size = info.block_size; pack; buffers; directories; files; } | false -> iter (handle, info) ~block_size:info.block_size ~capacity:info.capacity ~get_block commit index >>? fun (buffers, pack, directories, files) -> Lwt.return_ok { name; handle; capacity = info.capacity; block_size = info.block_size; pack; buffers; directories; files; }) | SOLO5_R_AGAIN -> assert false | SOLO5_R_EINVAL -> invalid_arg "Block: connect(%s): Invalid argument" name | SOLO5_R_EUNSPEC -> unspecified "Block: connect(%s): Unspecified error" name) module Commit = Git.Commit.Make (Git.Hash.Make (SHA1)) module Tree = Git.Tree.Make (Git.Hash.Make (SHA1)) let load ~block_size ~get_block pack uid = let open Rresult in let map = map ~block_size ~get_block in let weight = Carton.Dec.weight_of_uid ~map pack ~weight:Carton.Dec.null uid in let raw = Carton.Dec.make_raw ~weight in let v = Carton.Dec.of_uid ~map pack raw uid in match Carton.Dec.kind v with | `A -> let parser = Encore.to_angstrom Commit.format in Angstrom.parse_bigstring ~consume:All parser (Bigstringaf.sub (Carton.Dec.raw v) ~off:0 ~len:(Carton.Dec.len v)) |> R.reword_error (fun _ -> R.msgf "Invalid commit (%a)" SHA1.pp uid) >>| fun v -> `Commit v | `B -> let parser = Encore.to_angstrom Tree.format in Angstrom.parse_bigstring ~consume:All parser (Bigstringaf.sub (Carton.Dec.raw v) ~off:0 ~len:(Carton.Dec.len v)) |> R.reword_error (fun _ -> R.msgf "Invalid tree (%a)" SHA1.pp uid) >>| fun v -> `Tree v | `C -> R.ok (`Blob (Bigstringaf.sub (Carton.Dec.raw v) ~off:0 ~len:(Carton.Dec.len v))) | `D -> R.ok `Tag let with_ressources ~block_size ~get_block pack uid buffers = Lwt.catch (fun () -> let pack = Carton.Dec.with_z buffers.z pack in let pack = Carton.Dec.with_allocate ~allocate:buffers.allocate pack in let pack = Carton.Dec.with_w buffers.w pack in load ~block_size ~get_block pack uid |> Lwt.return) @@ fun exn -> raise exn let exists t key = match ( Art.find_opt t.directories (Art.key (Mirage_kv.Key.to_string key)), Art.find_opt t.files (Art.key (Mirage_kv.Key.to_string key)) ) with | None, None -> Lwt.return_ok None | Some _, None -> Lwt.return_ok (Some `Dictionary) | None, Some _ -> Lwt.return_ok (Some `Value) | Some _, Some _ -> assert false (* XXX(dinosaure): impossible. *) let get t key = let open Rresult in let open Lwt.Infix in match Art.find_opt t.files (Art.key (Mirage_kv.Key.to_string key)) with | None -> Lwt.return_error (`Not_found key) | Some hash -> ( Lwt_pool.use t.buffers (with_ressources ~block_size:t.block_size ~get_block t.pack hash) >>= function | Ok (`Blob v) -> Lwt.return_ok (Bigstringaf.to_string v) | Ok _ -> Lwt.return_error (`Value_expected key) | Error _ as err -> Lwt.return err) let list t key = match Art.find_opt t.directories (Art.key (Mirage_kv.Key.to_string key)) with | None -> Lwt.return_error (`Not_found key) | Some hash -> ( let open Lwt.Infix in Lwt_pool.use t.buffers (with_ressources ~block_size:t.block_size ~get_block t.pack hash) >>= function | Ok (`Tree v) -> let f acc { Git.Tree.name; perm; _ } = match perm with | `Everybody | `Normal -> (name, `Value) :: acc | `Dir -> (name, `Dictionary) :: acc | _ -> acc in let lst = List.fold_left f [] (Git.Tree.to_list v) in Lwt.return_ok lst | Ok _ -> Lwt.return_error (`Dictionary_expected key) | Error _ as err -> Lwt.return err) let digest t key = match ( Art.find_opt t.files (Art.key (Mirage_kv.Key.to_string key)), Art.find_opt t.directories (Art.key (Mirage_kv.Key.to_string key)) ) with | Some v, None -> Lwt.return_ok (SHA1.to_raw_string v) | None, Some v -> Lwt.return_ok (SHA1.to_raw_string v) | None, None -> Lwt.return_error (`Not_found key) | Some _, Some _ -> assert false let last_modified _t _key = Lwt.return_ok (0, 0L)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>