Skip to content

Commit 514167b

Browse files
committed
Add ZipStore storage backend.
This commit adds a ZipStore storage backend as described in the specification zarr-developers/zarr-specs#311 . Note that the implementation loads the entire zip archive into memory so care must be taken to ensure the zip archive is not too big to fit into the machine's memory. To use a ZipStore impelementation that does not load the archive into memory see `examples/zipstore.ml`.
1 parent 4ecee33 commit 514167b

File tree

17 files changed

+265
-212
lines changed

17 files changed

+265
-212
lines changed

dune-project

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
(and (>= 4.14.0)))
3131
(yojson (>= 1.6.0))
3232
(stdint (>= 0.7.2))
33+
(zipc (>= 0.2.0))
3334
(checkseum (>= 0.4.0))
3435
(odoc :with-doc)
3536
(ounit2 :with-test)

examples/dune

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@
44
(ocamlopt_flags (:standard -O3))
55
(libraries zarr-eio camlzip))
66

7-
(executable
8-
(name inmemory_zipstore)
9-
(modules inmemory_zipstore)
10-
(ocamlopt_flags (:standard -O3))
11-
(libraries zarr-lwt zipc))
12-
137
(executable
148
(name picos_fs_store)
159
(modules picos_fs_store)

examples/inmemory_zipstore.ml

Lines changed: 0 additions & 203 deletions
This file was deleted.

zarr-eio/src/storage.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ module MemoryStore = struct
33
let create = Zarr.Memory.create
44
end
55

6+
module ZipStore = struct
7+
module Z = Zarr.Zip.Make(Deferred)
8+
include Zarr.Storage.Make(Z)
9+
let with_open = Z.with_open
10+
end
11+
612
module FilesystemStore = struct
713
module FS = struct
814
module Deferred = Deferred

zarr-eio/src/storage.mli

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,38 @@ module MemoryStore : sig
77
(** [create ()] returns a new In-memory Zarr store type. *)
88
end
99

10+
module ZipStore : sig
11+
(** An Eio-aware Zip file storage backend for a Zarr v3 hierarchy. *)
12+
13+
include Zarr.Storage.STORE with type 'a Deferred.t = 'a
14+
15+
val with_open :
16+
?level:[ `None | `Fast | `Default | `Best ] ->
17+
?perm:Unix.file_perm ->
18+
[< `Read_only | `Read_write ] ->
19+
string ->
20+
(t -> 'a) ->
21+
'a
22+
(** [with_open mode p f] opens the zip archive at path [p] and applies
23+
function [f] to its open handle and writes any changes back to the zip
24+
archive if [mode] is [`Read_write], otherwise discards them at exit.
25+
If [p] does not exist, a handle to an empty zip archive is opened.
26+
Note that this function loads the entire zip archive into memory, so care
27+
must be taken to ensure that the compressed file contents can fit into
28+
memory. For now it does not handle ZIP64. ZIP64 is needed if your ZIP
29+
archive or decompressed file sizes exceed 2{^32}-1 bytes or if you need
30+
more than 65535 archive members.
31+
32+
{ul
33+
{- [level] is the DEFLATE algorithm compression level used when writing
34+
data to the store and defaults to [`Default]. Choose [`None] for no
35+
compression, [`Fast] for best speed, [`Best] for high compression rate
36+
and [`Default] for a mix of good speed and compression rate.}
37+
{- [perm] is the file permission to use when opening an existing zip file
38+
and defaults to [0o700].}
39+
} *)
40+
end
41+
1042
module FilesystemStore : sig
1143
(** A local filesystem storage backend for a Zarr V3 hierarchy. *)
1244

zarr-eio/test/test_eio.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ let _ =
143143
(Zarr.Storage.Not_a_filesystem_store fn)
144144
(fun () -> FilesystemStore.open_store ~env fn);
145145

146+
(* test with non-existant archive *)
147+
let zpath = tmp_dir ^ ".zip" in
148+
ZipStore.with_open `Read_write zpath (fun z -> test_storage (module ZipStore) z);
149+
(* test just opening the now exisitant archive created by the previous test. *)
150+
ZipStore.with_open `Read_only zpath (fun _ -> ZipStore.Deferred.return_unit);
146151
test_storage (module MemoryStore) @@ MemoryStore.create ();
147152
test_storage (module FilesystemStore) s)
148153
])

zarr-lwt/src/storage.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ module MemoryStore = struct
33
let create = Zarr.Memory.create
44
end
55

6+
module ZipStore = struct
7+
module Z = Zarr.Zip.Make(Deferred)
8+
include Zarr.Storage.Make(Z)
9+
let with_open = Z.with_open
10+
end
11+
612
module FilesystemStore = struct
713
module FS = struct
814
module Deferred = Deferred

zarr-lwt/src/storage.mli

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,38 @@ module MemoryStore : sig
77
(** [create ()] returns a new In-memory Zarr store type. *)
88
end
99

10+
module ZipStore : sig
11+
(** An Lwt-aware Zip file storage backend for a Zarr v3 hierarchy. *)
12+
13+
include Zarr.Storage.STORE with type 'a Deferred.t = 'a Lwt.t
14+
15+
val with_open :
16+
?level:[ `None | `Fast | `Default | `Best ] ->
17+
?perm:Unix.file_perm ->
18+
[< `Read_only | `Read_write ] ->
19+
string ->
20+
(t -> 'a Lwt.t) ->
21+
'a Lwt.t
22+
(** [with_open mode p f] opens the zip archive at path [p] and applies
23+
function [f] to its open handle and writes any changes back to the zip
24+
archive if [mode] is [`Read_write], otherwise discards them at exit.
25+
If [p] does not exist, a handle to an empty zip archive is opened.
26+
Note that this function loads the entire zip archive into memory, so care
27+
must be taken to ensure that the compressed file contents can fit into
28+
memory. For now it does not handle ZIP64. ZIP64 is needed if your ZIP
29+
archive or decompressed file sizes exceed 2{^32}-1 bytes or if you need
30+
more than 65535 archive members.
31+
32+
{ul
33+
{- [level] is the DEFLATE algorithm compression level used when writing
34+
data to the store and defaults to [`Default]. Choose [`None] for no
35+
compression, [`Fast] for best speed, [`Best] for high compression rate
36+
and [`Default] for a mix of good speed and compression rate.}
37+
{- [perm] is the file permission to use when opening an existing zip file
38+
and defaults to [0o700].}
39+
} *)
40+
end
41+
1042
module FilesystemStore : sig
1143
(** A local filesystem storage backend for a Zarr V3 hierarchy. *)
1244

zarr-lwt/test/test_lwt.ml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,11 @@ let _ =
141141
(Zarr.Storage.Not_a_filesystem_store fn)
142142
(fun () -> FilesystemStore.open_store fn);
143143

144-
Lwt_main.run @@
145-
Lwt.join
146-
[test_storage (module MemoryStore) @@ MemoryStore.create ()
144+
let zpath = tmp_dir ^ ".zip" in
145+
Lwt_main.run @@ Lwt.join
146+
[ZipStore.with_open `Read_write zpath (fun z -> test_storage (module ZipStore) z)
147+
(* test just opening the now exisitant archive created by the previous test. *)
148+
;ZipStore.with_open `Read_only zpath (fun _ -> ZipStore.Deferred.return_unit)
149+
;test_storage (module MemoryStore) @@ MemoryStore.create ()
147150
;test_storage (module FilesystemStore) s])
148151
])

zarr-sync/src/storage.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ module MemoryStore = struct
33
let create = Zarr.Memory.create
44
end
55

6+
module ZipStore = struct
7+
module Z = Zarr.Zip.Make(Deferred)
8+
include Zarr.Storage.Make(Z)
9+
let with_open = Z.with_open
10+
end
11+
612
module FilesystemStore = struct
713
module F = struct
814
module Deferred = Deferred

0 commit comments

Comments
 (0)