[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-API] [PATCH] add new modules to stdext



# HG changeset patch
# User David Scott <dave.scott@xxxxxxxxxxxxx>
# Date 1279751355 -3600
# Node ID 542efa53c3e25342a175ead7f9327b972f976820
# Parent  ad151dc6eb4578f098df793e92498a9ba1a9ec3a
Add new modules: lazyList, extentlistSet, set_test to stdext

lazyList contains a simple lazy list implementation.
extentlistSet contains a Set implementation where elements are stored as a list 
of (start, length) pairs
set_test contains functions to test a set implementation

extentlistset_test contains test cases for extentlistSet using set_test.

Signed-off-by: David Scott <dave.scott@xxxxxxxxxxxxx>

diff -r ad151dc6eb45 -r 542efa53c3e2 stdext/Makefile
--- a/stdext/Makefile   Mon Jul 12 08:33:28 2010 +0100
+++ b/stdext/Makefile   Wed Jul 21 23:29:15 2010 +0100
@@ -22,12 +22,13 @@
 
 STDEXT_OBJS = fun opt listext filenameext stringext arrayext hashtblext 
pervasiveext threadext ring \
        qring fring bigbuffer unixext range vIO trie config date encodings fe 
fecomms \
-       forkhelpers gzip sha1sum zerocheck base64 backtrace tar mapext os either
+       forkhelpers gzip sha1sum zerocheck base64 backtrace tar mapext os 
either \
+       lazyList extentlistSet set_test
 
 INTF = $(foreach obj, $(STDEXT_OBJS),$(obj).cmi)
 LIBS = stdext.cma stdext.cmxa
 
-PROGRAMS = base64pp fe_cli fe_test
+PROGRAMS = base64pp fe_cli fe_test extentlistset_test
 
 DOCDIR = /myrepos/xen-api-libs.hg/doc
 
@@ -46,6 +47,9 @@
 fe_test: fe_test.ml all libstdext_stubs.a
        ocamlfind $(OCAMLOPT) $(OCAMLOPTFLAGS) unix.cmxa ../uuid/uuid.cmxa 
../rpc-light/rpc.cmx ../rpc-light/jsonrpc.cmx stdext.cmxa -linkpkg -I ../uuid 
-o $@ $< -ccopt -L.
 
+extentlistset_test: extentlistset_test.ml all libstdext_stubs.a
+       ocamlfind $(OCAMLOPT) $(OCAMLOPTFLAGS) unix.cmxa stdext.cmxa -linkpkg 
-o $@ $< -ccopt -L.
+
 stdext.cmxa: libstdext_stubs.a $(foreach obj,$(STDEXT_OBJS),$(obj).cmx)
        $(OCAMLOPT) $(OCAMLOPTFLAGS) -a -o $@ -cclib -lstdext_stubs $(foreach 
obj,$(STDEXT_OBJS),$(obj).cmx)
 
diff -r ad151dc6eb45 -r 542efa53c3e2 stdext/extentlistSet.ml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/stdext/extentlistSet.ml   Wed Jul 21 23:29:15 2010 +0100
@@ -0,0 +1,106 @@
+
+module type Number = sig
+       type t
+       val zero: t
+       val add : t -> t -> t
+       val sub : t -> t -> t
+end
+
+module ExtentlistSet (A : Number) =
+struct
+       type extent = A.t * A.t
+       type t = extent list
+
+       let ($+) = A.add
+       let ($-) = A.sub
+
+       let empty = []
+
+       let sort list : t =
+               List.sort (fun x y -> compare (fst x) (fst y)) list
+
+       let remove_zeroes = List.filter (fun (_, y) -> y <> A.zero)
+
+       let union (list1: t) (list2: t) : t =
+               let combined = sort (list1 @ list2) in
+               let rec inner l acc =
+                       match l with
+                               | (s1,e1)::(s2,e2)::ls ->
+                                       let extent1_end = s1 $+ e1 in
+                                       if extent1_end < s2 then
+                                               inner ((s2,e2)::ls) 
((s1,e1)::acc)
+                                       else
+                                               let extent2_end = s2 $+ e2 in
+                                               if extent1_end > extent2_end 
then
+                                                       inner ((s1,e1)::ls) acc
+                                               else
+                                                       inner ((s1,s2 $+ e2 $- 
s1)::ls) acc
+                               | (s1,e1)::[] -> (s1,e1)::acc
+                               | [] -> []
+               in List.rev (inner combined [])
+
+       let intersection (list1: t) (list2: t) =
+               let rec inner l1 l2 acc =
+                       match (l1,l2) with
+                               | (s1,e1)::l1s , (s2,e2)::l2s ->
+                                       if s1 > s2 then inner l2 l1 acc else
+                                               if s1 $+ e1 < s2 then inner l1s 
l2 acc else
+                                                       if s1 < s2 then inner 
((s2,e1 $+ s1 $- s2)::l1s) l2 acc else
+                                                               (* s1=s2 *)
+                                                               if e1 < e2 then
+                                                                       inner 
l1s ((s2 $+ e1,e2 $- e1)::l2s) ((s1,e1)::acc)
+                                                               else if e1 > e2 
then
+                                                                       inner 
((s1 $+ e2,e1 $- e2)::l1s) l2s ((s2,e2)::acc)
+                                                               else (* e1=e2 *)
+                                                                       inner 
l1s l2s ((s1,e1)::acc)
+                               | _ -> List.rev acc
+               in
+               remove_zeroes(inner list1 list2 [])
+
+       let difference (list1: t) (list2: t) : t =
+               let rec inner l1 l2 acc =
+                       match (l1,l2) with
+                               | (s1,e1)::l1s , (s2,e2)::l2s ->
+                                       if s1<s2 then begin
+                                               if s1 $+ e1 > s2 then
+                                                       inner ((s2,s1 $+ e1 $- 
s2)::l1s) l2 ((s1,s2 $- s1)::acc)
+                                               else
+                                                       inner l1s l2 
((s1,e1)::acc)
+                                       end else if s1>s2 then begin
+                                               if s2 $+ e2 > s1 then
+                                                       inner l1 ((s1,s2 $+ e2 
$- s1)::l2s) acc
+                                               else
+                                                       inner l1 l2s acc
+                                       end else begin
+                                               (* s1=s2 *)
+                                               if e1 > e2 then
+                                                       inner ((s1 $+ e2,e1 $- 
e2)::l1s) l2s acc
+                                               else if e1 < e2 then
+                                                       inner l1s ((s2 $+ e1,e2 
$- e1)::l2s) acc
+                                               else
+                                                       inner l1s l2s acc
+                                       end
+                               | l1s, [] -> (List.rev acc) @ l1s
+                               | [], _ -> List.rev acc
+               in
+               remove_zeroes(inner list1 list2 [])
+
+       let of_list (list: extent list) : t =
+               let l = sort list in
+               let rec inner ls acc =
+                       match ls with
+                               | (s1,e1)::(s2,e2)::rest ->
+                                       (* extents should be non-overlapping *)
+                                       if s1 $+ e1 > s2 then failwith "Bad 
list"
+                                       (* adjacent extents should be coalesced 
*)
+                                       else if s1 $+ e1=s2 then inner ((s1,e1 
$+ e2)::rest) acc
+                                       else inner ((s2,e2)::rest) 
((s1,e1)::acc)
+                               | (s1,e1)::[] -> List.rev ((s1,e1)::acc)
+                               | [] -> List.rev acc
+               in
+               inner l []
+
+       let fold_left = List.fold_left
+
+       let to_list x = x
+end
diff -r ad151dc6eb45 -r 542efa53c3e2 stdext/extentlistSet.mli
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/stdext/extentlistSet.mli  Wed Jul 21 23:29:15 2010 +0100
@@ -0,0 +1,27 @@
+(** A module to represent sets of elements as (start, length) pairs. *)
+
+(** Elements must be 'Numbers': *)
+module type Number = sig 
+       type t 
+       val zero: t
+       val add : t -> t -> t 
+       val sub : t -> t -> t 
+
+end
+
+(** Representation of a Set *)
+module ExtentlistSet: functor (A : Number) -> sig
+       type extent = A.t * A.t
+       type t
+
+       val empty : t
+
+       val union : t -> t -> t
+       val intersection : t -> t -> t
+       val difference : t -> t -> t
+
+       val of_list : extent list -> t
+       val to_list : t -> extent list
+       val fold_left : ('a -> extent -> 'a) -> 'a -> t -> 'a
+end
+
diff -r ad151dc6eb45 -r 542efa53c3e2 stdext/extentlistset_test.ml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/stdext/extentlistset_test.ml      Wed Jul 21 23:29:15 2010 +0100
@@ -0,0 +1,92 @@
+(* We will check if a list of set equalities hold over random inputs *)
+
+open Set_test
+
+(* We test using the integer domain only. *)
+module Intextentlist = ExtentlistSet.ExtentlistSet(struct 
+  type t=int 
+  let zero=0 
+  let add=(+) 
+  let sub=(-) 
+end)
+open Intextentlist
+
+(* Sets are finite, up to cardinality [size] *)
+let size = 1000
+
+module Tests = SetEqualities(struct
+       type t = Intextentlist.t
+       let universe = of_list [(0, size)]
+       let (+) = union
+       let (^) = intersection
+       let (-) = difference
+
+       let not x = universe - x
+       let (=) x y = (x - y = empty) && (y - x = empty)
+       let extent_to_string (s, l) = Printf.sprintf "(%d, %d)" s l
+       let to_string xs = String.concat ", " (List.map extent_to_string 
(to_list xs))
+end)
+(* Given a triple of inputs, check that all the set equalities hold *)
+let one (a, b, c) = List.iter (fun f -> f a b c) Tests.all
+
+open LazyList
+
+(** [make p s e] return an extentlist starting at [s], ending before [e] where
+    an integer x is covered by the extentlist iff [p x] *)
+let make p s e =
+  let rec ints acc a b = if a < b then ints (a :: acc) (a + 1) b else acc in
+  of_list (List.fold_left (fun acc x -> if p x then (x, 1)::acc else acc) [] 
(ints [] s e))
+
+(* A lazy-list of random triples (a, b, c)*)
+let random_inputs =    
+  let one () = make (fun _ -> Random.bool ()) 0 (size - 1) in
+  (* Create triples of random inputs for the checker *)
+  let three () = one (), one (), one () in
+  let rec f () = lazy (Cons(three (), f ())) in
+  f ()
+
+let _ = 
+  let n = 1000 in
+  iter (fun _ -> ()) (take n (map one random_inputs));
+  Printf.printf "%d random sets of maximum size %d checked.\n" n size
+
+type run = 
+  | Empty of int
+  | Full of int
+let to_run_list xs = 
+  let rec inner acc index = function
+       | [] -> acc
+       | (x, y) :: xs -> inner (Full y :: (Empty (x - index)) :: acc) (x + y) 
xs in  let map f xs = 
+       let rec inner acc f = function
+         | [] -> acc
+         | (x :: xs) -> inner ((f x)::acc) f xs in
+         inner [] f xs in
+
+       List.rev (inner [] 0 xs)
+
+let _ =
+  (* vhds have max size of 2 TiB, in 2 MiB blocks => 2**20 blocks *)
+  (* The BAT consists of up to 2**20 blocks in any order *)
+  (* Worst case for us is as many singleton blocks as possible, which *)
+  (* can't be coalesced because they don't have neighbours. The maximum *)
+  (* number of blocks is achieved with the allocation pattern 10101010... *)
+  (* i.e. 2**19 singleton blocks. *)
+
+  (* As a bitmap we would have 2**19 / 2**3 = 2**16 bytes (64kbit) *)
+  let worst_case = make (fun x -> x mod 2 = 1) 0 (1024*1024/2/12) in
+  let hex (a, b) = Printf.sprintf "%x,%x" a b in
+  let to_string xs = "[" ^ (String.concat ";" (Listext.List.map_tr hex xs)) ^ 
"]" in
+
+
+  Printf.printf "generated\n";
+       let x = to_list worst_case in
+Printf.printf "got a list\n";
+         let y = Listext.List.map_tr hex x in
+Printf.printf "got lots of strings\n";
+  let s = to_string (to_list worst_case) in
+  Printf.printf "Extent size=%d\n" (String.length s);
+       let string_of_run = function
+         | Empty x -> Printf.sprintf "-%d" x
+         | Full x -> Printf.sprintf "+%d" x in
+       let s' = String.concat ";" (Listext.List.map_tr string_of_run 
(to_run_list x)) in
+         Printf.printf "Runs size=%d\n" (String.length s')
diff -r ad151dc6eb45 -r 542efa53c3e2 stdext/lazyList.ml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/stdext/lazyList.ml        Wed Jul 21 23:29:15 2010 +0100
@@ -0,0 +1,20 @@
+(* A lazy-list implementation *)
+
+type 'a elt =
+       | Empty
+       | Cons of 'a * 'a t
+and 'a t = 'a elt lazy_t
+
+let rec map f xs = lazy(match Lazy.force xs with
+       | Empty -> Empty
+       | Cons(x, xs) -> Cons(f x, map f xs))
+       
+let rec take n xs = lazy(match n, Lazy.force xs with
+       | 0, _ -> Empty
+       | n, Empty -> raise Not_found
+       | n, Cons(x, xs) -> Cons(x, take (n - 1) xs)) 
+       
+let rec iter f xs = match Lazy.force xs with
+       | Empty -> ()
+       | Cons(x, xs) -> f x; iter f xs
+
diff -r ad151dc6eb45 -r 542efa53c3e2 stdext/lazyList.mli
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/stdext/lazyList.mli       Wed Jul 21 23:29:15 2010 +0100
@@ -0,0 +1,16 @@
+(** A lazy-list *)
+
+(** A forced lazy list element *)
+type 'a elt = Empty | Cons of 'a * 'a t
+
+(** A lazy list *)
+and 'a t = 'a elt lazy_t
+
+(** [map f xs] returns the list [f 1; f 2; ...; f n] *)
+val map : ('a -> 'b) -> 'a t -> 'b t
+
+(** [take n xs] returns the list truncated to the first [n] elements *)
+val take : int -> 'a t -> 'a t
+
+(** [iter f xs] applies every list element to [f] *)
+val iter : ('a -> 'b) -> 'a t -> unit
diff -r ad151dc6eb45 -r 542efa53c3e2 stdext/set_test.ml
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/stdext/set_test.ml        Wed Jul 21 23:29:15 2010 +0100
@@ -0,0 +1,31 @@
+module type Set = sig
+  type t
+  val (+): t -> t -> t (* union *)
+  val (^): t -> t -> t (* intersection *)
+  val (-): t -> t -> t (* difference *)
+  val not: t -> t      (* complement *)
+  val (=): t -> t -> bool
+
+  val to_string: t -> string
+end
+
+module SetEqualities(S: Set) = struct
+  open S
+
+  let w txt f a b c = 
+       if Pervasives.not(f a b c)
+       then failwith (Printf.sprintf "%s a=%s b=%s c=%s" txt (S.to_string a) 
(S.to_string b) (S.to_string c))
+         
+  let all = [
+       w "commutative_1" (fun a b _ -> a + b = b + a);
+       w "commutative_2" (fun a b _ -> a ^ b = b ^ a);
+       w "associative_1" (fun a b c -> (a + b) + c = a + (b + c));
+       w "associative_2" (fun a b c -> (a ^ b) ^ c = a ^ (b ^ c));
+       w "distributive_1" (fun a b c -> a + (b ^ c) = (a + b) ^ (a + c));
+       w "distributive_2" (fun a b c -> a ^ (b + c) = (a ^ b) + (a ^ c));
+       w "complement_1" (fun a _ _ -> not (not a) = a);
+       w "demorgan_1" (fun a b _ -> not (a + b) = (not a) ^ (not b));
+       w "demorgan_2" (fun a b _ -> not (a ^ b) = (not a) + (not b));
+  ]
+end
+
diff -r ad151dc6eb45 -r 542efa53c3e2 stdext/set_test.mli
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/stdext/set_test.mli       Wed Jul 21 23:29:15 2010 +0100
@@ -0,0 +1,15 @@
+module type Set =
+  sig
+    type t
+    val ( + ) : t -> t -> t
+    val ( ^ ) : t -> t -> t
+    val ( - ) : t -> t -> t
+    val not : t -> t
+    val ( = ) : t -> t -> bool
+    val to_string : t -> string
+  end
+module SetEqualities :
+  functor (S : Set) ->
+    sig
+      val all : (S.t -> S.t -> S.t -> unit) list
+    end
diff -r ad151dc6eb45 -r 542efa53c3e2 xapi-libs.spec
--- a/xapi-libs.spec    Mon Jul 12 08:33:28 2010 +0100
+++ b/xapi-libs.spec    Wed Jul 21 23:29:15 2010 +0100
@@ -69,7 +69,7 @@
    /opt/xensource/libexec/pciutil
    /opt/xensource/libexec/sexprpp
    /opt/xensource/libexec/xmlpp
-
+   /opt/xensource/libexec/extentlistset_test
 
 %files devel
 %defattr(-,root,root,-)
@@ -180,6 +180,9 @@
    /usr/lib/ocaml/stdext/dllstdext_stubs.so
    /usr/lib/ocaml/stdext/encodings.cmi
    /usr/lib/ocaml/stdext/encodings.cmx
+   /usr/lib/ocaml/stdext/extentlistSet.cmi
+   /usr/lib/ocaml/stdext/extentlistSet.cmx
+   /usr/lib/ocaml/stdext/extentlistset_test.cmx
    /usr/lib/ocaml/stdext/fe.cmi
    /usr/lib/ocaml/stdext/fe.cmx
    /usr/lib/ocaml/stdext/fecomms.cmi
@@ -197,6 +200,8 @@
    /usr/lib/ocaml/stdext/hashtblext.cmi
    /usr/lib/ocaml/stdext/hashtblext.cmx
    /usr/lib/ocaml/stdext/libstdext_stubs.a
+   /usr/lib/ocaml/stdext/lazyList.cmi
+   /usr/lib/ocaml/stdext/lazyList.cmx
    /usr/lib/ocaml/stdext/listext.cmi
    /usr/lib/ocaml/stdext/listext.cmx
    /usr/lib/ocaml/stdext/mapext.cmi
@@ -211,6 +216,8 @@
    /usr/lib/ocaml/stdext/range.cmx
    /usr/lib/ocaml/stdext/ring.cmi
    /usr/lib/ocaml/stdext/ring.cmx
+   /usr/lib/ocaml/stdext/set_test.cmi
+   /usr/lib/ocaml/stdext/set_test.cmx
    /usr/lib/ocaml/stdext/sha1sum.cmi
    /usr/lib/ocaml/stdext/sha1sum.cmx
    /usr/lib/ocaml/stdext/stdext.a
 stdext/Makefile              |    8 ++-
 stdext/extentlistSet.ml      |  106 +++++++++++++++++++++++++++++++++++++++++++
 stdext/extentlistSet.mli     |   27 ++++++++++
 stdext/extentlistset_test.ml |   92 +++++++++++++++++++++++++++++++++++++
 stdext/lazyList.ml           |   20 ++++++++
 stdext/lazyList.mli          |   16 ++++++
 stdext/set_test.ml           |   31 ++++++++++++
 stdext/set_test.mli          |   15 ++++++
 xapi-libs.spec               |    9 +++-
 9 files changed, 321 insertions(+), 3 deletions(-)


Attachment: xen-api-libs.hg.patch
Description: Text Data

_______________________________________________
xen-api mailing list
xen-api@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/mailman/listinfo/xen-api

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.