Module type Lower.S

module Io : Io.S

Low level IO abstraction. A typical implementation is unix. This abstraction is meant to be dead simple. Not a lot of documentation is required.

module Errs : Io_errors.S
module Volume : sig ... end
type t
type open_error = [
  1. | Volume.open_error
  2. | `Volume_missing of string
]
type close_error = [
  1. | Io.close_error
]
type nonrec volume_identifier = string
val volume_identifier_t : volume_identifier Irmin.Type.t
type add_error = [
  1. | open_error
  2. | `Ro_not_allowed
  3. | `Multiple_empty_volumes
  4. | `File_exists of string
  5. | `Invalid_parent_directory
]
val v : readonly:bool -> volume_num:int -> string -> (t, [> open_error ]) Stdlib.result

v ~readonly ~volume_num lower_root loads all volumes located in the directory lower_root.

volume_num is the number of volumes that are expected in lower_root. 0 is valid for an empty lower.

Error `Volume_missing path is returned if an expected volume is not on disk, with the path to first volume that is missing. This can happen if volume_num is larger than the number of volumes on disk, or if one of the volume directories has been renamed accidentally.

If readonly is false, no write operations are allowed.

val reload : volume_num:int -> t -> (unit, [> open_error ]) Stdlib.result

reload ~volume_num t reloads volumes located in the root directory of t, using volume_num as the expected number of volumes.

val close : t -> (unit, [> close_error ]) Stdlib.result

close t closes all resources opened by t.

val volume_num : t -> int

volume_num t returns the number of volumes in the lower t.

val add_volume : t -> (Volume.t, [> add_error ]) Stdlib.result

add_volume t adds a new empty volume to t.

If there is already an empty volume, Error `Multiple_empty_volumes is returned. Only one empty volume is allowed.

If t is read-only, Error `Ro_not_allowed is returned.

val find_volume : off:Optint.Int63.t -> t -> Volume.t option

find_volume ~off t returns the Volume that contains off.

val read_exn : off:Optint.Int63.t -> len:int -> ?volume:volume_identifier -> t -> bytes -> volume_identifier

read_exn ~off ~len ~volume t b will read len bytes from a global off located in the volume with identifier volume. The volume identifier of the volume where the read occurs is returned.

If volume is not provided, find_volume will be used to attempt to locate the correct volume for the read.

val set_readonly : t -> bool -> unit

set_readonly t flag changes the writing permission of the lower layer (where true is read only). This should only be called by the GC worker to temporarily allow RW before calling archive_seq_exn.

val archive_seq_exn : upper_root:string -> generation:int -> to_archive:(Optint.Int63.t * string Irmin.Export_for_backends.Seq.t) list -> t -> volume_identifier

archive_seq ~upper_root ~generation ~to_archive t is called by the GC worker during the creation of the new generation to archive to_archive in the lower layer and returns the identifier of the volume where data was appended.

It is the only write operation allowed on the lower layer, and it makes no observable change as the control file is left untouched : instead new changes are written to volume.gen.control, which is swapped during GC finalization.

val read_range_exn : off:Optint.Int63.t -> min_len:int -> max_len:int -> ?volume:volume_identifier -> t -> bytes -> int * volume_identifier

Same as read_exn but will read at least min_len bytes and at most max_len. Returns the read length and the volume identifier from which the data was fetched.

type create_error := [
  1. | open_error
  2. | close_error
  3. | add_error
  4. | `Sys_error of string
]
val create_from : src:string -> dead_header_size:int -> size:Optint.Int63.t -> string -> (unit, [> create_error ]) Stdlib.result

create_from ~src ~dead_header_size ~size lower_root initializes the first lower volume in the directory lower_root by moving the suffix file src with end offset size.

val swap : volume:volume_identifier -> generation:int -> volume_num:int -> t -> (unit, [> `Volume_not_found of string | `Sys_error of string | open_error ]) Stdlib.result

swap ~volume ~generation ~volume_num t will rename a new volume control file in volume for generation of GC and then reload the lower with volume_num volumes.

val cleanup : generation:int -> t -> (unit, [> `Sys_error of string ]) Stdlib.result

cleanup ~generation t will attempt to cleanup the appendable volume if a GC crash has occurred.