2026-01-22 11:10.34: New job: test mirage/irmin https://github.com/mirage/irmin.git#refs/pull/2390/head (78d22af7160997461b5939c5618f00e82d613351) (linux-x86_64:(lint-fmt)) Base: ocaml/opam:debian-13-ocaml-4.08@sha256:7cdc2a1943ac1462f548be7816c6d02f14e605659f225027208abe04795ea500 ocamlformat version: version 0.27.0 (from opam) To reproduce locally: git clone --recursive "https://github.com/mirage/irmin.git" && cd "irmin" && git fetch origin "refs/pull/2390/head" && git reset --hard 78d22af7 cat > Dockerfile <<'END-OF-DOCKERFILE' FROM ocaml/opam:debian-13-ocaml-4.08@sha256:7cdc2a1943ac1462f548be7816c6d02f14e605659f225027208abe04795ea500 USER 1000:1000 RUN cd ~/opam-repository && (git cat-file -e 873cb18c37b308713d11ad3894c4bb78d73fb3e7 || git fetch origin master) && git reset -q --hard 873cb18c37b308713d11ad3894c4bb78d73fb3e7 && git log --no-decorate -n1 --oneline && opam update -u RUN opam depext -i dune WORKDIR /src RUN opam depext -i ocamlformat=0.27.0 COPY --chown=1000:1000 . /src/ RUN opam exec -- dune build @fmt --ignore-promoted-rules || (echo "dune build @fmt failed"; exit 2) END-OF-DOCKERFILE docker build . END-REPRO-BLOCK 2026-01-22 11:10.34: Using cache hint "mirage/irmin-ocaml/opam:debian-13-ocaml-4.08@sha256:7cdc2a1943ac1462f548be7816c6d02f14e605659f225027208abe04795ea500-debian-13-4.08_opam-2.5-ocamlformat-873cb18c37b308713d11ad3894c4bb78d73fb3e7" 2026-01-22 11:10.34: Using OBuilder spec: ((from ocaml/opam:debian-13-ocaml-4.08@sha256:7cdc2a1943ac1462f548be7816c6d02f14e605659f225027208abe04795ea500) (user (uid 1000) (gid 1000)) (run (cache (opam-archives (target /home/opam/.opam/download-cache))) (network host) (shell "cd ~/opam-repository && (git cat-file -e 873cb18c37b308713d11ad3894c4bb78d73fb3e7 || git fetch origin master) && git reset -q --hard 873cb18c37b308713d11ad3894c4bb78d73fb3e7 && git log --no-decorate -n1 --oneline && opam update -u")) (run (cache (opam-archives (target /home/opam/.opam/download-cache))) (network host) (shell "opam depext -i dune")) (workdir /src) (run (cache (opam-archives (target /home/opam/.opam/download-cache))) (network host) (shell "opam depext -i ocamlformat=0.27.0")) (copy (src .) (dst /src/)) (run (shell "opam exec -- dune build @fmt --ignore-promoted-rules || (echo \"dune build @fmt failed\"; exit 2)")) ) 2026-01-22 11:10.34: Waiting for resource in pool OCluster 2026-01-22 11:10.34: Waiting for worker… 2026-01-22 11:38.39: Got resource from pool OCluster Building on asteria.caelum.ci.dev All commits already cached HEAD is now at 78d22af716 Change default inlining threshold from 16 to 48 bytes (from ocaml/opam:debian-13-ocaml-4.08@sha256:7cdc2a1943ac1462f548be7816c6d02f14e605659f225027208abe04795ea500) 2026-01-22 11:39.29 ---> saved as "4c1f60dc0cc5644c6a4c05cf3315bdbf9cc478b70e443b212a1220385bab8bba" /: (user (uid 1000) (gid 1000)) /: (run (cache (opam-archives (target /home/opam/.opam/download-cache))) (network host) (shell "cd ~/opam-repository && (git cat-file -e 873cb18c37b308713d11ad3894c4bb78d73fb3e7 || git fetch origin master) && git reset -q --hard 873cb18c37b308713d11ad3894c4bb78d73fb3e7 && git log --no-decorate -n1 --oneline && opam update -u")) From https://github.com/ocaml/opam-repository * branch master -> FETCH_HEAD a6b2f19780..5bcf75c1ac master -> origin/master 873cb18c37 Merge pull request #29216 from shonfeder/release-dune-3.21.0 <><> Updating package repositories ><><><><><><><><><><><><><><><><><><><><><><> [default] Initialised default (at git+file:///home/opam/opam-repository): [INFO] opam 2.1 and 2.2 include many performance and security improvements over 2.0; please consider upgrading (https://opam.ocaml.org/doc/Install.html) Everything as up-to-date as possible (run with --verbose to show unavailable upgrades). However, you may "opam upgrade" these packages explicitly, which will ask permission to downgrade or uninstall the conflicting packages. Nothing to do. # Run eval $(opam env) to update the current shell environment 2026-01-22 11:40.33 ---> saved as "72a7cd495abee3d0659c15140c96fff42d035222fc9b794ad453f1a5292cd6f1" /: (run (cache (opam-archives (target /home/opam/.opam/download-cache))) (network host) (shell "opam depext -i dune")) # Detecting depexts using vars: arch=x86_64, os=linux, os-distribution=debian, os-family=debian # No extra OS packages requirements found. # All required OS packages found. # Now letting opam install the packages The following actions will be performed: - install dune 3.21.0 <><> Gathering sources ><><><><><><><><><><><><><><><><><><><><><><><><><><><><> [dune.3.21.0] found in cache <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed dune.3.21.0 Done. # Run eval $(opam env) to update the current shell environment 2026-01-22 11:41.03 ---> saved as "3b5aee51bb4636e6dab95deb6944478b896d0b06f021712424b773f7d70073ac" /: (workdir /src) /src: (run (cache (opam-archives (target /home/opam/.opam/download-cache))) (network host) (shell "opam depext -i ocamlformat=0.27.0")) # Detecting depexts using vars: arch=x86_64, os=linux, os-distribution=debian, os-family=debian # No extra OS packages requirements found. # All required OS packages found. # Now letting opam install the packages The following actions will be performed: - install sexplib0 v0.14.0 [required by base] - install ocamlbuild 0.16.1 [required by fpath, astring, uuseg] - install cmdliner 1.3.0 [required by ocamlformat] - install either 1.0.0 [required by ocamlformat-lib] - install menhirLib 20250912 [required by ocamlformat-lib] - install csexp 1.5.2 [required by ocamlformat] - install dune-build-info 3.21.0 [required by ocamlformat-lib] - install camlp-streams 5.0.1 [required by ocamlformat-lib] - install seq base [required by re] - install menhirSdk 20250912 [required by ocamlformat-lib] - install fix 20250919 [required by ocamlformat-lib] - install menhirCST 20250912 [required by menhir] - install ocamlfind 1.9.8 [required by ocp-indent, astring, fpath, uuseg] - install ocaml-version 4.0.3 [required by ocamlformat-lib] - install dune-configurator 3.21.0 [required by base] - install re 1.11.0 [required by ocamlformat] - install menhir 20250912 [required by ocamlformat-lib] - install topkg 1.1.1 [required by fpath, astring, uuseg] - install ocp-indent 1.9.0 [required by ocamlformat-lib] - install base v0.14.3 [required by ocamlformat-lib] - install uutf 1.0.4 [required by ocamlformat-lib] - install astring 0.8.5 [required by ocamlformat-lib] - install stdio v0.14.0 [required by ocamlformat-lib] - install uucp 15.0.0 [required by uuseg] - install fpath 0.7.3 [required by ocamlformat-lib] - install uuseg 15.0.0 [required by ocamlformat-lib] - install ocamlformat-lib 0.27.0 [required by ocamlformat] - install ocamlformat 0.27.0 ===== 28 to install ===== <><> Gathering sources ><><><><><><><><><><><><><><><><><><><><><><><><><><><><> [astring.0.8.5] found in cache [base.v0.14.3] found in cache [camlp-streams.5.0.1] found in cache [cmdliner.1.3.0] found in cache [csexp.1.5.2] found in cache [dune-build-info.3.21.0] found in cache [dune-configurator.3.21.0] found in cache [either.1.0.0] found in cache [fix.20250919] found in cache [fpath.0.7.3] found in cache [menhir.20250912] found in cache [menhirCST.20250912] found in cache [menhirLib.20250912] found in cache [menhirSdk.20250912] found in cache [ocaml-version.4.0.3] found in cache [ocamlbuild.0.16.1] found in cache [ocamlfind.1.9.8] found in cache [ocamlformat.0.27.0] found in cache [ocamlformat-lib.0.27.0] found in cache [ocp-indent.1.9.0] found in cache [re.1.11.0] found in cache [sexplib0.v0.14.0] found in cache [stdio.v0.14.0] found in cache [topkg.1.1.1] found in cache [uucp.15.0.0] found in cache [uuseg.15.0.0] found in cache [uutf.1.0.4] found in cache <><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><> -> installed seq.base -> installed camlp-streams.5.0.1 -> installed cmdliner.1.3.0 -> installed csexp.1.5.2 -> installed either.1.0.0 -> installed fix.20250919 -> installed menhirCST.20250912 -> installed menhirLib.20250912 -> installed menhirSdk.20250912 -> installed ocaml-version.4.0.3 -> installed sexplib0.v0.14.0 -> installed re.1.11.0 -> installed dune-build-info.3.21.0 -> installed ocamlfind.1.9.8 -> installed dune-configurator.3.21.0 -> installed ocamlbuild.0.16.1 -> installed ocp-indent.1.9.0 -> installed topkg.1.1.1 -> installed base.v0.14.3 -> installed astring.0.8.5 -> installed uutf.1.0.4 -> installed stdio.v0.14.0 -> installed menhir.20250912 -> installed fpath.0.7.3 -> installed uucp.15.0.0 -> installed uuseg.15.0.0 -> installed ocamlformat-lib.0.27.0 -> installed ocamlformat.0.27.0 Done. <><> ocp-indent.1.9.0 installed successfully ><><><><><><><><><><><><><><><><><> => This package requires additional configuration for use in editors. Install package 'user-setup', or manually: * for Emacs, add these lines to ~/.emacs: (add-to-list 'load-path "/home/opam/.opam/4.08/share/emacs/site-lisp") (require 'ocp-indent) * for Vim, add this line to ~/.vimrc: set rtp^="/home/opam/.opam/4.08/share/ocp-indent/vim" # Run eval $(opam env) to update the current shell environment 2026-01-22 11:42.00 ---> saved as "2ae43ae662b95641fa2bf73d980051b9145f20314d85ad107c6a3257b77df4e6" /src: (copy (src .) (dst /src/)) 2026-01-22 11:42.01 ---> saved as "729f9cd8142050805d31ee1771bc359f35ddfd207f4b600617a4c012d50468e0" /src: (run (shell "opam exec -- dune build @fmt --ignore-promoted-rules || (echo \"dune build @fmt failed\"; exit 2)")) Warning: Invalid documentation comment: File "src/irmin-pack/layout.ml", line 97, characters 27-50: '{v ... v}' (verbatim text) should begin on its own line. Warning: Invalid documentation comment: File "src/irmin-pack/layout.ml", line 97, characters 50-51: Paragraph should begin on its own line. Warning: Invalid documentation comment: File "test/irmin-graphql/common.mli", line 88, character 16 to line 92, character 6: '{[...]}' (code block) should begin on its own line. Warning: Invalid documentation comment: File "test/irmin-graphql/common.mli", line 98, character 16 to line 102, character 6: '{[...]}' (code block) should begin on its own line. Warning: Invalid documentation comment: File "test/irmin-graphql/common.mli", line 104, character 24 to line 108, character 6: '{[...]}' (code block) should begin on its own line. Warning: Invalid documentation comment: File "test/irmin-graphql/common.mli", line 114, character 16 to line 118, character 6: '{[...]}' (code block) should begin on its own line. File "src/irmin/irmin.ml", line 1, characters 0-0: diff --git a/_build/default/src/irmin/irmin.ml b/_build/default/src/irmin/.formatted/irmin.ml index 6750ee5..ce15365 100644 --- a/_build/default/src/irmin/irmin.ml +++ b/_build/default/src/irmin/.formatted/irmin.ml @@ -181,8 +181,8 @@ struct end module Of_backend = Store.Make - module Tree = Tree + module type Tree = Tree.S module type S = Store.S File "src/irmin/tree_intf.ml", line 1, characters 0-0: diff --git a/_build/default/src/irmin/tree_intf.ml b/_build/default/src/irmin/.formatted/tree_intf.ml index 6c2b48f..80cec03 100644 --- a/_build/default/src/irmin/tree_intf.ml +++ b/_build/default/src/irmin/.formatted/tree_intf.ml @@ -413,7 +413,8 @@ module type S = sig val reset_counters : unit -> unit val inspect : - t -> [ `Contents | `Node of [ `Map | `Key | `Value | `Portable_dirty | `Pruned ] ] + t -> + [ `Contents | `Node of [ `Map | `Key | `Value | `Portable_dirty | `Pruned ] ] (** [inspect t] is similar to {!kind}, with additional state information for nodes. It is primarily useful for debugging and testing. @@ -432,8 +433,8 @@ module type Sigs = sig val set_inline_contents_enabled : bool -> unit (** [set_inline_contents_enabled b] controls whether small contents are inlined directly in nodes. When [true], contents smaller than the - configured threshold will be inlined. Default is [false]. This is a - global setting that should be set before creating stores. *) + configured threshold will be inlined. Default is [false]. This is a global + setting that should be set before creating stores. *) val set_inline_contents_max_bytes : int -> unit (** [set_inline_contents_max_bytes n] sets the maximum serialized size in File "src/irmin-pack/conf.mli", line 1, characters 0-0: diff --git a/_build/default/src/irmin-pack/conf.mli b/_build/default/src/irmin-pack/.formatted/conf.mli index 6d3ffc0..7ead362 100644 --- a/_build/default/src/irmin-pack/conf.mli +++ b/_build/default/src/irmin-pack/.formatted/conf.mli @@ -135,14 +135,16 @@ val inline_contents : Irmin.Backend.Conf.t -> bool When enabled, content values smaller than 16 bytes (serialized) are stored directly within the parent node entry rather than as separate pack entries. - This reduces storage overhead and improves read performance for small values. + This reduces storage overhead and improves read performance for small + values. Note: Enabling this option changes the hash computation of nodes, making stores incompatible with stores created with inlining disabled for hash-based comparisons. - See the {{:./doc/irmin-pack/design/inline_contents.md}inline contents design - doc} for more details. *) + See the + {{:./doc/irmin-pack/design/inline_contents.md}inline contents design doc} + for more details. *) val switch : Irmin.Backend.Conf.t -> Eio.Switch.t (** Eio switch *) File "src/irmin/irmin.mli", line 1, characters 0-0: diff --git a/_build/default/src/irmin/irmin.mli b/_build/default/src/irmin/.formatted/irmin.mli index 2f57bf9..6259c34 100644 --- a/_build/default/src/irmin/irmin.mli +++ b/_build/default/src/irmin/.formatted/irmin.mli @@ -82,8 +82,8 @@ module Tree : sig val set_inline_contents_enabled : bool -> unit (** [set_inline_contents_enabled b] controls whether small contents are inlined directly in nodes. When [true], contents smaller than the - configured threshold will be inlined. Default is [false]. This is a - global setting that should be set before creating stores. *) + configured threshold will be inlined. Default is [false]. This is a global + setting that should be set before creating stores. *) val set_inline_contents_max_bytes : int -> unit (** [set_inline_contents_max_bytes n] sets the maximum serialized size in @@ -93,13 +93,14 @@ module Tree : sig val get_inline_contents_max_bytes : unit -> int (** [get_inline_contents_max_bytes ()] returns the current threshold. *) - module Make (B : Backend.S) : Tree_intf.S - with type path = B.Node.Path.t - and type step = B.Node.Path.step - and type metadata = B.Node.Metadata.t - and type contents = B.Contents.value - and type contents_key = B.Contents.Key.t - and type hash = B.Hash.t + module Make (B : Backend.S) : + Tree_intf.S + with type path = B.Node.Path.t + and type step = B.Node.Path.step + and type metadata = B.Node.Metadata.t + and type contents = B.Contents.value + and type contents_key = B.Contents.Key.t + and type hash = B.Hash.t end module Metadata = Metadata File "src/irmin-pack/inode_intf.ml", line 1, characters 0-0: diff --git a/_build/default/src/irmin-pack/inode_intf.ml b/_build/default/src/irmin-pack/.formatted/inode_intf.ml index 8d54e52..f2d4d6f 100644 --- a/_build/default/src/irmin-pack/inode_intf.ml +++ b/_build/default/src/irmin-pack/.formatted/inode_intf.ml @@ -118,10 +118,12 @@ module type Compress = sig type address = Offset of pack_offset | Hash of hash type ptr = { index : dict_key; hash : address } type tree = { depth : dict_key; length : dict_key; entries : ptr list } + type value = | Contents of name * address * metadata | Contents_inlined_value of name * string * metadata | Node of name * address + type v = Values of value list | Tree of tree type v1 = { mutable length : int; v : v } File "src/irmin/node.ml", line 1, characters 0-0: diff --git a/_build/default/src/irmin/node.ml b/_build/default/src/irmin/.formatted/node.ml index d2cb36e..bcd103d 100644 --- a/_build/default/src/irmin/node.ml +++ b/_build/default/src/irmin/.formatted/node.ml @@ -182,7 +182,8 @@ struct | Node n -> (n.name, `Node (n.node, n.inlined)) | Contents c -> (c.name, `Contents (c.contents, Metadata.default)) | Contents_m c -> (c.name, `Contents (c.contents, c.metadata)) - | Contents_inlined_value c -> (c.name, `Contents_inlined (c.value, c.metadata)) + | Contents_inlined_value c -> + (c.name, `Contents_inlined (c.value, c.metadata)) | Node_hash _ | Contents_hash _ | Contents_m_hash _ | Contents_inlined_hash _ -> (* Not reachable after [Portable.of_node]. See invariant on {!entry}. *) @@ -214,7 +215,8 @@ struct (c.name, `Contents (Contents_key.to_hash c.contents, c.metadata)) | Contents_hash c -> (c.name, `Contents (c.contents, Metadata.default)) | Contents_m_hash c -> (c.name, `Contents (c.contents, c.metadata)) - | Contents_inlined_value c -> (c.name, `Contents_inlined (c.value, c.metadata)) + | Contents_inlined_value c -> + (c.name, `Contents_inlined (c.value, c.metadata)) | Contents_inlined _c -> assert false | Contents_inlined_hash _c -> assert false File "test/irmin-pack/gen_always.ml", line 1, characters 0-0: diff --git a/_build/default/test/irmin-pack/gen_always.ml b/_build/default/test/irmin-pack/.formatted/gen_always.ml index d315877..58696da 100644 --- a/_build/default/test/irmin-pack/gen_always.ml +++ b/_build/default/test/irmin-pack/.formatted/gen_always.ml @@ -43,7 +43,7 @@ let info = Store.Info.empty let generate ~sw ~fs = let path = "version_3_always_new" in rm_dir path; - let rw = Store.Repo.v (config ~sw ~fs (Eio.Path.(fs / path))) in + let rw = Store.Repo.v (config ~sw ~fs Eio.Path.(fs / path)) in (* Create tree matching the original structure: borphan | b01 <- n01 <- n0 <- c0 @@ -61,11 +61,17 @@ let generate ~sw ~fs = let k_b01 = Store.Backend.Contents.add bstore "b01" in (* Create n01 node with step-b01 -> b01 *) - let n01 = Store.Backend.Node.Val.of_list [ ("step-b01", `Contents (k_b01, ())) ] [] in + let n01 = + Store.Backend.Node.Val.of_list + [ ("step-b01", `Contents (k_b01, ())) ] + [] + in let k_n01 = Store.Backend.Node.add nstore n01 in (* Create n0 (root) node with step-n01 -> n01 *) - let n0 = Store.Backend.Node.Val.of_list [ ("step-n01", `Node (k_n01, [])) ] [] in + let n0 = + Store.Backend.Node.Val.of_list [ ("step-n01", `Node (k_n01, [])) ] [] + in let k_n0 = Store.Backend.Node.add nstore n0 in (* Create commit *) @@ -81,7 +87,8 @@ let generate ~sw ~fs = let hex = String.to_seq hash_bytes |> Seq.map (fun c -> Printf.sprintf "%02x" (Char.code c)) - |> List.of_seq |> String.concat "" + |> List.of_seq + |> String.concat "" in Printf.printf "Commit hash (hex): %s\n" hex); File "test/irmin-pack/gen_gced.ml", line 1, characters 0-0: diff --git a/_build/default/test/irmin-pack/gen_gced.ml b/_build/default/test/irmin-pack/.formatted/gen_gced.ml index a0f6aea..9162f26 100644 --- a/_build/default/test/irmin-pack/gen_gced.ml +++ b/_build/default/test/irmin-pack/.formatted/gen_gced.ml @@ -42,7 +42,7 @@ let info = Store.Info.empty let generate ~domain_mgr ~sw ~fs = let path = "version_3_minimal_gced_new" in rm_dir path; - let rw = Store.Repo.v (config ~sw ~fs (Eio.Path.(fs / path))) in + let rw = Store.Repo.v (config ~sw ~fs Eio.Path.(fs / path)) in (* Create tree matching the original structure: borphan | b01 <- n01 <- n0 <- c0 @@ -50,39 +50,49 @@ let generate ~domain_mgr ~sw ~fs = borphan is orphan content that is added to the content store but NOT part of the tree. The tree only has step-n01/step-b01 -> "b01" *) - - let k_c0 = Store.Backend.Repo.batch rw (fun bstore nstore cstore -> - (* First, add the orphan content directly to the content store *) - let _ = Store.Backend.Contents.add bstore "borphan" in - - (* Add b01 content *) - let k_b01 = Store.Backend.Contents.add bstore "b01" in - - (* Create n01 node with step-b01 -> b01 *) - let n01 = Store.Backend.Node.Val.of_list [ ("step-b01", `Contents (k_b01, ())) ] [] in - let k_n01 = Store.Backend.Node.add nstore n01 in - - (* Create n0 (root) node with step-n01 -> n01 *) - let n0 = Store.Backend.Node.Val.of_list [ ("step-n01", `Node (k_n01, [])) ] [] in - let k_n0 = Store.Backend.Node.add nstore n0 in - - (* Create commit *) - let c0 = Store.Backend.Commit.Val.v ~parents:[] ~info ~node:k_n0 in - let k_c0 = Store.Backend.Commit.add cstore c0 in - - Printf.printf "Commit key type: %s\n" - (Irmin.Type.to_string Store.Backend.Commit.Key.t k_c0); - let hash = Store.Backend.Commit.Key.to_hash k_c0 in - Printf.printf "Commit hash (type): %s\n" - (Irmin.Type.to_string Store.Hash.t hash); - let hash_bytes = Irmin.Type.(unstage (to_bin_string Store.Hash.t)) hash in - let hex = - String.to_seq hash_bytes - |> Seq.map (fun c -> Printf.sprintf "%02x" (Char.code c)) - |> List.of_seq |> String.concat "" - in - Printf.printf "Commit hash (hex): %s\n" hex; - k_c0) in + let k_c0 = + Store.Backend.Repo.batch rw (fun bstore nstore cstore -> + (* First, add the orphan content directly to the content store *) + let _ = Store.Backend.Contents.add bstore "borphan" in + + (* Add b01 content *) + let k_b01 = Store.Backend.Contents.add bstore "b01" in + + (* Create n01 node with step-b01 -> b01 *) + let n01 = + Store.Backend.Node.Val.of_list + [ ("step-b01", `Contents (k_b01, ())) ] + [] + in + let k_n01 = Store.Backend.Node.add nstore n01 in + + (* Create n0 (root) node with step-n01 -> n01 *) + let n0 = + Store.Backend.Node.Val.of_list [ ("step-n01", `Node (k_n01, [])) ] [] + in + let k_n0 = Store.Backend.Node.add nstore n0 in + + (* Create commit *) + let c0 = Store.Backend.Commit.Val.v ~parents:[] ~info ~node:k_n0 in + let k_c0 = Store.Backend.Commit.add cstore c0 in + + Printf.printf "Commit key type: %s\n" + (Irmin.Type.to_string Store.Backend.Commit.Key.t k_c0); + let hash = Store.Backend.Commit.Key.to_hash k_c0 in + Printf.printf "Commit hash (type): %s\n" + (Irmin.Type.to_string Store.Hash.t hash); + let hash_bytes = + Irmin.Type.(unstage (to_bin_string Store.Hash.t)) hash + in + let hex = + String.to_seq hash_bytes + |> Seq.map (fun c -> Printf.sprintf "%02x" (Char.code c)) + |> List.of_seq + |> String.concat "" + in + Printf.printf "Commit hash (hex): %s\n" hex; + k_c0) + in (* Run GC with c0 as target to remove borphan *) Printf.printf "Running GC with c0 as target...\n"; File "test/irmin-pack/gen_minimal.ml", line 1, characters 0-0: diff --git a/_build/default/test/irmin-pack/gen_minimal.ml b/_build/default/test/irmin-pack/.formatted/gen_minimal.ml index e9de76b..0da9c6b 100644 --- a/_build/default/test/irmin-pack/gen_minimal.ml +++ b/_build/default/test/irmin-pack/.formatted/gen_minimal.ml @@ -43,7 +43,7 @@ let info = Store.Info.empty let generate ~sw ~fs = let path = "version_3_minimal_new" in rm_dir path; - let rw = Store.Repo.v (config ~sw ~fs (Eio.Path.(fs / path))) in + let rw = Store.Repo.v (config ~sw ~fs Eio.Path.(fs / path)) in (* Create tree matching the original structure: borphan | b01 <- n01 <- n0 <- c0 @@ -61,11 +61,17 @@ let generate ~sw ~fs = let k_b01 = Store.Backend.Contents.add bstore "b01" in (* Create n01 node with step-b01 -> b01 *) - let n01 = Store.Backend.Node.Val.of_list [ ("step-b01", `Contents (k_b01, ())) ] [] in + let n01 = + Store.Backend.Node.Val.of_list + [ ("step-b01", `Contents (k_b01, ())) ] + [] + in let k_n01 = Store.Backend.Node.add nstore n01 in (* Create n0 (root) node with step-n01 -> n01 *) - let n0 = Store.Backend.Node.Val.of_list [ ("step-n01", `Node (k_n01, [])) ] [] in + let n0 = + Store.Backend.Node.Val.of_list [ ("step-n01", `Node (k_n01, [])) ] [] + in let k_n0 = Store.Backend.Node.add nstore n0 in (* Create commit *) @@ -81,7 +87,8 @@ let generate ~sw ~fs = let hex = String.to_seq hash_bytes |> Seq.map (fun c -> Printf.sprintf "%02x" (Char.code c)) - |> List.of_seq |> String.concat "" + |> List.of_seq + |> String.concat "" in Printf.printf "Commit hash (hex): %s\n" hex); File "test/irmin-pack/test_inline_contents.ml", line 1, characters 0-0: diff --git a/_build/default/test/irmin-pack/test_inline_contents.ml b/_build/default/test/irmin-pack/.formatted/test_inline_contents.ml index 8a450de..e8ae0f6 100644 --- a/_build/default/test/irmin-pack/test_inline_contents.ml +++ b/_build/default/test/irmin-pack/.formatted/test_inline_contents.ml @@ -42,18 +42,22 @@ let config ~sw ~fs ?(readonly = false) ?(fresh = true) ~inline_contents root = let info = S.Info.empty -(** Test that data can be stored and retrieved correctly with inlining disabled *) +(** Test that data can be stored and retrieved correctly with inlining disabled +*) let test_without_inlining ~fs () = let root = root_no_inline ~fs in rm_dir root; Eio.Switch.run @@ fun sw -> let repo = - S.Repo.v (config ~sw ~fs ~readonly:false ~fresh:true ~inline_contents:false root) + S.Repo.v + (config ~sw ~fs ~readonly:false ~fresh:true ~inline_contents:false root) in (* Create a tree with small and large contents *) let tree = S.Tree.empty () in - let tree = S.Tree.add tree [ "small" ] "abc" in (* Small content, < 16 bytes *) - let tree = S.Tree.add tree [ "large" ] (String.make 100 'x') in (* Large content *) + let tree = S.Tree.add tree [ "small" ] "abc" in + (* Small content, < 16 bytes *) + let tree = S.Tree.add tree [ "large" ] (String.make 100 'x') in + (* Large content *) (* Create a commit *) let commit = S.Commit.v repo ~parents:[] ~info tree in let hash = S.Commit.hash commit in @@ -63,21 +67,28 @@ let test_without_inlining ~fs () = let small = S.Tree.find tree' [ "small" ] in let large = S.Tree.find tree' [ "large" ] in Alcotest.(check (option string)) "small content" (Some "abc") small; - Alcotest.(check (option string)) "large content" (Some (String.make 100 'x')) large; + Alcotest.(check (option string)) + "large content" + (Some (String.make 100 'x')) + large; S.Repo.close repo -(** Test that data can be stored and retrieved correctly with inlining enabled *) +(** Test that data can be stored and retrieved correctly with inlining enabled +*) let test_with_inlining ~fs () = let root = root_with_inline ~fs in rm_dir root; Eio.Switch.run @@ fun sw -> let repo = - S.Repo.v (config ~sw ~fs ~readonly:false ~fresh:true ~inline_contents:true root) + S.Repo.v + (config ~sw ~fs ~readonly:false ~fresh:true ~inline_contents:true root) in (* Create a tree with small and large contents *) let tree = S.Tree.empty () in - let tree = S.Tree.add tree [ "small" ] "abc" in (* Small content, < 16 bytes *) - let tree = S.Tree.add tree [ "large" ] (String.make 100 'x') in (* Large content *) + let tree = S.Tree.add tree [ "small" ] "abc" in + (* Small content, < 16 bytes *) + let tree = S.Tree.add tree [ "large" ] (String.make 100 'x') in + (* Large content *) (* Create a commit *) let commit = S.Commit.v repo ~parents:[] ~info tree in let hash = S.Commit.hash commit in @@ -87,10 +98,14 @@ let test_with_inlining ~fs () = let small = S.Tree.find tree' [ "small" ] in let large = S.Tree.find tree' [ "large" ] in Alcotest.(check (option string)) "small content" (Some "abc") small; - Alcotest.(check (option string)) "large content" (Some (String.make 100 'x')) large; + Alcotest.(check (option string)) + "large content" + (Some (String.make 100 'x')) + large; S.Repo.close repo -(** Test that the same data produces the same content hash regardless of inlining *) +(** Test that the same data produces the same content hash regardless of + inlining *) let test_content_equivalence ~fs () = let root_no_inline = root_equiv_no ~fs in let root_inline = root_equiv_yes ~fs in @@ -100,7 +115,8 @@ let test_content_equivalence ~fs () = (* Create store without inlining *) let repo1 = S.Repo.v - (config ~sw ~fs ~readonly:false ~fresh:true ~inline_contents:false root_no_inline) + (config ~sw ~fs ~readonly:false ~fresh:true ~inline_contents:false + root_no_inline) in let tree1 = S.Tree.empty () in let tree1 = S.Tree.add tree1 [ "a" ] "small" in @@ -111,7 +127,8 @@ let test_content_equivalence ~fs () = (* Create store with inlining *) let repo2 = S.Repo.v - (config ~sw ~fs ~readonly:false ~fresh:true ~inline_contents:true root_inline) + (config ~sw ~fs ~readonly:false ~fresh:true ~inline_contents:true + root_inline) in let tree2 = S.Tree.empty () in let tree2 = S.Tree.add tree2 [ "a" ] "small" in @@ -122,28 +139,49 @@ let test_content_equivalence ~fs () = (* Verify data is the same when read back *) let repo1 = S.Repo.v - (config ~sw ~fs ~readonly:true ~fresh:false ~inline_contents:false root_no_inline) + (config ~sw ~fs ~readonly:true ~fresh:false ~inline_contents:false + root_no_inline) in let repo2 = S.Repo.v - (config ~sw ~fs ~readonly:true ~fresh:false ~inline_contents:true root_inline) + (config ~sw ~fs ~readonly:true ~fresh:false ~inline_contents:true + root_inline) + in + let tree1' = + S.Commit.of_hash repo1 (S.Commit.hash commit1) + |> Option.get + |> S.Commit.tree + in + let tree2' = + S.Commit.of_hash repo2 (S.Commit.hash commit2) + |> Option.get + |> S.Commit.tree in - let tree1' = S.Commit.of_hash repo1 (S.Commit.hash commit1) |> Option.get |> S.Commit.tree in - let tree2' = S.Commit.of_hash repo2 (S.Commit.hash commit2) |> Option.get |> S.Commit.tree in (* Verify contents are identical *) - Alcotest.(check (option string)) "a" (S.Tree.find tree1' [ "a" ]) (S.Tree.find tree2' [ "a" ]); - Alcotest.(check (option string)) "b" (S.Tree.find tree1' [ "b" ]) (S.Tree.find tree2' [ "b" ]); - Alcotest.(check (option string)) "c/d" (S.Tree.find tree1' [ "c"; "d" ]) (S.Tree.find tree2' [ "c"; "d" ]); + Alcotest.(check (option string)) + "a" + (S.Tree.find tree1' [ "a" ]) + (S.Tree.find tree2' [ "a" ]); + Alcotest.(check (option string)) + "b" + (S.Tree.find tree1' [ "b" ]) + (S.Tree.find tree2' [ "b" ]); + Alcotest.(check (option string)) + "c/d" + (S.Tree.find tree1' [ "c"; "d" ]) + (S.Tree.find tree2' [ "c"; "d" ]); S.Repo.close repo1; S.Repo.close repo2 -(** Test that verifies small content is actually inlined in the node structure *) +(** Test that verifies small content is actually inlined in the node structure +*) let test_inlining_structure ~fs () = let root = Eio.Path.(fs / "_build" / "test-inline-structure") in rm_dir root; Eio.Switch.run @@ fun sw -> let repo = - S.Repo.v (config ~sw ~fs ~readonly:false ~fresh:true ~inline_contents:true root) + S.Repo.v + (config ~sw ~fs ~readonly:false ~fresh:true ~inline_contents:true root) in (* Create a tree with small content that should be inlined *) let tree = S.Tree.empty () in @@ -151,10 +189,18 @@ let test_inlining_structure ~fs () = - 1-byte variant tag for the Contents.t encoding - 1-byte varint length prefix for the string So raw content must be < 46 bytes (45 or less) to be inlined. *) - let tree = S.Tree.add tree [ "tiny" ] "x" in (* 1 byte raw -> 3 bytes serialized -> inlined *) - let tree = S.Tree.add tree [ "small" ] "hello" in (* 5 bytes raw -> 7 bytes serialized -> inlined *) - let tree = S.Tree.add tree [ "medium" ] "0123456789abc0123456789abc0123456789abc012345" in (* 45 bytes raw -> 47 bytes serialized -> inlined *) - let tree = S.Tree.add tree [ "large" ] "0123456789abc0123456789abc0123456789abc0123456" in (* 46 bytes raw -> 48 bytes serialized -> NOT inlined *) + let tree = S.Tree.add tree [ "tiny" ] "x" in + (* 1 byte raw -> 3 bytes serialized -> inlined *) + let tree = S.Tree.add tree [ "small" ] "hello" in + (* 5 bytes raw -> 7 bytes serialized -> inlined *) + let tree = + S.Tree.add tree [ "medium" ] "0123456789abc0123456789abc0123456789abc012345" + in + (* 45 bytes raw -> 47 bytes serialized -> inlined *) + let tree = + S.Tree.add tree [ "large" ] "0123456789abc0123456789abc0123456789abc0123456" + in + (* 46 bytes raw -> 48 bytes serialized -> NOT inlined *) (* Commit to persist the tree *) let commit = S.Commit.v repo ~parents:[] ~info tree in let _hash = S.Commit.hash commit in @@ -162,7 +208,8 @@ let test_inlining_structure ~fs () = let commit' = S.Commit.of_hash repo (S.Commit.hash commit) |> Option.get in let tree' = S.Commit.tree commit' in (* Get the root node using to_backend_node *) - let root_node = match S.Tree.destruct tree' with + let root_node = + match S.Tree.destruct tree' with | `Node (n, _inlined) -> S.to_backend_node n | `Contents _ -> Alcotest.fail "Expected a node" in @@ -171,17 +218,17 @@ let test_inlining_structure ~fs () = (* Count inlined vs non-inlined contents *) let inlined_count = ref 0 in let non_inlined_count = ref 0 in - List.iter (fun (step, value) -> - match value with - | `Contents_inlined (bytes, _) -> - [%log.debug "Inlined content at %s: %S" step bytes]; - incr inlined_count - | `Contents _ -> - [%log.debug "Non-inlined content at %s" step]; - incr non_inlined_count - | `Node _ -> - [%log.debug "Node at %s" step] - ) entries; + List.iter + (fun (step, value) -> + match value with + | `Contents_inlined (bytes, _) -> + [%log.debug "Inlined content at %s: %S" step bytes]; + incr inlined_count + | `Contents _ -> + [%log.debug "Non-inlined content at %s" step]; + incr non_inlined_count + | `Node _ -> [%log.debug "Node at %s" step]) + entries; (* Verify: 3 entries should be inlined (tiny, small, medium), 1 should not (large) *) Alcotest.(check int) "inlined count" 3 !inlined_count; Alcotest.(check int) "non-inlined count" 1 !non_inlined_count; File "src/irmin/store.ml", line 1, characters 0-0: diff --git a/_build/default/src/irmin/store.ml b/_build/default/src/irmin/.formatted/store.ml index ce5aa75..668441e 100644 --- a/_build/default/src/irmin/store.ml +++ b/_build/default/src/irmin/.formatted/store.ml @@ -939,10 +939,7 @@ module Make (B : Backend.S) = struct let mem_tree t k = tree t |> fun tree -> Tree.mem_tree tree k let find_all t k = tree t |> fun tree -> Tree.find_all tree k let find t k = tree t |> fun tree -> Tree.find tree k - - let get t k = - tree t |> fun tree -> Tree.get tree k - + let get t k = tree t |> fun tree -> Tree.get tree k let find_tree t k = tree t |> fun tree -> Tree.find_tree tree k let get_tree t k = tree t |> fun tree -> Tree.get_tree tree k File "test/irmin-pack/test_existing_stores.ml", line 1, characters 0-0: diff --git a/_build/default/test/irmin-pack/test_existing_stores.ml b/_build/default/test/irmin-pack/.formatted/test_existing_stores.ml index 00d49c3..a3519b5 100644 --- a/_build/default/test/irmin-pack/test_existing_stores.ml +++ b/_build/default/test/irmin-pack/.formatted/test_existing_stores.ml @@ -356,9 +356,9 @@ end (** Test that verifies mixed V2/V3 inode entries in a pack file. - This test opens an existing store with V2 inodes, adds new entries - (which will be V3), and verifies that both V2 and V3 entries coexist - and can be read correctly. + This test opens an existing store with V2 inodes, adds new entries (which + will be V3), and verifies that both V2 and V3 entries coexist and can be + read correctly. We use version_2_to_3_always store because it uses always indexing strategy which indexes inodes (unlike minimal strategy used by version_3_minimal). *) @@ -422,8 +422,7 @@ module Test_mixed_v2_v3 = struct (* The archived store should have V2 inodes (created before V3 introduction) *) Alcotest.(check bool) - "Initial store should have V2 inodes" - (initial_v2 > 0) true; + "Initial store should have V2 inodes" (initial_v2 > 0) true; (* Add new content - this will create V3 inodes *) let tree = S.Commit.tree commit in @@ -450,8 +449,7 @@ module Test_mixed_v2_v3 = struct "Should still have V2 inodes (old entries preserved)" (final_v2 >= initial_v2) true; Alcotest.(check bool) - "Should have new V3 inodes (from new writes)" - (final_v3 > initial_v3) true; + "Should have new V3 inodes (from new writes)" (final_v3 > initial_v3) true; (* Verify we can still read the original commit via its hash *) let repo = S.Repo.v conf in @@ -464,7 +462,7 @@ module Test_mixed_v2_v3 = struct [%log.app "Mixed V2/V3 test passed: V2=%d V3=%d inodes coexist and are readable" - final_v2 final_v3] + final_v2 final_v3] end let tests ~fs ~domain_mgr = File "test/irmin-pack/bench_inline/distribution.ml", line 1, characters 0-0: diff --git a/_build/default/test/irmin-pack/bench_inline/distribution.ml b/_build/default/test/irmin-pack/bench_inline/.formatted/distribution.ml index 7d7630f..09ff2d0 100644 --- a/_build/default/test/irmin-pack/bench_inline/distribution.ml +++ b/_build/default/test/irmin-pack/bench_inline/.formatted/distribution.ml @@ -5,7 +5,7 @@ type t = | Bimodal of { small : int; large : int; small_ratio : float } | Log_normal of { mu : float; sigma : float; min : int; max : int } | Zipfian of { min : int; max : int; exponent : float; cdf : float array } - | Fixed of int list (* Cycle through fixed sizes *) + | Fixed of int list (* Cycle through fixed sizes *) let uniform ~min ~max = Uniform { min; max } let bimodal ~small ~large ~small_ratio = Bimodal { small; large; small_ratio } @@ -16,14 +16,14 @@ let fixed sizes = Fixed sizes let zipfian ~min ~max ~exponent = let n = max - min + 1 in (* Precompute CDF for efficient sampling *) - let weights = Array.init n (fun i -> - 1.0 /. (float_of_int (i + 1) ** exponent) - ) in + let weights = + Array.init n (fun i -> 1.0 /. (float_of_int (i + 1) ** exponent)) + in let total = Array.fold_left ( +. ) 0.0 weights in let cdf = Array.make n 0.0 in let acc = ref 0.0 in for i = 0 to n - 1 do - acc := !acc +. weights.(i) /. total; + acc := !acc +. (weights.(i) /. total); cdf.(i) <- !acc done; Zipfian { min; max; exponent; cdf } @@ -41,8 +41,7 @@ let binary_search_cdf cdf u = if lo >= hi then lo else let mid = (lo + hi) / 2 in - if cdf.(mid) < u then go (mid + 1) hi - else go lo mid + if cdf.(mid) < u then go (mid + 1) hi else go lo mid in go 0 (Array.length cdf - 1) @@ -53,7 +52,7 @@ let sample_one = function if Random.float 1.0 < small_ratio then small else large | Log_normal { mu; sigma; min; max } -> let z = random_normal () in - let x = exp (mu +. sigma *. z) in + let x = exp (mu +. (sigma *. z)) in let size = int_of_float x in Int.max min (Int.min max size) | Zipfian { min; cdf; _ } -> @@ -64,8 +63,7 @@ let sample_one = function let n = List.length sizes in List.nth sizes (Random.int n) -let sample ~n dist = - Array.init n (fun _ -> sample_one dist) +let sample ~n dist = Array.init n (fun _ -> sample_one dist) (* Statistics *) let mean arr = @@ -83,8 +81,7 @@ let describe arr = Array.sort Int.compare sorted; let n = Array.length sorted in {||} - ^ Printf.sprintf "n=%d, min=%d, p50=%d, p90=%d, p99=%d, max=%d, mean=%.1f" - n + ^ Printf.sprintf "n=%d, min=%d, p50=%d, p90=%d, p99=%d, max=%d, mean=%.1f" n sorted.(0) sorted.(n / 2) sorted.(n * 9 / 10) File "test/irmin-pack/bench_inline/main.ml", line 1, characters 0-0: diff --git a/_build/default/test/irmin-pack/bench_inline/main.ml b/_build/default/test/irmin-pack/bench_inline/.formatted/main.ml index 7961315..dbba6dd 100644 --- a/_build/default/test/irmin-pack/bench_inline/main.ml +++ b/_build/default/test/irmin-pack/bench_inline/.formatted/main.ml @@ -3,24 +3,26 @@ let () = Random.init 42 (* All available distributions *) -let distributions_list = [ - ("uniform-small", Distribution.all_small); - ("uniform-large", Distribution.all_large); - ("around-threshold", Distribution.around_threshold); - ("mostly-small", Distribution.mostly_small); - ("mostly-large", Distribution.mostly_large); - ("log-normal-small", Distribution.log_normal_small); - ("log-normal-medium", Distribution.log_normal_medium); - ("zipfian-small", Distribution.zipfian_small); - ("zipfian-medium", Distribution.zipfian_medium); - ("zipfian-steep", Distribution.zipfian_steep); -] +let distributions_list = + [ + ("uniform-small", Distribution.all_small); + ("uniform-large", Distribution.all_large); + ("around-threshold", Distribution.around_threshold); + ("mostly-small", Distribution.mostly_small); + ("mostly-large", Distribution.mostly_large); + ("log-normal-small", Distribution.log_normal_small); + ("log-normal-medium", Distribution.log_normal_medium); + ("zipfian-small", Distribution.zipfian_small); + ("zipfian-medium", Distribution.zipfian_medium); + ("zipfian-steep", Distribution.zipfian_steep); + ] (* Distribution argument *) let distribution = - let doc = Printf.sprintf - "Size distribution. One of: %s" - (String.concat ", " (List.map fst distributions_list)) in + let doc = + Printf.sprintf "Size distribution. One of: %s" + (String.concat ", " (List.map fst distributions_list)) + in Cmdliner.Arg.( value & opt (enum distributions_list) Distribution.around_threshold @@ -39,10 +41,7 @@ let n_contents = & info [ "n"; "contents" ] ~docv:"N" ~doc:"Number of contents to create") let inline_contents = - Cmdliner.Arg.( - value - & flag - & info [ "inline" ] ~doc:"Enable inline contents") + Cmdliner.Arg.(value & flag & info [ "inline" ] ~doc:"Enable inline contents") let inline_threshold = Cmdliner.Arg.( @@ -55,7 +54,8 @@ let n_reads = Cmdliner.Arg.( value & opt int 1_000 - & info [ "reads" ] ~docv:"N" ~doc:"Number of read operations for latency measurement") + & info [ "reads" ] ~docv:"N" + ~doc:"Number of read operations for latency measurement") let runs = Cmdliner.Arg.( @@ -64,19 +64,22 @@ let runs = & info [ "runs" ] ~docv:"N" ~doc:"Number of benchmark iterations") let run_all_flag = - Cmdliner.Arg.( - value - & flag - & info [ "all" ] ~doc:"Run all distributions") + Cmdliner.Arg.(value & flag & info [ "all" ] ~doc:"Run all distributions") let csv_header = - Cmdliner.Arg.( - value - & flag - & info [ "header" ] ~doc:"Print CSV header") + Cmdliner.Arg.(value & flag & info [ "header" ] ~doc:"Print CSV header") -let config distribution n_contents inline_contents inline_threshold n_reads runs = - Bench.{ distribution; n_contents; inline_contents; inline_threshold; n_reads; runs } +let config distribution n_contents inline_contents inline_threshold n_reads runs + = + Bench. + { + distribution; + n_contents; + inline_contents; + inline_threshold; + n_reads; + runs; + } (* Single distribution run *) let run_single csv_header dist_name config = @@ -92,59 +95,101 @@ let run_all n_contents inline_threshold n_reads runs = let distributions = distributions_list in Bench.print_csv_header (); Eio_main.run @@ fun env -> - List.iter (fun (dist_name, distribution) -> - (* First run without inlining *) - let config = Bench.{ distribution; n_contents; inline_contents = false; - inline_threshold; n_reads; runs } in - let result = Bench.run ~fs:env#fs ~config in - Bench.print_csv_row ~dist_name ~config result; - (* Then run with inlining *) - let config = Bench.{ config with inline_contents = true } in - let result = Bench.run ~fs:env#fs ~config in - Bench.print_csv_row ~dist_name ~config result - ) distributions + List.iter + (fun (dist_name, distribution) -> + (* First run without inlining *) + let config = + Bench. + { + distribution; + n_contents; + inline_contents = false; + inline_threshold; + n_reads; + runs; + } + in + let result = Bench.run ~fs:env#fs ~config in + Bench.print_csv_row ~dist_name ~config result; + (* Then run with inlining *) + let config = Bench.{ config with inline_contents = true } in + let result = Bench.run ~fs:env#fs ~config in + Bench.print_csv_row ~dist_name ~config result) + distributions (* Run threshold optimization: test multiple thresholds on selected distributions *) let run_optimize n_contents n_reads runs = Logs.set_level None; let thresholds = [ 8; 16; 24; 32; 48; 64; 96; 128 ] in (* Use representative distributions *) - let distributions = [ - ("zipfian-steep", Distribution.zipfian_steep); - ("zipfian-small", Distribution.zipfian_small); - ("log-normal-small", Distribution.log_normal_small); - ("mostly-small", Distribution.mostly_small); - ] in + let distributions = + [ + ("zipfian-steep", Distribution.zipfian_steep); + ("zipfian-small", Distribution.zipfian_small); + ("log-normal-small", Distribution.log_normal_small); + ("mostly-small", Distribution.mostly_small); + ] + in Bench.print_csv_header (); Eio_main.run @@ fun env -> - List.iter (fun (dist_name, distribution) -> - (* Baseline: no inlining *) - let config = Bench.{ distribution; n_contents; inline_contents = false; - inline_threshold = 0; n_reads; runs } in - let result = Bench.run ~fs:env#fs ~config in - Bench.print_csv_row ~dist_name ~config result; - (* Test each threshold *) - List.iter (fun inline_threshold -> - let config = Bench.{ distribution; n_contents; inline_contents = true; - inline_threshold; n_reads; runs } in + List.iter + (fun (dist_name, distribution) -> + (* Baseline: no inlining *) + let config = + Bench. + { + distribution; + n_contents; + inline_contents = false; + inline_threshold = 0; + n_reads; + runs; + } + in let result = Bench.run ~fs:env#fs ~config in - Bench.print_csv_row ~dist_name ~config result - ) thresholds - ) distributions + Bench.print_csv_row ~dist_name ~config result; + (* Test each threshold *) + List.iter + (fun inline_threshold -> + let config = + Bench. + { + distribution; + n_contents; + inline_contents = true; + inline_threshold; + n_reads; + runs; + } + in + let result = Bench.run ~fs:env#fs ~config in + Bench.print_csv_row ~dist_name ~config result) + thresholds) + distributions let cmd_run = - let run csv_header dist_name distribution n_contents inline_contents inline_threshold n_reads runs all = - if all then - run_all n_contents inline_threshold n_reads runs + let run csv_header dist_name distribution n_contents inline_contents + inline_threshold n_reads runs all = + if all then run_all n_contents inline_threshold n_reads runs else - run_single csv_header dist_name (config distribution n_contents inline_contents inline_threshold n_reads runs) + run_single csv_header dist_name + (config distribution n_contents inline_contents inline_threshold n_reads + runs) in let doc = "Run inline contents benchmark" in Cmdliner.Cmd.v (Cmdliner.Cmd.info "run" ~doc) - Cmdliner.Term.(const run $ csv_header $ distribution_name $ distribution - $ n_contents $ inline_contents $ inline_threshold - $ n_reads $ runs $ run_all_flag) + Cmdliner.Term.( + const run + $ csv_header + $ distribution_name + $ distribution + $ n_contents + $ inline_contents + $ inline_threshold + $ n_reads + $ runs + $ run_all_flag) let cmd_optimize = let doc = "Find optimal inlining threshold by testing multiple values" in @@ -157,7 +202,8 @@ let sweep_threshold = Cmdliner.Arg.( value & opt int 16 - & info [ "threshold"; "t" ] ~docv:"BYTES" ~doc:"Inlining threshold to test around") + & info [ "threshold"; "t" ] ~docv:"BYTES" + ~doc:"Inlining threshold to test around") let sweep_range = Cmdliner.Arg.( @@ -172,22 +218,46 @@ let run_sweep n_contents n_reads runs threshold range = Printf.printf "size,inline,store_bytes,write_ms,read_p50_us,read_p99_us\n"; Eio_main.run @@ fun env -> for size = threshold - range to threshold + range do - let distribution = Distribution.fixed [size] in - List.iter (fun inline_contents -> - let config = Bench.{ distribution; n_contents; inline_contents; - inline_threshold = threshold; n_reads; runs } in - let (store_size, write_time, p50, p99, _p999, _inlined, _non_inlined, _sizes) = - Bench.run ~fs:env#fs ~config in - Printf.printf "%d,%b,%d,%.2f,%.2f,%.2f\n" - size inline_contents store_size write_time p50 p99 - ) [ false; true ] + let distribution = Distribution.fixed [ size ] in + List.iter + (fun inline_contents -> + let config = + Bench. + { + distribution; + n_contents; + inline_contents; + inline_threshold = threshold; + n_reads; + runs; + } + in + let ( store_size, + write_time, + p50, + p99, + _p999, + _inlined, + _non_inlined, + _sizes ) = + Bench.run ~fs:env#fs ~config + in + Printf.printf "%d,%b,%d,%.2f,%.2f,%.2f\n" size inline_contents + store_size write_time p50 p99) + [ false; true ] done let cmd_sweep = let doc = "Sweep content sizes around inlining threshold" in Cmdliner.Cmd.v (Cmdliner.Cmd.info "sweep" ~doc) - Cmdliner.Term.(const run_sweep $ n_contents $ n_reads $ runs $ sweep_threshold $ sweep_range) + Cmdliner.Term.( + const run_sweep + $ n_contents + $ n_reads + $ runs + $ sweep_threshold + $ sweep_range) let cmds = [ cmd_run; cmd_optimize; cmd_sweep ] File "test/irmin-pack/bench_inline/bench.ml", line 1, characters 0-0: diff --git a/_build/default/test/irmin-pack/bench_inline/bench.ml b/_build/default/test/irmin-pack/bench_inline/.formatted/bench.ml index a8e7fd1..6c7d499 100644 --- a/_build/default/test/irmin-pack/bench_inline/bench.ml +++ b/_build/default/test/irmin-pack/bench_inline/.formatted/bench.ml @@ -3,41 +3,42 @@ module S = Irmin_tezos.Store type config = { - n_contents : int; (* Number of contents to create *) + n_contents : int; (* Number of contents to create *) distribution : Distribution.t; inline_contents : bool; - inline_threshold : int; (* Max serialized bytes for inlining *) - n_reads : int; (* Number of read operations for latency measurement *) - runs : int; (* Number of benchmark runs *) + inline_threshold : int; (* Max serialized bytes for inlining *) + n_reads : int; (* Number of read operations for latency measurement *) + runs : int; (* Number of benchmark runs *) } type metrics = { store_size_bytes : int; write_time_ms : float; - read_latencies_us : float array; (* Individual read latencies in microseconds *) + read_latencies_us : float array; + (* Individual read latencies in microseconds *) inlined_count : int; non_inlined_count : int; - content_sizes : int array; (* Actual sizes generated *) + content_sizes : int array; (* Actual sizes generated *) } -let default_config = { - n_contents = 10_000; - distribution = Distribution.around_threshold; - inline_contents = false; - inline_threshold = 48; - n_reads = 1_000; - runs = 5; -} +let default_config = + { + n_contents = 10_000; + distribution = Distribution.around_threshold; + inline_contents = false; + inline_threshold = 48; + n_reads = 1_000; + runs = 5; + } let root fs = Eio.Path.(fs / "_build" / "bench-inline") - -let reset_env ~fs () = - Eio.Path.rmtree ~missing_ok:true (root fs) - +let reset_env ~fs () = Eio.Path.rmtree ~missing_ok:true (root fs) let info () = S.Info.empty let open_repo ~sw ~fs ~fresh ~readonly ~inline_contents () = - let conf = Irmin_pack.Conf.init ~sw ~fs ~fresh ~readonly ~inline_contents (root fs) in + let conf = + Irmin_pack.Conf.init ~sw ~fs ~fresh ~readonly ~inline_contents (root fs) + in S.Repo.v conf (* Generate random content of given size *) @@ -47,22 +48,24 @@ let make_content size = (* Generate paths and contents based on distribution *) let generate ~config = let sizes = Distribution.sample ~n:config.n_contents config.distribution in - let contents = Array.mapi (fun i size -> - let path = [ Printf.sprintf "content_%06d" i ] in - let value = make_content size in - (path, value, size) - ) sizes in + let contents = + Array.mapi + (fun i size -> + let path = [ Printf.sprintf "content_%06d" i ] in + let value = make_content size in + (path, value, size)) + sizes + in contents (* Measure directory size recursively *) let rec dir_size path = if Sys.is_directory path then let entries = Sys.readdir path in - Array.fold_left (fun acc entry -> - acc + dir_size (Filename.concat path entry) - ) 0 entries - else - (Unix.stat path).Unix.st_size + Array.fold_left + (fun acc entry -> acc + dir_size (Filename.concat path entry)) + 0 entries + else (Unix.stat path).Unix.st_size (* Count inlined vs non-inlined contents by examining the backend *) let count_inlined repo = @@ -72,17 +75,19 @@ let count_inlined repo = let main = S.main repo in let head = S.Head.get main in let tree = S.Commit.tree head in - let root_node = match S.Tree.destruct tree with + let root_node = + match S.Tree.destruct tree with | `Node (n, _) -> S.to_backend_node n | `Contents _ -> failwith "Expected root to be a node" in let entries = S.Backend.Node.Val.list root_node in - List.iter (fun (_step, value) -> - match value with - | `Contents_inlined _ -> incr inlined - | `Contents _ -> incr non_inlined - | `Node _ -> () - ) entries; + List.iter + (fun (_step, value) -> + match value with + | `Contents_inlined _ -> incr inlined + | `Contents _ -> incr non_inlined + | `Node _ -> ()) + entries; (!inlined, !non_inlined) (* Run a single benchmark iteration *) @@ -95,14 +100,18 @@ let run_one ~sw ~fs ~config = Irmin.Tree.set_inline_contents_max_bytes config.inline_threshold; (* Write phase *) - let repo = open_repo ~sw ~fs ~fresh:true ~readonly:false - ~inline_contents:config.inline_contents () in + let repo = + open_repo ~sw ~fs ~fresh:true ~readonly:false + ~inline_contents:config.inline_contents () + in let main = S.main repo in let t0 = Unix.gettimeofday () in - let tree = Array.fold_left (fun tree (path, value, _size) -> - S.Tree.add tree path value - ) (S.Tree.empty ()) contents in + let tree = + Array.fold_left + (fun tree (path, value, _size) -> S.Tree.add tree path value) + (S.Tree.empty ()) contents + in S.set_tree_exn ~info main [] tree; let t1 = Unix.gettimeofday () in let write_time_ms = 1000.0 *. (t1 -. t0) in @@ -116,34 +125,47 @@ let run_one ~sw ~fs ~config = let store_size_bytes = dir_size store_path in (* Read phase - reopen in readonly mode *) - let repo = open_repo ~sw ~fs ~fresh:false ~readonly:true - ~inline_contents:config.inline_contents () in + let repo = + open_repo ~sw ~fs ~fresh:false ~readonly:true + ~inline_contents:config.inline_contents () + in let main = S.main repo in let head = S.Head.get main in let tree = S.Commit.tree head in (* Sample random reads and measure latency *) let n_contents = Array.length contents in - let read_latencies_us = Array.init config.n_reads (fun _ -> - let idx = Random.int n_contents in - let path, expected_value, _ = contents.(idx) in - let t0 = Unix.gettimeofday () in - let value = S.Tree.find tree path in - let t1 = Unix.gettimeofday () in - (match value with - | Some v when Bytes.equal v expected_value -> () - | Some v -> - Printf.eprintf "Warning: value mismatch at %s: expected %d bytes, got %d bytes\n" - (String.concat "/" path) (Bytes.length expected_value) (Bytes.length v) - | None -> - Printf.eprintf "Warning: missing value at %s\n" (String.concat "/" path)); - 1_000_000.0 *. (t1 -. t0) - ) in + let read_latencies_us = + Array.init config.n_reads (fun _ -> + let idx = Random.int n_contents in + let path, expected_value, _ = contents.(idx) in + let t0 = Unix.gettimeofday () in + let value = S.Tree.find tree path in + let t1 = Unix.gettimeofday () in + (match value with + | Some v when Bytes.equal v expected_value -> () + | Some v -> + Printf.eprintf + "Warning: value mismatch at %s: expected %d bytes, got %d bytes\n" + (String.concat "/" path) + (Bytes.length expected_value) + (Bytes.length v) + | None -> + Printf.eprintf "Warning: missing value at %s\n" + (String.concat "/" path)); + 1_000_000.0 *. (t1 -. t0)) + in S.Repo.close repo; - { store_size_bytes; write_time_ms; read_latencies_us; - inlined_count; non_inlined_count; content_sizes } + { + store_size_bytes; + write_time_ms; + read_latencies_us; + inlined_count; + non_inlined_count; + content_sizes; + } (* Compute latency percentiles *) let latency_percentiles latencies = @@ -156,7 +178,6 @@ let latency_percentiles latencies = (* Run benchmark with multiple iterations *) let run ~fs ~config = Eio.Switch.run @@ fun sw -> - (* Warm-up run *) let _ = run_one ~sw ~fs ~config in @@ -173,28 +194,36 @@ let run ~fs ~config = let median_store_size = store_sizes.(config.runs / 2) in (* Combine all read latencies from all runs *) - let all_latencies = Array.concat (Array.to_list - (Array.map (fun r -> r.read_latencies_us) results)) in + let all_latencies = + Array.concat + (Array.to_list (Array.map (fun r -> r.read_latencies_us) results)) + in let p50, p99, p999 = latency_percentiles all_latencies in (* Use first result for counts (should be same across runs) *) let r0 = results.(0) in - (median_store_size, median_write_time, p50, p99, p999, - r0.inlined_count, r0.non_inlined_count, r0.content_sizes) + ( median_store_size, + median_write_time, + p50, + p99, + p999, + r0.inlined_count, + r0.non_inlined_count, + r0.content_sizes ) (* Print results as CSV row *) let print_csv_header () = - Printf.printf "distribution,threshold,n_contents,store_bytes,write_ms,read_p50_us,read_p99_us,read_p999_us,inlined,non_inlined,size_stats\n" - -let print_csv_row ~dist_name ~config (store_size, write_time, p50, p99, p999, inlined, non_inlined, sizes) = - let threshold_str = if config.inline_contents then string_of_int config.inline_threshold else "off" in - Printf.printf "%s,%s,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%d,\"%s\"\n" - dist_name - threshold_str - config.n_contents - store_size - write_time - p50 p99 p999 - inlined non_inlined + Printf.printf + "distribution,threshold,n_contents,store_bytes,write_ms,read_p50_us,read_p99_us,read_p999_us,inlined,non_inlined,size_stats\n" + +let print_csv_row ~dist_name ~config + (store_size, write_time, p50, p99, p999, inlined, non_inlined, sizes) = + let threshold_str = + if config.inline_contents then string_of_int config.inline_threshold + else "off" + in + Printf.printf "%s,%s,%d,%d,%.2f,%.2f,%.2f,%.2f,%d,%d,\"%s\"\n" dist_name + threshold_str config.n_contents store_size write_time p50 p99 p999 inlined + non_inlined (Distribution.describe sizes) File "src/irmin-server/unix/server.ml", line 1, characters 0-0: diff --git a/_build/default/src/irmin-server/unix/server.ml b/_build/default/src/irmin-server/unix/.formatted/server.ml index 276f0f4..6ebee01 100644 --- a/_build/default/src/irmin-server/unix/server.ml +++ b/_build/default/src/irmin-server/unix/.formatted/server.ml @@ -239,8 +239,7 @@ module Make (Codec : Conn.Codec.S) (Store : Irmin.Generic_key.S) = struct let path = Store.Path.rcons prefix path in let kind = Store.Tree.kind tree Store.Path.empty in match kind with - | Some `Contents -> - Some (path, "contents", Store.Tree.hash tree) + | Some `Contents -> Some (path, "contents", Store.Tree.hash tree) | Some `Node -> Some (path, "node", Store.Tree.hash tree) | None -> None) keys File "bench/irmin-pack/bench_inlined_contents.ml", line 1, characters 0-0: diff --git a/_build/default/bench/irmin-pack/bench_inlined_contents.ml b/_build/default/bench/irmin-pack/.formatted/bench_inlined_contents.ml index d6c89ef..37b9ded 100644 --- a/_build/default/bench/irmin-pack/bench_inlined_contents.ml +++ b/_build/default/bench/irmin-pack/.formatted/bench_inlined_contents.ml @@ -36,9 +36,15 @@ let time_it name f = (ms, result) (* Content generators *) -let small_content i = Bytes.of_string (Printf.sprintf "v%d" (i mod 1000)) (* 2-4 bytes, will be inlined *) -let medium_content i = Bytes.of_string (Printf.sprintf "value_%06d" i) (* 12 bytes, will be inlined *) -let large_content i = Bytes.of_string (Printf.sprintf "large_content_value_%010d" i) (* 30 bytes, NOT inlined *) +let small_content i = Bytes.of_string (Printf.sprintf "v%d" (i mod 1000)) + +(* 2-4 bytes, will be inlined *) +let medium_content i = Bytes.of_string (Printf.sprintf "value_%06d" i) +(* 12 bytes, will be inlined *) + +let large_content i = + Bytes.of_string (Printf.sprintf "large_content_value_%010d" i) +(* 30 bytes, NOT inlined *) type content_size = Small | Medium | Large @@ -60,63 +66,65 @@ type config = { content_size : content_size; } -let _default_config = { - num_entries = 1000; - num_commits = 10; - content_size = Small; -} +let _default_config = + { num_entries = 1000; num_commits = 10; content_size = Small } (* Run a single benchmark *) let run_benchmark ~sw ~fs ~inline_contents ~config root = Eio.Path.rmtree ~missing_ok:true root; let store_config = Irmin_pack.config ~sw ~fs ~fresh:true - ~indexing_strategy:Irmin_pack.Indexing_strategy.minimal - ~inline_contents root + ~indexing_strategy:Irmin_pack.Indexing_strategy.minimal ~inline_contents + root in let repo = Store.Repo.v store_config in (* Benchmark: Write phase *) let write_time, commits = - time_it (Printf.sprintf "Write (%d commits x %d entries)" - config.num_commits config.num_entries) - (fun () -> - let commits = ref [] in - for commit_idx = 0 to config.num_commits - 1 do - let tree = Store.Tree.empty () in - let tree = - let rec add_entries tree i = - if i >= config.num_entries then tree - else - let key = [ Printf.sprintf "dir%d" (i / 100); - Printf.sprintf "file%d" i ] in - let value = content_of_size config.content_size - (commit_idx * config.num_entries + i) in - let tree = Store.Tree.add tree key value in - add_entries tree (i + 1) - in - add_entries tree 0 - in - let commit = Store.Commit.v repo ~parents:[] ~info tree in - commits := commit :: !commits - done; - !commits) + time_it + (Printf.sprintf "Write (%d commits x %d entries)" config.num_commits + config.num_entries) (fun () -> + let commits = ref [] in + for commit_idx = 0 to config.num_commits - 1 do + let tree = Store.Tree.empty () in + let tree = + let rec add_entries tree i = + if i >= config.num_entries then tree + else + let key = + [ + Printf.sprintf "dir%d" (i / 100); Printf.sprintf "file%d" i; + ] + in + let value = + content_of_size config.content_size + ((commit_idx * config.num_entries) + i) + in + let tree = Store.Tree.add tree key value in + add_entries tree (i + 1) + in + add_entries tree 0 + in + let commit = Store.Commit.v repo ~parents:[] ~info tree in + commits := commit :: !commits + done; + !commits) in (* Benchmark: Read phase - read all contents from last commit *) let read_time, () = - time_it (Printf.sprintf "Read (%d entries)" config.num_entries) - (fun () -> - match commits with - | [] -> () - | commit :: _ -> - let tree = Store.Commit.tree commit in - for i = 0 to config.num_entries - 1 do - let key = [ Printf.sprintf "dir%d" (i / 100); - Printf.sprintf "file%d" i ] in - let _ = Store.Tree.find tree key in - () - done) + time_it (Printf.sprintf "Read (%d entries)" config.num_entries) (fun () -> + match commits with + | [] -> () + | commit :: _ -> + let tree = Store.Commit.tree commit in + for i = 0 to config.num_entries - 1 do + let key = + [ Printf.sprintf "dir%d" (i / 100); Printf.sprintf "file%d" i ] + in + let _ = Store.Tree.find tree key in + () + done) in (* Get storage size *) @@ -131,7 +139,8 @@ let run ~sw ~fs ~config = let root_with_inline = Eio.Path.(fs / "_bench" / "inline-yes") in Fmt.pr "@.=== Benchmark: %s contents, %d commits x %d entries ===@.@." - (string_of_size config.content_size) config.num_commits config.num_entries; + (string_of_size config.content_size) + config.num_commits config.num_entries; Fmt.pr "--- Without inlining ---@."; let no_inline_write, no_inline_read, no_inline_size = @@ -153,8 +162,9 @@ let run ~sw ~fs ~config = ((with_inline_read -. no_inline_read) /. no_inline_read *. 100.0); Fmt.pr "Store size: %d MB (no inline) vs %d MB (inline) [%.1f%%]@." no_inline_size with_inline_size - (Float.of_int (with_inline_size - no_inline_size) /. - Float.of_int (max 1 no_inline_size) *. 100.0); + (Float.of_int (with_inline_size - no_inline_size) + /. Float.of_int (max 1 no_inline_size) + *. 100.0); () (* Command line interface *) @@ -169,7 +179,9 @@ let num_commits = Arg.(value & opt int 10 & info [ "c"; "num-commits" ] ~doc) let content_size = - let doc = "Content size: small (2-4 bytes), medium (12 bytes), or large (30 bytes)" in + let doc = + "Content size: small (2-4 bytes), medium (12 bytes), or large (30 bytes)" + in let sizes = [ ("small", Small); ("medium", Medium); ("large", Large) ] in Arg.(value & opt (enum sizes) Small & info [ "s"; "size" ] ~doc) @@ -186,6 +198,7 @@ let main () num_entries num_commits content_size = let cmd = let doc = "Benchmark inline contents performance" in let info = Cmd.info "bench-inlined-contents" ~doc in - Cmd.v info Term.(const main $ const () $ num_entries $ num_commits $ content_size) + Cmd.v info + Term.(const main $ const () $ num_entries $ num_commits $ content_size) let () = exit (Cmd.eval cmd) File "dune", line 1, characters 0-0: diff --git a/_build/default/dune b/_build/default/.formatted/dune index ed29bf8..34f5fc8 100644 --- a/_build/default/dune +++ b/_build/default/.formatted/dune @@ -8,5 +8,12 @@ (files README.md) (package irmin-cli) (deps %{bin:irmin}) - (libraries irmin irmin-cli irmin-git irmin-git.unix eio eio_main eio.unix + (libraries + irmin + irmin-cli + irmin-git + irmin-git.unix + eio + eio_main + eio.unix lwt_eio)) File "src/irmin/tree.ml", line 1, characters 0-0: diff --git a/_build/default/src/irmin/tree.ml b/_build/default/src/irmin/.formatted/tree.ml index 704dd05..28aea87 100644 --- a/_build/default/src/irmin/tree.ml +++ b/_build/default/src/irmin/.formatted/tree.ml @@ -510,7 +510,8 @@ module Make (P : Backend.S) = struct type portable = Portable.t [@@deriving irmin ~equal ~pp] (* [elt] is a tree *) - type elt = [ `Node of t * Contents.t list | `Contents of Contents.t * Metadata.t ] + type elt = + [ `Node of t * Contents.t list | `Contents of Contents.t * Metadata.t ] and update = Add of elt | Remove and updatemap = update StepMap.t @@ -1370,10 +1371,8 @@ module Make (P : Backend.S) = struct | `pruned ] Scan.t) with - | Map m -> - of_map m - | Repo_value (repo, v) -> - of_value repo v + | Map m -> of_map m + | Repo_value (repo, v) -> of_value repo v | Repo_key (repo, k) -> let v = value_of_key ~cache t repo k in let v = get_ok ctx v in @@ -1383,15 +1382,13 @@ module Make (P : Backend.S) = struct | Some (Add v) -> Some v | Some Remove -> None | None -> of_value repo v) - | Portable p -> - of_portable p + | Portable p -> of_portable p | Portable_dirty (p, um) -> ( match StepMap.find_opt step um with | Some (Add v) -> Some v | Some Remove -> None | None -> of_portable p) - | Pruned h -> - pruned_hash_exn ctx h + | Pruned h -> pruned_hash_exn ctx h in match Atomic.get t.info.findv_cache with | None -> of_t () @@ -1716,21 +1713,15 @@ module Make (P : Backend.S) = struct | `pruned ] Scan.t) with - | Map m -> - of_map m - | Repo_value (repo, v) -> - of_value repo v StepMap.empty + | Map m -> of_map m + | Repo_value (repo, v) -> of_value repo v StepMap.empty | Repo_key (repo, k) -> let v = value_of_key ~cache:true t repo k |> get_ok "update" in of_value repo v StepMap.empty - | Value_dirty (repo, v, um) -> - of_value repo v um - | Portable p -> - of_portable p StepMap.empty - | Portable_dirty (p, um) -> - of_portable p um - | Pruned h -> - pruned_hash_exn "update" h + | Value_dirty (repo, v, um) -> of_value repo v um + | Portable p -> of_portable p StepMap.empty + | Portable_dirty (p, um) -> of_portable p um + | Pruned h -> pruned_hash_exn "update" h let remove t step = update t step Remove let add t step v = update t step (Add v) @@ -1832,8 +1823,7 @@ module Make (P : Backend.S) = struct [@@deriving irmin ~equal] type t = - [ `Node of node * Contents.t list - | `Contents of Contents.t * Metadata.t ] + [ `Node of node * Contents.t list | `Contents of Contents.t * Metadata.t ] [@@deriving irmin] let to_backend_node n = @@ -2017,8 +2007,7 @@ module Make (P : Backend.S) = struct [%log.debug "Tree.seq %a" pp_path path]; sub ~cache "seq.sub" t path |> function | None -> Seq.empty - | Some n -> - Node.seq ?offset ?length ~cache n |> get_ok "seq" + | Some n -> Node.seq ?offset ?length ~cache n |> get_ok "seq" let list t ?offset ?length ?(cache = true) path = seq t ?offset ?length ~cache path |> List.of_seq @@ -2286,7 +2275,8 @@ module Make (P : Backend.S) = struct let to_bin = Type.(unstage (to_bin_string P.Contents.Val.t)) in let bytes = to_bin v in (* Add 2 bytes for variant tag and length prefix overhead *) - if String.length bytes + 2 < !inline_contents_max_bytes then Some bytes + if String.length bytes + 2 < !inline_contents_max_bytes then + Some bytes else None in @@ -2316,8 +2306,8 @@ module Make (P : Backend.S) = struct | Some k -> Some (step, `Contents (k, m)) | None -> assertion_failure - "Encountered child contents value with uncached key \ - during export:@,\ + "Encountered child contents value with uncached \ + key during export:@,\ @ @[%a@]" dump v))) in @@ -2347,14 +2337,15 @@ module Make (P : Backend.S) = struct | Add (`Contents (c, m) as v) -> ( (* Check if contents should be inlined at export time *) match should_inline_contents c with - | Some bytes -> P.Node.Val.add acc k (`Contents_inlined (bytes, m)) + | Some bytes -> + P.Node.Val.add acc k (`Contents_inlined (bytes, m)) | None -> ( match Contents.cached_key c with | Some ptr -> P.Node.Val.add acc k (`Contents (ptr, m)) | None -> assertion_failure - "Encountered child contents value 3 with uncached key \ - during export:@,\ + "Encountered child contents value 3 with uncached \ + key during export:@,\ @ @[%a@]" dump v))) updates v @@ -2676,8 +2667,7 @@ module Make (P : Backend.S) = struct let rec concrete : type r. concrete -> (t or_empty, r) cont = fun t k -> match t with - | `Contents (c, m) -> - k (Non_empty (of_contents ~metadata:m c)) + | `Contents (c, m) -> k (Non_empty (of_contents ~metadata:m c)) | `Tree childs -> tree StepMap.empty childs (function | Empty -> k Empty @@ -2758,8 +2748,7 @@ module Make (P : Backend.S) = struct match t with | `Node (n, il) -> `Node (Node.hash ~cache n, List.map (Contents.hash ~cache) il) - | `Contents (c, m) -> - `Contents (Contents.hash ~cache c, m) + | `Contents (c, m) -> `Contents (Contents.hash ~cache c, m) let stats ?(force = false) (t : t) = let cache = true in File "src/irmin-pack/inode.ml", line 1, characters 0-0: diff --git a/_build/default/src/irmin-pack/inode.ml b/_build/default/src/irmin-pack/.formatted/inode.ml index d6d6e25..75a79af 100644 --- a/_build/default/src/irmin-pack/inode.ml +++ b/_build/default/src/irmin-pack/.formatted/inode.ml @@ -2459,10 +2459,7 @@ struct ~mem:(Pack.unsafe_mem t) v let hash_exn = Val.hash_exn - - let add t v = - save t v - + let add t v = save t v let equal_hash = Irmin.Type.(unstage (equal H.t)) let check_hash expected got = File "src/irmin-pack-tools/tezos_explorer/show.ml", line 1, characters 0-0: diff --git a/_build/default/src/irmin-pack-tools/tezos_explorer/show.ml b/_build/default/src/irmin-pack-tools/tezos_explorer/.formatted/show.ml index 186b71a..c85f91b 100644 --- a/_build/default/src/irmin-pack-tools/tezos_explorer/show.ml +++ b/_build/default/src/irmin-pack-tools/tezos_explorer/.formatted/show.ml @@ -595,8 +595,10 @@ let show_inode c (inode : Files.Inode.compress) = | Contents_inlined_value (n, bytes, ()) -> let img1 = string A.(fg lightred ++ st bold) "Contents (inlined):" in let img2 = name n in - let content = strf ~attr:A.(fg lightwhite) "%d bytes" (String.length bytes) in - ( img1 <-> (void 2 0 <|> (img2 <-> content)), [] ) + let content = + strf ~attr:A.(fg lightwhite) "%d bytes" (String.length bytes) + in + (img1 <-> (void 2 0 <|> (img2 <-> content)), []) | Node (n, addr) -> let node, node_button = addr_show addr in let img1 = string A.(fg lightred ++ st bold) "Node:" in File "src/irmin-test/store.ml", line 1, characters 0-0: diff --git a/_build/default/src/irmin-test/store.ml b/_build/default/src/irmin-test/.formatted/store.ml index 2360957..ed2714d 100644 --- a/_build/default/src/irmin-test/store.ml +++ b/_build/default/src/irmin-test/.formatted/store.ml @@ -2390,9 +2390,7 @@ module Make (S : Generic_key) = struct let node_b = S.Tree.destruct tree - |> ( function - | `Contents _ -> assert false - | `Node (n, _il) -> n ) + |> ( function `Contents _ -> assert false | `Node (n, _il) -> n ) |> S.to_backend_node in let node_ph = pre_hash_of S.Backend.Node.Val.t node_b in dune build @fmt failed "/usr/bin/env" "bash" "-c" "opam exec -- dune build @fmt --ignore-promoted-rules || (echo "dune build @fmt failed"; exit 2)" failed with exit status 2 2026-01-22 11:42.03: Job failed: Failed: Build failed