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

[Xen-API] [PATCH 2 of 2] CA-43021: hook in 'sparse_dd' for improved VM.copy performance



# HG changeset patch
# User David Scott <dave.scott@xxxxxxxxxxxxx>
# Date 1279905520 -3600
# Node ID 3bf70773971b9906e4d7355049b2cf7a88a13b23
# Parent  2580868fdc435e5c729f98bd707d018dafd3dc2a
CA-43021: hook in 'sparse_dd' for improved VM.copy performance

On local LVHD, VM.copies of freshly installed guests are much quicker:

Guest          Previous VM.copy time    New VM.copy time   Speedup
----------------------------------------------------------------
Debian Lenny   2:11                     1:18               40%
Windows 7      14:18                    7:57               44%

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

diff -r 2580868fdc43 -r 3bf70773971b ocaml/xapi/sm_fs_ops.ml
--- a/ocaml/xapi/sm_fs_ops.ml   Fri Jul 23 18:18:39 2010 +0100
+++ b/ocaml/xapi/sm_fs_ops.ml   Fri Jul 23 18:18:40 2010 +0100
@@ -138,59 +138,48 @@
              raise e
          )
          
-exception Cancelled
-exception NonZero
-
-(* dd with sparseness check *)
-let sparse_dd refresh_session ~__context sparse ifd ofd size bs =
-  let round v = int_of_float (v *. 50.0) in
-  let update = 
-    let oldvalue = ref (-1.0) in
-    fun value ->  
-      if round value <> round !oldvalue then begin
-       TaskHelper.exn_if_cancelling ~__context;
-       TaskHelper.operate_on_db_task ~__context 
-         (fun self -> 
-           Db.Task.set_progress ~__context ~self ~value);
-      end;
-      oldvalue := value
-  in
-
-  let buf = String.create bs in
-  
-  let allzero s n =
-    try
-      for i=0 to n-1 do
-        if s.[i] <> '\000' then raise NonZero
-      done;
-      true
-    with NonZero -> false
-  in
-
-  let rec do_block offset =
-    refresh_session ();
-
-    update ((Int64.to_float offset) /. (Int64.to_float size));   
-    let remaining = Int64.sub size offset in
-    if remaining=0L 
-    then ()  (* EOF *)
-    else
-      begin
-       let this_chunk = Int64.to_int (min remaining (Int64.of_int bs)) in
-       Unixext.really_read ifd buf 0 this_chunk;
-       begin
-         if sparse && (allzero buf this_chunk)
-          then
-           ignore(Unix.LargeFile.lseek ofd (Int64.of_int this_chunk) 
Unix.SEEK_CUR)
-         else
-           let n = Unix.write ofd buf 0 this_chunk in
-           (if n<this_chunk then failwith "Error!")
-       end;
-       do_block (Int64.add offset (Int64.of_int this_chunk))
-      end
-  in
-  do_block 0L;
-  update 1.0
+(** Use the new external sparse_dd program *)
+let sparse_dd_new ~__context prezeroed infile outfile size = 
+       let pipe_read, pipe_write = Unix.pipe () in
+       let to_close = ref [ pipe_read; pipe_write ] in
+       let close x = if List.mem x !to_close then (Unix.close x; to_close := 
List.filter (fun y -> y <> x) !to_close) in
+       finally
+       (fun () ->
+               match Forkhelpers.with_logfile_fd "sparse_dd"
+                       (fun log_fd ->
+                               let pid = Forkhelpers.safe_close_and_exec None 
(Some pipe_write) (Some log_fd) [] 
+                               "/opt/xensource/libexec/sparse_dd"
+                               ([ "-machine"; "-src"; infile; "-dest"; 
outfile; "-size"; Int64.to_string size ] @
+                               (if prezeroed then [ "-prezeroed" ] else [])) in
+                               close pipe_write;
+                               (* Read Progress: output from the binary *)
+                               let buf = String.create 128 in
+                               let finished = ref false in
+                               while not (!finished) do
+                                       let n = Unix.read pipe_read buf 0 
(String.length buf) in
+                                       if n = 0 then finished := true else 
debug "sparse_dd: %s" (String.sub buf 0 n);
+                                       try 
+                                               Scanf.sscanf (String.sub buf 0 
n) "Progress: %d"
+                                               (fun progress ->
+                                                       
TaskHelper.exn_if_cancelling ~__context;
+                                                       
TaskHelper.operate_on_db_task ~__context 
+                                                       (fun self -> 
Db.Task.set_progress ~__context ~self ~value:(float_of_int progress /. 100.))
+                                               )
+                                       with _ -> ()
+                               done;
+                               match Forkhelpers.waitpid pid with
+                               | (_, Unix.WEXITED 0) -> ()
+                               | (_, Unix.WEXITED n) -> error "sparse_dd exit: 
%d" n; failwith "sparse_dd"
+                       ) with
+               | Forkhelpers.Success _ -> ()
+               | Forkhelpers.Failure (log, exn) ->
+                       error "Failure from sparse_dd: %s" log;
+                       raise exn       
+       )
+       (fun () ->
+               close pipe_read;
+               close pipe_write)
+       
 
 (* SCTX-286: thin provisioning is thrown away over VDI.copy, 
VM.import(VM.export).
    Return true if the newly created vdi must have zeroes written into it; 
default to false
@@ -226,38 +215,18 @@
 let copy_vdi ~__context vdi_src vdi_dst = 
   TaskHelper.set_cancellable ~__context;
   Helpers.call_api_functions ~__context (fun rpc session_id ->
-  let refresh_session = Xapi_session.consider_touching_session rpc session_id 
in
 
 
   (* Use the sparse copy unless we must write zeroes into the new VDI *)
   let sparse = not (must_write_zeroes_into_new_vdi ~__context vdi_dst) in
 
   let size = Db.VDI.get_virtual_size ~__context ~self:vdi_src in
-  let blocksize = 1024*1024 in
-
-  debug "Sm_fs_ops.copy_vdi: copying %Ld in blocks of %d%s preserving 
sparseness" size blocksize (if sparse then "" else " NOT");
-
-  let dd = sparse_dd refresh_session ~__context sparse in
 
   with_block_attached_device __context rpc session_id vdi_src `RO
     (fun device_src ->
        with_block_attached_device __context rpc session_id vdi_dst `RW
         (fun device_dst ->
-           let ifd=Unix.openfile device_src [Unix.O_RDONLY] 0o600 
-           and ofd=Unix.openfile device_dst [Unix.O_WRONLY; Unix.O_SYNC] 0o600 
in
-           finally
-             (fun () ->
-                try
-                  dd ifd ofd size blocksize;
-                with
-                  | Unix.Unix_error(Unix.EIO, _, _) ->
-                      raise (Api_errors.Server_error (Api_errors.vdi_io_error, 
["Device I/O error"]))
-                  | e ->
-                      debug "Caught exception %s" (ExnHelper.string_of_exn e);
-                      log_backtrace ())
-             (fun () ->
-                Unix.close ifd;
-                Unix.close ofd)
+           sparse_dd_new ~__context sparse device_src device_dst size; 
         )
     )
   )
 ocaml/xapi/sm_fs_ops.ml |  117 +++++++++++++++++------------------------------
 1 files changed, 43 insertions(+), 74 deletions(-)


Attachment: sm_fs_ops.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®.