(* The album example: the client part *) (* The example is representative of the standard Java RMI benchmarks and examples: remote file servers (in the paper TCY09), album collection (of the paper IYTC09), etc. It is particularly akin to the remote linked list traversal RMI micro-benchmark See album.ml for more explanation and literature references. *) (* #load "unix.cma";; #load "config.cmo";; #load "wire.cmo";; #load "future.cmo";; #load "rpc_dsl.cmo";; #load "album.cmo";; *) open Rpc_dsl;; open Album;; open Wire;; open Future;; (* Declaration for the album interface: functions and their types *) (* We extend Chourai with more constants *) module Album = struct include CHRBatchExt let get_album : (string -> album_descr) chr = ref (Tag ("get_album", arr_typerep string_typerep album_typerep)) let next_album : (album_descr -> album_descr) chr = ref (Tag ("next_album", arr_typerep album_typerep album_typerep)) let get_title : (album_descr -> string) chr = ref (Tag ("get_title", arr_typerep album_typerep string_typerep)) let get_rating : (album_descr -> int) chr = ref (Tag ("get_rating", arr_typerep album_typerep int_typerep)) let delete_album : (album_descr -> string) chr = ref (Tag ("delete_album", arr_typerep album_typerep string_typerep)) end;; open Album;; (* Only one round-trip to the server *) let t11 = app get_album (string "small");; let t1v = let title = app get_title t11 and rating = app get_rating t11 in (force title, force rating);; let ("Title 0", 1) = t1v;; (* Client result: val t11 : Album.album_descr Album.chr = {contents = Var (4, )} Waiting for a response val t1v : string * int = ("Title 0", 1) *) (* Server trace: New connection Evaluating: App Tag:get_album "small" Evaluating: App Tag:get_title Var4 Evaluating: App Tag:get_rating Var4 Responses computed. Replying... *) (* Trying to get information about the nonexistent second album of the small collection *) let t21 = app next_album (app get_album (string "small"));; let "Skipped due to the earlier: Failure(\"next_album: the album collection is exhausted\")" = try let title = app get_title t21 and rating = app get_rating t21 in (force title, force rating); assert false with Failure e -> e ;; (* val t21 : Album.album_descr Album.chr Waiting for a response Exception: Failure "Skipped due to the earlier: Failure(\"next_album: the album collection is exhausted\")". *) (* Server trace: New connection Evaluating: App Tag:get_album "small" Evaluating: App Tag:next_album Var7 Responses computed. Replying... *) (* Get data on the nth album in the collection *) (* Only one round-trip to the server. The loop is unrolled on the client, but is executed entirely on the server. Compare with the familiar partial evaluation's 'power' specialized to the fixed exponent, with the loop completely unrolled. *) let rec skip_albums n album = if n <= 0 then album else skip_albums (pred n) (app next_album album) ;; let t31 = skip_albums 4 (app get_album (string "large"));; let t3v = let title = app get_title t31 and rating = app get_rating t31 in (force title, force rating);; (* val t31 : Album.album_descr Album.chr = {contents = Var (15, )} Waiting for a response val t3v : string * int = ("Title 104", 1) *) (* Server trace: New connection Evaluating: App Tag:get_album "large" Evaluating: App Tag:next_album Var11 Evaluating: App Tag:next_album Var12 Evaluating: App Tag:next_album Var13 Evaluating: App Tag:next_album Var14 Evaluating: App Tag:get_title Var15 Evaluating: App Tag:get_rating Var15 Responses computed. Replying... *) let t41 = (app get_album (string "large"));; let true = force (guard (app2 lt (app get_rating t41) (int 5)) (fun () -> app delete_album t41));; let t41 = skip_albums 1 (app get_album (string "large"));; let false = force (guard (app2 lt (app get_rating t41) (int 5)) (fun () -> app delete_album t41));; (* Delete low-rated albums among first n *) let delete_low_rating n = let rec loop album i = let t = guard (app2 lt (app get_rating album) (int 5)) (fun () -> app delete_album album) in if i >= n then force t else loop (app next_album album) (succ i) in loop (app get_album (string "large")) 0 ;; let true = delete_low_rating 4;; (* The server trace shows that all computation is done at the server side. New connection from Evaluating: App Tag:get_album "large" Evaluating: App Tag:get_album "large" Evaluating: App Tag:get_rating Var19 Evaluating: App2 Tag:< Var20 5 Evaluating: Guard Var21 in Let 22 = App Tag:delete_album Var19 Evaluating: App Tag:delete_album Var19 Evaluating: App Tag:next_album Var19 Evaluating: App Tag:get_rating Var24 Evaluating: App2 Tag:< Var25 5 Evaluating: Guard Var26 in Let 27 = App Tag:delete_album Var24 Evaluating: App Tag:next_album Var24 Evaluating: App Tag:get_rating Var29 Evaluating: App2 Tag:< Var30 5 Evaluating: Guard Var31 in Let 32 = App Tag:delete_album Var29 Evaluating: App Tag:delete_album Var29 Evaluating: App Tag:next_album Var29 Evaluating: App Tag:get_rating Var34 Evaluating: App2 Tag:< Var35 5 Evaluating: Guard Var36 in Let 37 = App Tag:delete_album Var34 Evaluating: App Tag:next_album Var34 Evaluating: App Tag:get_rating Var39 Evaluating: App2 Tag:< Var40 5 Evaluating: Guard Var41 in Let 42 = App Tag:delete_album Var39 Evaluating: App Tag:delete_album Var39 Responses computed successfully. Replying... *) Printf.printf "\nAll done\n";;