Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

132 lines (120 sloc) 7.918 kb
* Copyright (C) 2006-2009 Citrix Systems Inc.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* GNU Lesser General Public License for more details.
open Pervasiveext
module D=Debug.Debugger(struct let name="dbsync" end)
open D
let safe_wrapper n f x =
f x
with e ->
debug "Caught exception while cancelling tasks (%s): %s" n (ExnHelper.string_of_exn e);
log_backtrace ()
let update_all_allowed_operations ~__context =
let open Stats in
let all_vms = Db.VM.get_all ~__context
and all_vbds = Db.VBD.get_all ~__context
and all_vifs = Db.VIF.get_all ~__context
and all_vdis = Db.VDI.get_all ~__context
and all_srs = Db.SR.get_all ~__context
and all_pbds = Db.PBD.get_all ~__context
and all_hosts = Db.Host.get_all ~__context in
time_this "Cancel_tasks.update_all_allowed_operations: VM" (fun () ->
debug "Updating allowed operations: VM";
List.iter (safe_wrapper "allowed_ops - VMs" (fun self -> Xapi_vm_lifecycle.update_allowed_operations ~__context ~self)) all_vms;
debug "Finished updating allowed operations: VM");
time_this "Cancel_tasks.update_all_allowed_operations: VBD" (fun () ->
debug "Updating allowed operations: VBD";
List.iter (safe_wrapper "allowed_ops - VBDs" (fun self -> Xapi_vbd_helpers.update_allowed_operations ~__context ~self)) all_vbds;
debug "Finished updating allowed operations: VBD");
time_this "Cancel_tasks.update_all_allowed_operations: VIF" (fun () ->
debug "Updating allowed operations: VIF";
List.iter (safe_wrapper "allowed_ops - VIFs" (fun self -> Xapi_vif_helpers.update_allowed_operations ~__context ~self)) all_vifs;
debug "Finished updating allowed operations: VIF");
time_this "Cancel_tasks.update_all_allowed_operations: VDI" (fun () ->
debug "Updating allowed operations: VDI";
let sr_records = (fun sr -> (sr, Db.SR.get_record_internal ~__context ~self:sr)) all_srs in
let pbd_records = (fun pbd -> (pbd, Db.PBD.get_record ~__context ~self:pbd)) all_pbds in
let vbd_records = (fun vbd -> (vbd, Db.VBD.get_record_internal ~__context ~self:vbd)) all_vbds in
List.iter (safe_wrapper "allowed_ops - VDIs"
(fun self -> Xapi_vdi.update_allowed_operations_internal ~__context ~self ~sr_records ~pbd_records ~vbd_records)) all_vdis;
debug "Finished updating allowed operations: VDI");
time_this "Cancel_tasks.update_all_allowed_operations: SR" (fun () ->
debug "Updating allowed operations: SR";
List.iter (safe_wrapper "allowed_ops" (fun self ->
Db.SR.set_current_operations ~__context ~self ~value:[];
Xapi_sr.update_allowed_operations ~__context ~self)) all_srs;
debug "Finished updating allowed operations: SR";
debug "Updating allowed operations: host";
List.iter (safe_wrapper "allowed_ops - host" (fun self -> Xapi_host_helpers.update_allowed_operations ~__context ~self)) all_hosts;
debug "Finished updating allowed operations: host")
(* !!! This code was written in a world when tasks, current_operations and allowed_operations were persistent.
This is no longer the case (we changed this to reduce writes to flash for OEM case + to simplify xapi logic elsewhere).
The case where the slave calls the master to cancel its tasks is still useful; however, when the master restarts
then all the current-operations,allowed-operations and tasks for the whole pool will have been lost. We rely on the
resyncing code + persistent fields such as "currently-attached" etc. to provide enough lock-state across xapi restart
to ensure safe storage access. However, long-running xapi managed tasks are going to float off into the ether over a
master restart... *)
(* When the master restarts, it updates all allowed_operations. The first time a slave says Pool.hello, it is not
necessary to update the allowed_operations again. The next time the slave says hello (eg after a slave but not master restart)
we do need to update the allowed_operations. This optimises the cold-boot/master-failover case. *)
let hosts_already_cancelled = ref []
let master_finished_initial_cancel = ref false
let cancelled_c = Condition.create ()
let cancelled_m = Mutex.create ()
(** Mark tasks that are pending or cancelling on this host as cancelled *)
(** This function is called by master on behalf of slave, when slave sends a "Pool.hello" msg on reconnect *)
let cancel_tasks_on_host ~__context ~host_opt =
Threadext.Mutex.execute cancelled_m
(fun () ->
(* Block Pool.hello on behalf of slaves until the master has finished the initial resync *)
if host_opt = None (* initial sync, not Pool.hello *)
then (master_finished_initial_cancel := true; Condition.broadcast cancelled_c)
else (while not !master_finished_initial_cancel do Condition.wait cancelled_c cancelled_m done);
let tasks = Db.Task.get_all ~__context in
let this_host_tasks, should_update_all_allowed_operations =
match host_opt with
None ->
debug "cancel_tasks_on_host: master will cancel all tasks";
tasks, true
| (Some host) ->
debug "cancel_tasks_on_host: host = %s" (Ref.string_of host);
let should_cancel =
if List.mem host !hosts_already_cancelled then true else begin
hosts_already_cancelled := host :: !hosts_already_cancelled;
end in
List.filter (fun t -> Db.Task.get_resident_on ~__context ~self:t = host) tasks, should_cancel in
let incomplete_tasks = List.filter (fun t -> let s = Db.Task.get_status ~__context ~self:t in s=`pending || s=`cancelling) this_host_tasks in
(* Need to remove any current_operations associated with these tasks *)
let all_vms = Db.VM.get_all ~__context
and all_vbds = Db.VBD.get_all ~__context
and all_vifs = Db.VIF.get_all ~__context
and all_vdis = Db.VDI.get_all ~__context
and all_srs = Db.SR.get_all ~__context
and all_hosts = Db.Host.get_all ~__context
let task_ids = Ref.string_of incomplete_tasks in
List.iter (safe_wrapper "vm_lifecycle" (fun self -> Xapi_vm_lifecycle.cancel_tasks ~__context ~self ~all_tasks_in_db:tasks ~task_ids)) all_vms;
List.iter (safe_wrapper "vbd_helpers" (fun self -> Xapi_vbd_helpers.cancel_tasks ~__context ~self ~all_tasks_in_db:tasks ~task_ids)) all_vbds;
List.iter (safe_wrapper "vif_helpers" (fun self -> Xapi_vif_helpers.cancel_tasks ~__context ~self ~all_tasks_in_db:tasks ~task_ids)) all_vifs;
List.iter (safe_wrapper "vdis" (fun self -> Xapi_vdi.cancel_tasks ~__context ~self ~all_tasks_in_db:tasks ~task_ids)) all_vdis;
List.iter (safe_wrapper "sr" (fun self -> Xapi_sr.cancel_tasks ~__context ~self ~all_tasks_in_db:tasks ~task_ids)) all_srs;
List.iter (safe_wrapper "host" (fun self -> Xapi_host_helpers.cancel_tasks ~__context ~self ~all_tasks_in_db:tasks ~task_ids)) all_hosts;
let hosts = default (Db.Host.get_all ~__context) (may (fun x -> [x]) host_opt) in
List.iter (safe_wrapper "host_helpers - cancel tasks" (fun self -> Xapi_host_helpers.cancel_tasks ~__context ~self ~all_tasks_in_db:tasks ~task_ids)) hosts;
List.iter (safe_wrapper "host_helpers - allowed ops" (fun self -> Xapi_host_helpers.update_allowed_operations ~__context ~self)) hosts;
List.iter (safe_wrapper "destroy_tasks" (fun task -> TaskHelper.destroy ~__context task)) incomplete_tasks;
if should_update_all_allowed_operations
then update_all_allowed_operations ~__context
Jump to Line
Something went wrong with that request. Please try again.