Skip to content

Commit 5097475

Browse files
author
Vincent Bernardoff
committed
CA-98944: Replaced potentially lots of db calls (one per VBD) by two big get_internal_where calls
Signed-off-by: Vincent Bernardoff <[email protected]>
1 parent df98fbe commit 5097475

File tree

5 files changed

+147
-16
lines changed

5 files changed

+147
-16
lines changed

ocaml/test/OMakefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ OCAML_OBJS = \
3131
test_pool_db_backup \
3232
test_xapi_db_upgrade \
3333
test_ca91480 \
34+
test_ca98944 \
3435
test_pr1510 \
3536
test_pool_license \
3637

ocaml/test/suite.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ let base_suite =
2121
Test_pool_db_backup.test;
2222
Test_xapi_db_upgrade.test;
2323
Test_ca91480.test;
24+
Test_ca98944.test;
2425
Test_pr1510.suite;
2526
Test_pool_license.test;
2627
]

ocaml/test/test_ca98944.ml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
(*
2+
* Copyright (C) 2006-2012 Citrix Systems Inc.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published
6+
* by the Free Software Foundation; version 2.1 only. with the special
7+
* exception on linking described in file LICENSE.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*)
14+
15+
open OUnit
16+
open Test_common
17+
18+
(* Helpers for testing Xapi_vdi.check_operation_error *)
19+
20+
let setup_test ~__context vbd_fun =
21+
let pbd_ref, sr_ref, vdi_ref = Ref.make (), Ref.make (), Ref.make () in
22+
let () = make_sr ~__context ~ref:sr_ref () in
23+
let () = make_pbd ~__context ~ref:pbd_ref ~sR:sr_ref () in
24+
let () = make_vdi ~__context ~ref:vdi_ref ~sR:sr_ref () in
25+
let vdi_record = Db.VDI.get_record_internal ~__context ~self:vdi_ref in
26+
vbd_fun vdi_ref;
27+
vdi_ref, vdi_record
28+
29+
let my_cmp a b = match a,b with
30+
| Some aa, Some bb -> fst aa = fst bb
31+
| None, None -> a = b
32+
| _ -> false
33+
34+
let run_assert_equal_with_vdi ~__context ?(cmp = my_cmp) ?(ha_enabled=false) vbd_list op exc =
35+
let vdi_ref, vdi_record = setup_test ~__context vbd_list in
36+
assert_equal ~cmp (Xapi_vdi.check_operation_error ~__context ha_enabled vdi_record vdi_ref op) exc
37+
38+
(* This is to test Xapi_vdi.check_operation_error against CA-98944
39+
code. This DO NOT fully test the aforementionned function *)
40+
let test_vdi () =
41+
let __context = Mock.make_context_with_new_db "Mock context" in
42+
(* Should raise vdi_in_use *)
43+
run_assert_equal_with_vdi ~__context
44+
(fun vdi_ref ->
45+
make_vbd ~vDI:vdi_ref ~__context
46+
~reserved:true ~currently_attached:false ~current_operations:["", `attach] ())
47+
`update (Some (Api_errors.vdi_in_use, []));
48+
49+
(* Should raise vdi_in_use *)
50+
run_assert_equal_with_vdi ~__context
51+
(fun vdi_ref ->
52+
make_vbd ~vDI:vdi_ref
53+
~__context ~reserved:false ~currently_attached:true ~current_operations:["", `attach] ())
54+
`update (Some (Api_errors.vdi_in_use, []));
55+
56+
(* Should raise vdi_in_use *)
57+
run_assert_equal_with_vdi ~__context
58+
(fun vdi_ref -> make_vbd ~vDI:vdi_ref
59+
~__context ~reserved:true ~currently_attached:true ~current_operations:["", `attach] ())
60+
`update (Some (Api_errors.vdi_in_use, []));
61+
62+
(* Should raise other_operation_in_progress *)
63+
run_assert_equal_with_vdi ~__context
64+
(fun vdi_ref -> make_vbd ~vDI:vdi_ref
65+
~__context ~reserved:false ~currently_attached:false ~current_operations:["", `attach] ())
66+
`update (Some (Api_errors.other_operation_in_progress, []));
67+
68+
(* Should pass *)
69+
run_assert_equal_with_vdi ~__context
70+
(fun vdi_ref -> make_vbd ~vDI:vdi_ref
71+
~__context ~reserved:false ~currently_attached:false ~current_operations:[] ())
72+
`forget None
73+
74+
let test =
75+
"test_ca98944" >:::
76+
[
77+
"test_vdi" >:: test_vdi
78+
]

ocaml/test/test_common.ml

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
open API
1616
open OUnit
1717

18+
(** Utility functions *)
1819
let skip str = skip_if true str
20+
let make_uuid () = Uuid.string_of_uuid (Uuid.make_uuid ())
1921

2022
(** Make a simple in-memory database containing a single host and dom0 VM record. *)
2123
let make_test_database () =
@@ -63,7 +65,7 @@ let make_vm ~__context ?(name_label="name_label") ?(name_description="descriptio
6365
~ha_always_run ~ha_restart_priority ~tags ~blocked_operations ~protection_policy
6466
~is_snapshot_from_vmpp ~appliance ~start_delay ~shutdown_delay ~order ~suspend_SR ~version
6567

66-
let make_host ~__context ?(uuid=Uuid.string_of_uuid (Uuid.make_uuid ())) ?(name_label="host")
68+
let make_host ~__context ?(uuid=make_uuid ()) ?(name_label="host")
6769
?(name_description="description") ?(hostname="localhost") ?(address="127.0.0.1")
6870
?(external_auth_type="") ?(external_auth_service_name="") ?(external_auth_configuration=[])
6971
?(license_params=[]) ?(edition="free") ?(license_server=[]) ?(local_cache_sr=Ref.null) ?(chipset_info=[]) () =
@@ -95,11 +97,49 @@ let make_pool ~__context ~master ?(name_label="") ?(name_description="")
9597
?(other_config=[Xapi_globs.memory_ratio_hvm; Xapi_globs.memory_ratio_pv]) () =
9698
let pool_ref = Ref.make () in
9799
Db.Pool.create ~__context ~ref:pool_ref
98-
~uuid:(Uuid.to_string (Uuid.make_uuid ())) ~name_label ~name_description
100+
~uuid:(make_uuid ()) ~name_label ~name_description
99101
~master ~default_SR ~suspend_image_SR ~crash_dump_SR ~ha_enabled
100102
~ha_configuration ~ha_statefiles ~ha_host_failures_to_tolerate
101103
~ha_plan_exists_for ~ha_allow_overcommit ~ha_overcommitted ~blobs ~tags
102104
~gui_config ~wlb_url ~wlb_username ~wlb_password ~wlb_enabled
103105
~wlb_verify_cert ~redo_log_enabled ~redo_log_vdi ~vswitch_controller
104106
~restrictions ~other_config;
105107
pool_ref
108+
109+
let make_sr ~__context ~ref ?(uuid=make_uuid ()) ?(name_label="") ?(name_description="") ?(allowed_operations=[])
110+
?(current_operations=[]) ?(virtual_allocation=0L) ?(physical_utilisation=0L) ?(physical_size=0L) ?(_type="")
111+
?(content_type="") ?(shared=true) ?(other_config=[]) ?(tags=[]) ?(default_vdi_visibility=true)
112+
?(sm_config=[]) ?(blobs=[]) ?(local_cache_enabled=false) ?(introduced_by=Ref.make ()) () =
113+
Db.SR.create ~__context ~ref ~uuid ~name_label ~name_description ~allowed_operations
114+
~current_operations ~virtual_allocation ~physical_utilisation ~physical_size ~_type
115+
~content_type ~shared ~other_config ~tags ~default_vdi_visibility ~sm_config ~blobs
116+
~local_cache_enabled ~introduced_by
117+
118+
let make_pbd ~__context ~ref ?(uuid=make_uuid ()) ?(host=Ref.make ()) ?(sR=Ref.make ())
119+
?(device_config=[]) ?(currently_attached=true) ?(other_config=[]) () =
120+
Db.PBD.create ~__context ~ref ~uuid ~host ~sR ~device_config ~currently_attached ~other_config
121+
122+
let make_vbd ~__context ?(ref=Ref.make ()) ?(uuid=make_uuid ()) ?(allowed_operations=[])
123+
?(current_operations=[]) ?(vM=Ref.make ()) ?(vDI=Ref.make ()) ?(device="")
124+
?(userdevice="") ?(bootable=true) ?(mode=`RW) ?(_type=`Disk)
125+
?(unpluggable=false) ?(storage_lock=false) ?(empty=false)
126+
?(reserved=false) ?(other_config=[]) ?(currently_attached=false)
127+
?(status_code=0L) ?(status_detail="") ?(runtime_properties=[])
128+
?(qos_algorithm_type="") ?(qos_algorithm_params=[]) ?(qos_supported_algorithms=[])
129+
?(metrics = Ref.make ()) () =
130+
Db.VBD.create ~__context ~ref ~uuid ~allowed_operations ~current_operations ~vM ~vDI ~device
131+
~userdevice ~bootable ~mode ~_type ~unpluggable ~storage_lock ~empty ~reserved ~other_config
132+
~currently_attached ~status_code ~status_detail ~runtime_properties ~qos_algorithm_type
133+
~qos_algorithm_params ~qos_supported_algorithms ~metrics
134+
135+
let make_vdi ~__context ?(ref=Ref.make ()) ?(uuid=make_uuid ()) ?(name_label="")
136+
?(name_description="") ?(allowed_operations=[]) ?(current_operations=[]) ?(sR=Ref.make ())
137+
?(virtual_size=0L) ?(physical_utilisation=0L) ?(_type=`user) ?(sharable=true) ?(read_only=false)
138+
?(other_config=[]) ?(storage_lock=false) ?(location="") ?(managed=false) ?(missing=false)
139+
?(parent=Ref.null) ?(xenstore_data=[]) ?(sm_config=[]) ?(is_a_snapshot=false)
140+
?(snapshot_of=Ref.null) ?(snapshot_time=API.Date.never) ?(tags=[]) ?(allow_caching=true)
141+
?(on_boot=`persist) ?(metadata_of_pool=Ref.make ()) ?(metadata_latest=true) () =
142+
Db.VDI.create ~__context ~ref ~uuid ~name_label ~name_description ~allowed_operations
143+
~current_operations ~sR ~virtual_size ~physical_utilisation ~_type ~sharable ~read_only ~other_config
144+
~storage_lock ~location ~managed ~missing ~parent ~xenstore_data ~sm_config ~is_a_snapshot ~snapshot_of
145+
~snapshot_time ~tags ~allow_caching ~on_boot ~metadata_of_pool ~metadata_latest

ocaml/xapi/xapi_vdi.ml

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ open Printf
2929
let check_operation_error ~__context ?(sr_records=[]) ?(pbd_records=[]) ?(vbd_records=[]) ha_enabled record _ref' op =
3030
let _ref = Ref.string_of _ref' in
3131
let current_ops = record.Db_actions.vDI_current_operations in
32-
3332
let reset_on_boot = record.Db_actions.vDI_on_boot = `reset in
3433

3534
(* Policy:
@@ -58,35 +57,47 @@ let check_operation_error ~__context ?(sr_records=[]) ?(pbd_records=[]) ?(vbd_re
5857
then Some(Api_errors.sr_no_pbds, [Ref.string_of sr])
5958
else
6059
(* check to see whether VBDs exist which are using this VDI *)
61-
let my_vbd_records = match vbd_records with
62-
| [] -> List.map (fun vbd -> Db.VBD.get_record_internal ~__context ~self:vbd) record.Db_actions.vDI_VBDs
63-
| _ -> List.map snd (List.filter (fun (_, vbd_record) -> vbd_record.Db_actions.vBD_VDI = _ref') vbd_records)
64-
in
6560

6661
(* Only a 'live' operation can be performed if there are active (even RO) devices *)
67-
let is_active v = v.Db_actions.vBD_currently_attached || v.Db_actions.vBD_reserved in
62+
let my_active_vbd_records = match vbd_records with
63+
| [] -> List.map snd (Db.VBD.get_internal_records_where ~__context
64+
~expr:(
65+
And(Eq (Field "VDI", Literal _ref),
66+
Or(
67+
Eq (Field "currently_attached", Literal "true"),
68+
Eq (Field "reserved", Literal "true")))
69+
))
70+
| _ -> List.map snd (List.filter (fun (_, vbd_record) ->
71+
vbd_record.Db_actions.vBD_VDI = _ref' && (vbd_record.Db_actions.vBD_currently_attached || vbd_record.Db_actions.vBD_reserved)
72+
) vbd_records)
73+
in
74+
6875
(* VBD operations (plug/unplug) (which should be transient) cause us to serialise *)
69-
let has_current_operation v = v.Db_actions.vBD_current_operations <> [] in
76+
let my_has_current_operation_vbd_records = match vbd_records with
77+
| [] -> List.map snd (Db.VBD.get_internal_records_where ~__context
78+
~expr:(
79+
And(Eq (Field "VDI", Literal _ref), Not (Eq (Field "current_operations", Literal "()")))
80+
))
81+
| _ -> List.map snd (List.filter (fun (_, vbd_record) ->
82+
vbd_record.Db_actions.vBD_VDI = _ref' && vbd_record.Db_actions.vBD_current_operations <> []
83+
) vbd_records)
84+
in
7085

7186
(* If the VBD is currently_attached then some operations can still be performed ie:
7287
VDI.clone (if the VM is suspended we have to have the 'allow_clone_suspended_vm'' flag)
7388
VDI.snapshot; VDI.resize_online; 'blocked' (CP-831) *)
7489
let operation_can_be_performed_live = match op with
75-
| `snapshot -> true
76-
| `resize_online -> true
77-
| `blocked -> true
78-
| `clone -> true
90+
| `snapshot | `resize_online | `blocked | `clone -> true
7991
| _ -> false in
8092

8193
(* NB RO vs RW sharing checks are done in xapi_vbd.ml *)
8294

8395
let sr_uuid = Db.SR.get_uuid ~__context ~self:sr in
8496
let sm_features = Xapi_sr_operations.features_of_sr_internal ~_type:sr_type ~uuid:sr_uuid in
8597

86-
let any_vbd p = List.fold_left (||) false (List.map p my_vbd_records) in
87-
if not operation_can_be_performed_live && (any_vbd is_active)
98+
if not operation_can_be_performed_live && (my_active_vbd_records <> [])
8899
then Some (Api_errors.vdi_in_use,[_ref; (Record_util.vdi_operation_to_string op)])
89-
else if any_vbd has_current_operation
100+
else if my_has_current_operation_vbd_records <> []
90101
then Some (Api_errors.other_operation_in_progress, [ "VDI"; _ref ])
91102
else (
92103
match op with

0 commit comments

Comments
 (0)