Lower.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
val volume_identifier_t : volume_identifier Irmin.Type.t
type add_error = [
|
open_error
|
`Ro_not_allowed
|
`Multiple_empty_volumes
|
`File_exists of string
|
`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
.
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.
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.
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.