Skip to content

Commit 5f67805

Browse files
committed
update lwt httpstore
1 parent 7932b3d commit 5f67805

File tree

3 files changed

+102
-36
lines changed

3 files changed

+102
-36
lines changed

zarr-lwt/src/storage.ml

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -340,16 +340,16 @@ end
340340

341341
module HttpStore = struct
342342
exception Not_implemented
343-
exception Request_failed of string
343+
exception Request_failed of int * string
344344

345345
let raise_status_error s =
346346
let c = Cohttp.Code.code_of_status s in
347-
let msg = Printf.sprintf "%d: %s" c (Cohttp.Code.reason_phrase_of_code c) in
348-
raise (Request_failed msg)
347+
raise (Request_failed (c, Cohttp.Code.reason_phrase_of_code c))
349348

350349
module IO = struct
351350
module Deferred = Deferred
352351
open Deferred.Syntax
352+
open Deferred.Infix
353353
open Cohttp_lwt_unix
354354

355355
type t = {base_url : Uri.t}
@@ -363,7 +363,12 @@ module HttpStore = struct
363363
raise (Zarr.Storage.Key_not_found key)
364364
| e -> raise_status_error e
365365

366-
let size t key =
366+
let size t key = Lwt.catch
367+
(fun () -> get t key >>| String.length)
368+
(function
369+
| Zarr.Storage.Key_not_found _ -> Deferred.return 0
370+
| exn -> raise exn)
371+
(*let size t key =
367372
let url = Uri.with_path t.base_url key in
368373
let* resp = Client.head url in
369374
match Response.status resp with
@@ -375,7 +380,7 @@ module HttpStore = struct
375380
String.length data
376381
end
377382
| #Cohttp.Code.client_error_status as e when e = `Not_found -> Deferred.return 0
378-
| e -> raise_status_error e
383+
| e -> raise_status_error e *)
379384

380385
let is_member t key =
381386
let+ s = size t key in
@@ -390,11 +395,11 @@ module HttpStore = struct
390395
let size = String.length data in
391396
List.map (read_range ~data ~size) ranges
392397

393-
(*let set t key data =
398+
let set t key data =
394399
let url = Uri.with_path t.base_url key in
395400
let body = Cohttp_lwt.Body.of_string data in
396401
let headers = Cohttp.Header.of_list [("Content-Length", string_of_int (String.length data))] in
397-
let* resp, _ = Client.put ~body ~headers url in
402+
let* resp, _ = Client.post ~body ~headers url in
398403
match Response.status resp with
399404
| #Cohttp.Code.success_status -> Deferred.return_unit
400405
| e -> raise_status_error e
@@ -413,11 +418,14 @@ module HttpStore = struct
413418
Bytes.unsafe_to_string s
414419
in
415420
set t key (List.fold_left f ov rsv)
416-
*)
417421

418-
let set _ = raise Not_implemented
419-
let set_partial_values _ = raise Not_implemented
420-
let erase _ = raise Not_implemented
422+
let erase t key =
423+
let url = Uri.with_path t.base_url key in
424+
let* resp, _ = Client.delete url in
425+
match Response.status resp with
426+
| #Cohttp.Code.success_status -> Deferred.return_unit
427+
| e -> raise_status_error e
428+
421429
let erase_prefix _ = raise Not_implemented
422430
let list _ = raise Not_implemented
423431
let list_dir _ = raise Not_implemented

zarr-lwt/src/storage.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ end
2323

2424
module HttpStore : sig
2525
exception Not_implemented
26-
exception Request_failed of string
26+
exception Request_failed of int * string
2727
include Zarr.Storage.STORE with module Deferred = Deferred
2828
val with_open : string -> (t -> 'a Lwt.t) -> 'a Lwt.t
2929
end

zarr-lwt/test/test_lwt.ml

Lines changed: 82 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -149,21 +149,52 @@ let _ =
149149
and profile = "default" in
150150

151151
let promises =
152-
[ZipStore.with_open `Read_write zpath (fun z -> test_storage (module ZipStore) z)
152+
[ZipStore.with_open `Read_write zpath (test_storage (module ZipStore))
153153
(* test just opening the now exisitant archive created by the previous test. *)
154154
;ZipStore.with_open `Read_only zpath (fun _ -> ZipStore.Deferred.return_unit)
155155
;AmazonS3Store.with_open ~region ~bucket ~profile (test_storage (module AmazonS3Store))
156-
;test_storage (module MemoryStore) @@ MemoryStore.create ()
156+
;test_storage (module MemoryStore) (MemoryStore.create ())
157157
;test_storage (module FilesystemStore) s
158158
;HttpStore.with_open "http://127.0.0.1:8080" (fun store ->
159159
let module S = Tiny_httpd in
160-
let dir_behavior = S.Dir.Lists and download = true and delete = true and upload = true in
161-
let config = S.Dir.config ~dir_behavior ~delete ~upload ~download ()
162-
and addr = "127.0.0.1" and port = 8080 in
163-
let server = S.create ~max_connections:4 ~addr ~port () in
164-
(*let dir = "/home/zoj/dev/zarr-ml/testdata.zarr" in *)
165-
let dir = Sys.getenv "HTTPSTORE_DIR" in
166-
S.Dir.add_dir_path ~config ~dir ~prefix:"" server;
160+
let server = S.create ~max_connections:1000 ~addr:"127.0.0.1" ~port:8080 () in
161+
let dir = tmp_dir in
162+
S.add_route_handler server ~meth:`HEAD S.Route.rest_of_path_urlencoded (fun path _ ->
163+
let fspath = Filename.concat dir path in
164+
match In_channel.(with_open_gen [Open_rdonly] 0o700 fspath length) with
165+
| exception Sys_error e -> S.Response.make_raw ~code:404 e
166+
| s ->
167+
let headers =
168+
[("Content-Length", Int64.to_string s)
169+
;("Content-Type",
170+
if String.ends_with ~suffix:".json" path
171+
then "application/json"
172+
else "application/octet-stream")]
173+
in
174+
let r = S.Response.make_raw ~code:200 "" in
175+
S.Response.update_headers (List.append headers) r
176+
);
177+
S.add_route_handler server ~meth:`GET S.Route.rest_of_path_urlencoded (fun path _ ->
178+
let fspath = Filename.concat dir path in
179+
match In_channel.(with_open_gen [Open_rdonly] 0o700 fspath input_all) with
180+
| exception Sys_error _ -> S.Response.make_raw ~code:404 (Printf.sprintf "%s not found" path)
181+
| s -> S.Response.make_raw ~code:200 s
182+
);
183+
S.add_route_handler server ~meth:`POST S.Route.rest_of_path_urlencoded (fun path req ->
184+
let write oc = Out_channel.(output_string oc req.body; flush oc) in
185+
let fspath = Filename.concat dir path in
186+
Zarr.Util.create_parent_dir fspath 0o700;
187+
let f = [Open_wronly; Open_trunc; Open_creat] in
188+
match Out_channel.(with_open_gen f 0o700 fspath write) with
189+
| exception Sys_error e -> S.Response.make_raw ~code:500 e
190+
| () -> S.Response.make_raw ~code:201 req.body
191+
);
192+
S.add_route_handler server ~meth:`DELETE S.Route.rest_of_path_urlencoded (fun path _ ->
193+
let fspath = Filename.concat dir path in
194+
match Sys.remove fspath with
195+
| exception Sys_error e -> S.Response.make_raw ~code:404 e
196+
| () -> S.Response.make_raw ~code:200 (Printf.sprintf "%s deleted successfully" path)
197+
);
167198
let _ = Thread.create S.run server in
168199

169200
let open Deferred.Syntax in
@@ -172,25 +203,52 @@ let _ =
172203
(fun () -> let* _ = f () in Deferred.return_unit)
173204
(function
174205
| HttpStore.Not_implemented -> Deferred.return_unit
175-
| exn -> raise exn)
206+
| _ -> failwith "Supposed to raise Not_implemented")
176207
in
177-
let gnode = Node.Group.of_path "/some/group" in
208+
let gnode = Node.Group.root in
209+
let attrs = `Assoc [("questions", `String "answer")] in
210+
let* () = HttpStore.Group.create ~attrs store gnode in
211+
let* exists = HttpStore.Group.exists store gnode in
212+
assert_equal ~printer:string_of_bool true exists;
178213
let* meta = HttpStore.Group.metadata store gnode in
179-
assert_equal ~printer:Metadata.Group.show Metadata.Group.default meta;
180-
let anode = Node.Array.of_path "/some/group/another" in
181-
let slice = [|R [|0; 5|]; I 10; R [|0; 10|]|] in
182-
let* _ = HttpStore.Array.read store anode slice Complex32 in
183-
let* () = assert_not_implemented (fun () -> HttpStore.hierarchy store) in
184-
let* () = assert_not_implemented (fun () -> HttpStore.Group.create store (Node.Group.of_path "/blah")) in
214+
assert_equal ~printer:Yojson.Safe.show attrs (Metadata.Group.attributes meta);
215+
let* exists = HttpStore.Array.exists store Node.Array.(gnode / "non-member") in
216+
assert_equal ~printer:string_of_bool false exists;
217+
let cfg =
218+
{chunk_shape = [|2; 5; 5|]
219+
;index_location = End
220+
;index_codecs = [`Bytes LE]
221+
;codecs = [`Transpose [|2; 0; 1|]; `Bytes BE]} in
222+
let anode = Node.Array.(gnode / "arrnode")
223+
and slice = [|R [|0; 5|]; I 10; R [|0; 10|]|]
224+
and bigger_slice = [|R [|0; 6|]; L [|9; 10|] ; R [|0; 11|]|]
225+
and codecs = [`ShardingIndexed cfg] and shape = [|100; 100; 50|] and chunks = [|10; 15; 20|] in
226+
let* () = HttpStore.Array.create ~codecs ~shape ~chunks Complex32 Complex.one anode store in
227+
let exp = Ndarray.init Complex32 [|6; 1; 11|] (Fun.const Complex.one) in
228+
let* got = HttpStore.Array.read store anode slice Complex32 in
229+
assert_equal exp got;
230+
Ndarray.fill exp Complex.{re=2.0; im=0.};
231+
let* () = HttpStore.Array.write store anode slice exp in
232+
let* got = HttpStore.Array.read store anode slice Complex32 in
233+
(* test if a bigger slice containing new elements can be read from store *)
234+
let* _ = HttpStore.Array.read store anode bigger_slice Complex32 in
235+
assert_equal exp got;
236+
(* test writing a bigger slice to store *)
237+
let* () = HttpStore.Array.write store anode bigger_slice @@ Ndarray.init Complex32 [|7; 2; 12|] (Fun.const Complex.{re=0.; im=3.0}) in
238+
let* got = HttpStore.Array.read store anode slice Complex32 in
239+
Ndarray.fill exp Complex.{re=0.; im=3.0};
240+
assert_equal exp got;
241+
let nshape = [|25; 28; 10|] in
242+
let* () = HttpStore.Array.reshape store anode nshape in
243+
let* meta = HttpStore.Array.metadata store anode in
244+
assert_equal ~printer:print_int_array nshape (Metadata.Array.shape meta);
245+
let* () = assert_not_implemented (fun () -> HttpStore.Array.rename store anode "newname") in
185246
let* () = assert_not_implemented (fun () -> HttpStore.Group.children store gnode) in
186-
(*let* () = assert_not_implemented (fun () -> HttpStore.Array.rename store anode "newname") in *)
187-
let* () = assert_not_implemented (fun () -> HttpStore.Array.reshape store anode [|1;1;1|]) in
188-
let* () = assert_not_implemented (fun () -> HttpStore.clear store) in
189-
let+ () = assert_not_implemented (fun () ->
190-
let exp = Ndarray.init Complex32 [|6; 1; 11|] (Fun.const Complex.one) in
191-
HttpStore.Array.write store anode slice exp) in
247+
let* () = assert_not_implemented (fun () -> HttpStore.hierarchy store) in
248+
let* () = assert_not_implemented (fun () -> HttpStore.Group.delete store gnode) in
249+
let+ () = assert_not_implemented (fun () -> HttpStore.clear store) in
192250
Tiny_httpd.stop server)
193251
]
194252
in
195-
ignore (Lwt_main.run @@ Lwt.join promises))
253+
Lwt_main.run @@ Lwt.join promises)
196254
])

0 commit comments

Comments
 (0)