Skip to content

Commit 94ab77b

Browse files
committed
Move code from Xapi_sr to Xapi_vdi_helpers.
It's necessary to be able to start and stop metadata replication on a per-VDI rather than a per-SR basis - these changes will make that easier. Signed-off-by: John Else <[email protected]>
1 parent 4a6729c commit 94ab77b

File tree

2 files changed

+91
-64
lines changed

2 files changed

+91
-64
lines changed

ocaml/xapi/xapi_sr.ml

Lines changed: 12 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -432,10 +432,6 @@ let assert_can_host_ha_statefile ~__context ~sr =
432432
Xha_statefile.assert_sr_can_host_statefile ~__context ~sr
433433

434434
(* Metadata replication to SRs *)
435-
let redo_log_lifecycle_mutex = Mutex.create ()
436-
let metadata_replication : ((API.ref_SR, (API.ref_VBD * Redo_log.redo_log)) Hashtbl.t) =
437-
Hashtbl.create Xapi_globs.redo_log_max_instances
438-
439435
let find_or_create_metadata_vdi ~__context ~sr =
440436
let pool = Helpers.get_pool ~__context in
441437
let vdi_can_be_used vdi =
@@ -468,71 +464,23 @@ let get_master_dom0 ~__context =
468464
let vms = Db.Host.get_resident_VMs ~__context ~self:master in
469465
List.hd (List.filter (fun vm -> Db.VM.get_is_control_domain ~__context ~self:vm) vms)
470466

471-
let provision_metadata_vdi_and_start_redo_log ~__context ~sr =
472-
let vdi = find_or_create_metadata_vdi ~__context ~sr in
473-
let log = Redo_log.create () in
474-
let sr_uuid = Db.SR.get_uuid ~__context ~self:sr in
475-
let dom0 = get_master_dom0 ~__context in
476-
(* Create and plug vbd *)
477-
let vbd = Helpers.call_api_functions ~__context (fun rpc session_id ->
478-
let vbd = Client.VBD.create ~rpc ~session_id ~vM:dom0 ~empty:false ~vDI:vdi
479-
~userdevice:"autodetect" ~bootable:false ~mode:`RW ~_type:`Disk
480-
~unpluggable:true ~qos_algorithm_type:"" ~qos_algorithm_params:[]
481-
~other_config:[]
482-
in
483-
Client.VBD.plug ~rpc ~session_id ~self:vbd;
484-
vbd)
485-
in
486-
(* Enable redo_log and point it at the new device *)
487-
let device = Db.VBD.get_device ~__context ~self:vbd in
488-
try
489-
Redo_log.enable_block log ("/dev/" ^ device);
490-
Redo_log.startup log;
491-
Hashtbl.add metadata_replication sr (vbd, log);
492-
debug "Redo log started on SR %s" sr_uuid
493-
with e ->
494-
Helpers.call_api_functions ~__context (fun rpc session_id ->
495-
Client.VBD.unplug ~rpc ~session_id ~self:vbd);
496-
raise (Api_errors.Server_error(Api_errors.cannot_enable_redo_log,
497-
[Printexc.to_string e]))
498-
499467
let enable_database_replication ~__context ~sr =
500468
if (not (Pool_features.is_enabled ~__context Features.DR)) then
501469
raise (Api_errors.Server_error(Api_errors.license_restriction, []));
502-
Mutex.execute redo_log_lifecycle_mutex (fun () ->
503-
debug "Attempting to enable metadata replication on SR [%s:%s]"
504-
(Db.SR.get_name_label ~__context ~self:sr) (Db.SR.get_uuid ~__context ~self:sr);
505-
if Hashtbl.mem metadata_replication sr then
506-
debug "Metadata is already being replicated to this SR."
507-
else begin
508-
(* Check that the number of metadata redo_logs isn't already at the limit. *)
509-
(* There should never actually be more redo_logs than the limit! *)
510-
if Hashtbl.length metadata_replication >= Xapi_globs.redo_log_max_instances then
511-
raise (Api_errors.Server_error(Api_errors.no_more_redo_logs_allowed, []))
512-
else
513-
provision_metadata_vdi_and_start_redo_log ~__context ~sr
514-
end
515-
)
470+
let metadata_vdi = find_or_create_metadata_vdi ~__context ~sr in
471+
Xapi_vdi_helpers.enable_database_replication ~__context ~vdi:metadata_vdi
516472

473+
(* Disable metadata replication to all metadata VDIs in this SR. *)
517474
let disable_database_replication ~__context ~sr =
518-
Mutex.execute redo_log_lifecycle_mutex (fun () ->
519-
debug "Attempting to disable metadata replication on SR [%s:%s]."
520-
(Db.SR.get_name_label ~__context ~self:sr) (Db.SR.get_uuid ~__context ~self:sr);
521-
if not(Hashtbl.mem metadata_replication sr) then
522-
debug "Metadata is not being replicated to this SR."
523-
else begin
524-
let (vbd, log) = Hashtbl.find metadata_replication sr in
525-
Redo_log.shutdown log;
526-
Redo_log.disable log;
527-
Helpers.call_api_functions ~__context (fun rpc session_id ->
528-
Client.VBD.unplug ~rpc ~session_id ~self:vbd);
529-
Hashtbl.remove metadata_replication sr;
530-
Redo_log.delete log;
531-
let vdi = Db.VBD.get_VDI ~__context ~self:vbd in
532-
Helpers.call_api_functions ~__context (fun rpc session_id ->
533-
Client.VDI.destroy ~rpc ~session_id ~self:vdi)
534-
end
535-
)
475+
let metadata_vdis = List.filter
476+
(fun vdi ->
477+
Db.VDI.get_type ~__context ~self:vdi = `metadata &&
478+
(Db.VDI.get_metadata_of_pool ~__context ~self:vdi = Helpers.get_pool ~__context))
479+
(Db.SR.get_VDIs ~__context ~self:sr)
480+
in
481+
List.iter
482+
(fun vdi -> Xapi_vdi_helpers.disable_database_replication ~__context ~vdi)
483+
metadata_vdis
536484

537485
let create_new_blob ~__context ~sr ~name ~mime_type =
538486
let blob = Xapi_blob.create ~__context ~mime_type in

ocaml/xapi/xapi_vdi_helpers.ml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515
* @group Storage
1616
*)
1717

18+
open Client
19+
open Pervasiveext
20+
open Threadext
21+
22+
module D=Debug.Debugger(struct let name="xapi" end)
23+
open D
24+
1825
(* We only support .iso files (from an iso SR) and block devices from
1926
a local magic SR (eg /dev/hda) but NOT phantom_vbd block attach isos *)
2027
let assert_vdi_is_valid_iso ~__context ~vdi =
@@ -28,3 +35,75 @@ let assert_managed ~__context ~vdi =
2835
if not (Db.VDI.get_managed ~__context ~self:vdi)
2936
then raise (Api_errors.Server_error(Api_errors.vdi_not_managed, [ Ref.string_of vdi ]))
3037

38+
(* Database replication to metadata VDIs. *)
39+
let redo_log_lifecycle_mutex = Mutex.create ()
40+
41+
let metadata_replication : ((API.ref_VDI, (API.ref_VBD * Redo_log.redo_log)) Hashtbl.t) =
42+
Hashtbl.create Xapi_globs.redo_log_max_instances
43+
44+
let get_master_dom0 ~__context =
45+
let pool = Helpers.get_pool ~__context in
46+
let master = Db.Pool.get_master ~__context ~self:pool in
47+
let vms = Db.Host.get_resident_VMs ~__context ~self:master in
48+
List.hd (List.filter (fun vm -> Db.VM.get_is_control_domain ~__context ~self:vm) vms)
49+
50+
(* Create and plug a VBD from the VDI, then create a redo log and point it at the block device. *)
51+
let enable_database_replication ~__context ~vdi =
52+
Mutex.execute redo_log_lifecycle_mutex (fun () ->
53+
let name_label = Db.VDI.get_name_label ~__context ~self:vdi in
54+
let uuid = Db.VDI.get_uuid ~__context ~self:vdi in
55+
debug "Attempting to disable metadata replication on VDI [%s:%s]." name_label uuid;
56+
if Hashtbl.mem metadata_replication vdi then
57+
debug "Metadata is already being replicated to VDI [%s:%s]." name_label uuid
58+
else begin
59+
(* Check that the number of metadata redo_logs isn't already at the limit. *)
60+
(* There should never actually be more redo_logs than the limit! *)
61+
if Hashtbl.length metadata_replication >= Xapi_globs.redo_log_max_instances then
62+
raise (Api_errors.Server_error(Api_errors.no_more_redo_logs_allowed, []));
63+
let log = Redo_log.create () in
64+
let dom0 = get_master_dom0 ~__context in
65+
(* Create and plug vbd *)
66+
let vbd = Helpers.call_api_functions ~__context (fun rpc session_id ->
67+
let vbd = Client.VBD.create ~rpc ~session_id ~vM:dom0 ~empty:false ~vDI:vdi
68+
~userdevice:"autodetect" ~bootable:false ~mode:`RW ~_type:`Disk
69+
~unpluggable:true ~qos_algorithm_type:"" ~qos_algorithm_params:[]
70+
~other_config:[]
71+
in
72+
Client.VBD.plug ~rpc ~session_id ~self:vbd;
73+
vbd)
74+
in
75+
(* Enable redo_log and point it at the new device *)
76+
let device = Db.VBD.get_device ~__context ~self:vbd in
77+
try
78+
Redo_log.enable_block log ("/dev/" ^ device);
79+
Redo_log.startup log;
80+
Hashtbl.add metadata_replication vdi (vbd, log);
81+
let vbd_uuid = Db.VBD.get_uuid ~__context ~self:vbd in
82+
debug "Redo log started on VBD %s" vbd_uuid
83+
with e ->
84+
Helpers.call_api_functions ~__context (fun rpc session_id ->
85+
Client.VBD.unplug ~rpc ~session_id ~self:vbd);
86+
raise (Api_errors.Server_error(Api_errors.cannot_enable_redo_log,
87+
[Printexc.to_string e]))
88+
end
89+
)
90+
91+
(* Shut down the redo log, then unplug and destroy the VBD. *)
92+
let disable_database_replication ~__context ~vdi =
93+
Mutex.execute redo_log_lifecycle_mutex (fun () ->
94+
debug "Attempting to disable metadata replication on VDI [%s:%s]."
95+
(Db.VDI.get_name_label ~__context ~self:vdi) (Db.VDI.get_uuid ~__context ~self:vdi);
96+
if not(Hashtbl.mem metadata_replication vdi) then
97+
debug "Metadata is not being replicated to this VDI."
98+
else begin
99+
let (vbd, log) = Hashtbl.find metadata_replication vdi in
100+
Redo_log.shutdown log;
101+
Redo_log.disable log;
102+
Helpers.call_api_functions ~__context (fun rpc session_id ->
103+
Client.VBD.unplug ~rpc ~session_id ~self:vbd;
104+
Client.VBD.destroy ~rpc ~session_id ~self:vbd);
105+
Hashtbl.remove metadata_replication vdi;
106+
Redo_log.delete log;
107+
Db.VDI.set_metadata_latest ~__context ~self:vdi ~value:false
108+
end
109+
)

0 commit comments

Comments
 (0)