Skip to content

Commit e588bc9

Browse files
committed
vhd_qcow_parsing: Parse the new interval-based data_clusters format
This requires switching stream_vdi to the new format, away from the memory-costly Map storing information on every single allocated cluster. Signed-off-by: Andrii Sultanov <andriy.sultanov@vates.tech>
1 parent aa42450 commit e588bc9

4 files changed

Lines changed: 43 additions & 29 deletions

File tree

ocaml/xapi/qcow_tool_wrapper.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ val send :
2424
-> int64
2525
-> unit
2626

27-
val parse_header : string -> int * int list
27+
val parse_header : string -> int * (int * int) list

ocaml/xapi/stream_vdi.ml

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -195,23 +195,6 @@ let get_chunk_numbers_in_increasing_order descriptor_list offset =
195195
let chunks = process [] offset descriptor_list in
196196
List.rev chunks
197197

198-
let get_allocated_chunks_from_clusters cluster_size cluster_list =
199-
let chunk_size = Int64.to_int chunk_size in
200-
let chunks_in_cluster = (cluster_size + chunk_size - 1) / chunk_size in
201-
let set =
202-
List.fold_left
203-
(fun set cluster_no ->
204-
let cluster_offset = cluster_no * cluster_size in
205-
let chunk_no = cluster_offset / chunk_size in
206-
let chunks_to_add =
207-
Seq.init chunks_in_cluster (fun i -> chunk_no + i)
208-
in
209-
ChunkSet.add_seq chunks_to_add set
210-
)
211-
ChunkSet.empty cluster_list
212-
in
213-
set
214-
215198
let send_one ofd (__context : Context.t) rpc session_id progress refresh_session
216199
(prefix, vdi_ref, _size) =
217200
let size = Db.VDI.get_virtual_size ~__context ~self:vdi_ref in
@@ -317,26 +300,47 @@ let send_one ofd (__context : Context.t) rpc session_id progress refresh_session
317300
| _ ->
318301
failwith (Printf.sprintf "%s: unreachable" __FUNCTION__)
319302
in
320-
let set =
321-
get_allocated_chunks_from_clusters cluster_size cluster_list
322-
in
323303
(* First and last chunks are always written - it's a limitation
324304
of the XVA format *)
325305
let last_chunk =
326306
Int64.((to_int size - to_int chunk_size + 1) / to_int chunk_size)
327307
in
328-
let set = set |> ChunkSet.add 0 |> ChunkSet.add last_chunk in
329-
ChunkSet.iter
330-
(fun this_chunk_no ->
331-
let offset = Int64.(mul (of_int this_chunk_no) chunk_size) in
308+
let process_chunk chunk_no ~force =
309+
if force || (chunk_no <> 0 && chunk_no <> last_chunk) then
310+
let offset = Int64.(mul (of_int chunk_no) chunk_size) in
332311
let _ =
333-
write_chunk this_chunk_no offset
312+
write_chunk chunk_no offset
334313
~write_check:(fun _ _ -> true)
335314
~seek:true ~timeout_workaround:false
336315
in
337316
()
317+
in
318+
319+
process_chunk 0 ~force:true ;
320+
321+
let chunk_size = Int64.to_int chunk_size in
322+
let chunks_in_cluster =
323+
(cluster_size + chunk_size - 1) / chunk_size
324+
in
325+
(* Iterate over allocated intervals, copying every cluster inside *)
326+
List.iter
327+
(fun (cluster_no_left, cluster_no_right) ->
328+
let calc_chunk cluster =
329+
let cluster_offset = cluster * cluster_size in
330+
let chunk_no = cluster_offset / chunk_size in
331+
chunk_no
332+
in
333+
let left_chunk_no = calc_chunk cluster_no_left in
334+
let right_chunk_no =
335+
calc_chunk cluster_no_right + chunks_in_cluster - 1
336+
in
337+
for i = left_chunk_no to right_chunk_no do
338+
process_chunk i ~force:false
339+
done
338340
)
339-
set
341+
cluster_list ;
342+
343+
process_chunk last_chunk ~force:true
340344
with e ->
341345
debug "%s: Falling back to reading the whole raw disk after %s"
342346
__FUNCTION__ (Printexc.to_string e) ;

ocaml/xapi/vhd_qcow_parsing.ml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ let parse_header pipe_reader =
5353
1 lsl Yojson.Basic.Util.(member "cluster_bits" json |> to_int)
5454
in
5555
let cluster_list =
56-
Yojson.Basic.Util.(member "data_clusters" json |> to_list |> List.map to_int)
56+
Yojson.Basic.Util.(
57+
member "data_clusters" json
58+
|> to_list
59+
|> List.map (fun x ->
60+
match to_list x with
61+
| x :: y :: _ ->
62+
(to_int x, to_int y)
63+
| _ ->
64+
raise (Invalid_argument "Invalid JSON")
65+
)
66+
)
5767
in
5868
(cluster_size, cluster_list)

ocaml/xapi/vhd_qcow_parsing.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ val run_tool :
2121
-> string list
2222
-> unit
2323

24-
val parse_header : Unix.file_descr -> int * int list
24+
val parse_header : Unix.file_descr -> int * (int * int) list

0 commit comments

Comments
 (0)