Skip to content

Commit

Permalink
CA-61929: Don't return from DR_task.create until SR is ready.
Browse files Browse the repository at this point in the history
When creating a DR_task, don't return until the asynchronous actions
dealing with metadata VDIs have completed. This means that
VDI.metadata_latest will be up to date for foreign database VDIs when
DR_task.create returns.
  • Loading branch information
johnelse committed Aug 9, 2011
1 parent 763d1f8 commit 69ad9d1
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 6 deletions.
14 changes: 10 additions & 4 deletions ocaml/xapi/message_forwarding.ml
Expand Up @@ -3325,11 +3325,14 @@ end
the internal scan function directly. the internal scan function directly.
*) *)
Server_helpers.exec_with_new_task "PBD.plug initial SR scan" (fun __scan_context -> Server_helpers.exec_with_new_task "PBD.plug initial SR scan" (fun __scan_context ->
let handle_metadata_vdis () = (* Only handle metadata VDIs when attaching shared storage to the master. *)
(* Only handle metadata VDIs when attaching shared storage to the master. *) let should_handle_metadata_vdis =
let pbd_host = Db.PBD.get_host ~__context:__scan_context ~self in let pbd_host = Db.PBD.get_host ~__context:__scan_context ~self in
let master = Db.Pool.get_master ~__context:__scan_context ~self:(Helpers.get_pool ~__context:__scan_context) in let master = Db.Pool.get_master ~__context:__scan_context ~self:(Helpers.get_pool ~__context:__scan_context) in
if (pbd_host = master) && (Db.SR.get_shared ~__context:__scan_context ~self:sr) then begin (pbd_host = master) && (Db.SR.get_shared ~__context:__scan_context ~self:sr)
in
let handle_metadata_vdis () =
if should_handle_metadata_vdis then begin
debug "Shared SR %s is being plugged to master - handling metadata VDIs." (sr_uuid ~__context sr); debug "Shared SR %s is being plugged to master - handling metadata VDIs." (sr_uuid ~__context sr);
let metadata_vdis = List.filter let metadata_vdis = List.filter
(fun vdi -> Db.VDI.get_type ~__context:__scan_context ~self:vdi = `metadata) (fun vdi -> Db.VDI.get_type ~__context:__scan_context ~self:vdi = `metadata)
Expand All @@ -3354,10 +3357,13 @@ end
with e -> with e ->
debug "Could not re-enable database replication to VDI %s - caught %s" debug "Could not re-enable database replication to VDI %s - caught %s"
vdi_uuid (Printexc.to_string e) vdi_uuid (Printexc.to_string e)
end end;
Xapi_dr.signal_sr_is_ready ~__context:__scan_context ~sr
end else end else
debug "SR %s is not shared or is being plugged to a slave - not handling metadata VDIs at this point." (sr_uuid ~__context sr) debug "SR %s is not shared or is being plugged to a slave - not handling metadata VDIs at this point." (sr_uuid ~__context sr)
in in
if should_handle_metadata_vdis then
Xapi_dr.signal_sr_is_processing ~__context:__scan_context ~sr;
Xapi_sr.scan_one ~__context:__scan_context ~callback:handle_metadata_vdis sr) Xapi_sr.scan_one ~__context:__scan_context ~callback:handle_metadata_vdis sr)


let unplug ~__context ~self = let unplug ~__context ~self =
Expand Down
38 changes: 38 additions & 0 deletions ocaml/xapi/xapi_dr.ml
Expand Up @@ -5,6 +5,8 @@ open Threadext
module D = Debug.Debugger(struct let name="xapi" end) module D = Debug.Debugger(struct let name="xapi" end)
open D open D


(* -------------------------- VDI caching ----------------------------------- *)

(* Keep track of foreign metadata VDIs and their database generations and pool UUIDs. *) (* Keep track of foreign metadata VDIs and their database generations and pool UUIDs. *)
(* The generation count is used to keep track of metadata_latest of all foreign database VDIs. *) (* The generation count is used to keep track of metadata_latest of all foreign database VDIs. *)
(* The pool uuid is cached so that "xe pool-param-get param-name=metadata-of-pool" can be called without opening the database. *) (* The pool uuid is cached so that "xe pool-param-get param-name=metadata-of-pool" can be called without opening the database. *)
Expand Down Expand Up @@ -113,6 +115,42 @@ let read_vdi_cache_record ~vdi =
else else
None) None)


(* ------------ Providing signalling that an SR is ready for DR ------------- *)

let processing_srs : API.ref_SR list ref = ref []
let processing_srs_m = Mutex.create ()
let processing_srs_c = Condition.create ()

let signal_sr_is_processing ~__context ~sr =
debug "Recording that processing of SR %s has started." (Db.SR.get_uuid ~__context ~self:sr);
Mutex.execute processing_srs_m
(fun () ->
let srs = !processing_srs in
if not(List.mem sr srs) then
processing_srs := sr::srs)

let signal_sr_is_ready ~__context ~sr =
debug "Recording that processing of SR %s has finished." (Db.SR.get_uuid ~__context ~self:sr);
Mutex.execute processing_srs_m
(fun () ->
let srs = !processing_srs in
if List.mem sr srs then begin
processing_srs := (List.filter (fun x -> x <> sr) srs);
Condition.broadcast processing_srs_c
end)

let wait_until_sr_is_ready ~__context ~sr =
let sr_uuid = Db.SR.get_uuid ~__context ~self:sr in
Mutex.execute processing_srs_m
(fun () ->
debug "Waiting for SR %s to be processed." sr_uuid;
while List.mem sr !processing_srs do
Condition.wait processing_srs_c processing_srs_m
done;
debug "Finished waiting for SR %s to be processed." sr_uuid)

(* --------------------------------- VM recovery ---------------------------- *)

(* This function uses the VM export functionality to *) (* This function uses the VM export functionality to *)
(* create the objects required to reimport a list of VMs *) (* create the objects required to reimport a list of VMs *)
let create_import_objects ~__context ~vms = let create_import_objects ~__context ~vms =
Expand Down
4 changes: 2 additions & 2 deletions ocaml/xapi/xapi_dr_task.ml
Expand Up @@ -78,8 +78,8 @@ let try_create_sr_from_record ~__context ~_type ~device_config ~dr_task ~sr_reco
debug "Attaching SR %s to host %s" sr_record.uuid (Db.Host.get_name_label ~__context ~self:host); debug "Attaching SR %s to host %s" sr_record.uuid (Db.Host.get_name_label ~__context ~self:host);
let pbd = Client.PBD.create ~rpc ~session_id ~host ~sR:sr ~device_config ~other_config:[] in let pbd = Client.PBD.create ~rpc ~session_id ~host ~sR:sr ~device_config ~other_config:[] in
Client.PBD.plug ~rpc ~session_id ~self:pbd) hosts; Client.PBD.plug ~rpc ~session_id ~self:pbd) hosts;
(* Ensure the VDI records are in the database. *) (* Wait until the asynchronous scan is complete and metadata_latest has been updated for all metadata VDIs. *)
Client.SR.scan ~rpc ~session_id ~sr; Xapi_dr.wait_until_sr_is_ready ~__context ~sr;
Db.SR.set_introduced_by ~__context ~self:sr ~value:dr_task Db.SR.set_introduced_by ~__context ~self:sr ~value:dr_task
with e -> with e ->
(* Clean up if anything goes wrong. *) (* Clean up if anything goes wrong. *)
Expand Down

0 comments on commit 69ad9d1

Please sign in to comment.