Skip to content

Commit

Permalink
Merge pull request #5129 from edwintorok/private/edvint/redologsize
Browse files Browse the repository at this point in the history
CA-380551: bump minimum HA SR size to 4GiB
  • Loading branch information
edwintorok authored Nov 6, 2023
2 parents d9d6103 + f387d52 commit 4f449c5
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 41 deletions.
13 changes: 11 additions & 2 deletions ocaml/database/redo_log.ml
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,17 @@ let mib megabytes =
let ( ** ) = Int64.mul in
Int64.of_int megabytes ** 1024L ** 1024L

(* Make sure we have plenty of room for the database *)
let minimum_vdi_size, recommended_vdi_size = (mib 256, mib 4096)
(* Make sure we have plenty of room for the database
There is also a 4MiB statefile, so make the sum be 4GB, which is easier to document.
*)
let minimum_vdi_size =
let ( // ) = Int64.div and ( ** ) = Int64.mul and ( -- ) = Int64.sub in
let align = mib 4 in
((4_000_000_000L // align)
-- 2L
(* -2 because we also need room for a statefile, and an 'empty' SR seems to have a utilization of 4MiB *)
)
** align

let redo_log_sm_config = [("type", "raw")]

Expand Down
3 changes: 0 additions & 3 deletions ocaml/database/redo_log.mli
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ val get_static_device : string -> string option
val minimum_vdi_size : int64
(** Minimum size for redo log VDI *)

val recommended_vdi_size : int64
(** Recommended size for redo log VDI *)

val redo_log_sm_config : (string * string) list
(** SM config for redo log VDI *)

Expand Down
2 changes: 1 addition & 1 deletion ocaml/xapi/xapi_pool.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2859,7 +2859,7 @@ let create_redo_log_vdi ~__context ~sr =
Client.VDI.create ~rpc ~session_id ~name_label:"Metadata redo-log"
~name_description:
"Used when HA is disabled, while extra security is still desired"
~sR:sr ~virtual_size:Redo_log.recommended_vdi_size ~_type:`redo_log
~sR:sr ~virtual_size:Redo_log.minimum_vdi_size ~_type:`redo_log
~sharable:true ~read_only:false ~other_config:[] ~xenstore_data:[]
~sm_config:Redo_log.redo_log_sm_config ~tags:[]
)
Expand Down
2 changes: 1 addition & 1 deletion ocaml/xapi/xapi_sr.ml
Original file line number Diff line number Diff line change
Expand Up @@ -946,7 +946,7 @@ let find_or_create_metadata_vdi ~__context ~sr =
Helpers.call_api_functions ~__context (fun rpc session_id ->
Client.VDI.create ~rpc ~session_id ~name_label:"Metadata for DR"
~name_description:"Used for disaster recovery" ~sR:sr
~virtual_size:Redo_log.recommended_vdi_size ~_type:`metadata
~virtual_size:Redo_log.minimum_vdi_size ~_type:`metadata
~sharable:false ~read_only:false ~other_config:[]
~xenstore_data:[] ~sm_config:Redo_log.redo_log_sm_config ~tags:[]
)
Expand Down
4 changes: 2 additions & 2 deletions ocaml/xapi/xha_metadata_vdi.ml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ let create ~__context ~sr =
Helpers.call_api_functions ~__context (fun rpc session_id ->
Client.VDI.create ~rpc ~session_id ~name_label:"Metadata for HA"
~name_description:"Used for master failover" ~sR:sr
~virtual_size:Redo_log.recommended_vdi_size ~_type:`redo_log
~sharable:true ~read_only:false ~other_config:[] ~xenstore_data:[]
~virtual_size:Redo_log.minimum_vdi_size ~_type:`redo_log ~sharable:true
~read_only:false ~other_config:[] ~xenstore_data:[]
~sm_config:Redo_log.redo_log_sm_config ~tags:[]
)

Expand Down
77 changes: 45 additions & 32 deletions ocaml/xapi/xha_statefile.ml
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,49 @@ open Client

(** Return the minimum size of an HA statefile, as of
XenServer HA state-file description vsn 1.3 *)
let minimum_size =
let minimum_statefile_size =
let ( ** ) = Int64.mul and ( ++ ) = Int64.add in
let global_section_size = 4096L
and host_section_size = 4096L
and maximum_number_of_hosts = 64L in
global_section_size ++ (maximum_number_of_hosts ** host_section_size)

let round_to ~align n = Int64.(div (add n @@ sub align 1L) align |> mul align)

(* SM doesn't actually allow us to create VDIs smaller than 4MiB, so we need to round up *)
let minimum_sr_size =
[minimum_statefile_size; Redo_log.minimum_vdi_size]
|> List.map @@ round_to ~align:Int64.(shift_left 1L 22)
|> List.fold_left Int64.add Int64.zero

let ha_fits_sr ~__context ~what ~sr ~typ ~minimum_size =
let ha_fits self =
Db.VDI.get_type ~__context ~self = typ
&& Db.VDI.get_virtual_size ~__context ~self >= minimum_size
in
match List.filter ha_fits (Db.SR.get_VDIs ~__context ~self:sr) with
| x :: _ ->
debug "Would re-use existing %s: %s" what
(Db.VDI.get_uuid ~__context ~self:x) ;
Some x
| [] ->
debug "no suitable existing %s found; would have to create a fresh one"
what ;
let self = sr in
let size = Db.SR.get_physical_size ~__context ~self in
let utilisation = Db.SR.get_physical_utilisation ~__context ~self in
let free_space = Int64.sub size utilisation in
if free_space < minimum_sr_size then (
let sr = Ref.string_of sr in
info "%s: SR %s size=%Ld utilisation=%Ld free=%Ld needed=%Ld"
__FUNCTION__ sr size utilisation free_space minimum_sr_size ;
raise
(Api_errors.Server_error
(Api_errors.sr_source_space_insufficient, [sr])
)
) else
None

let check_sr_can_host_statefile ~__context ~sr ~cluster_stack =
(* Check that each host has a PBD to this SR *)
let pbds = Db.SR.get_PBDs ~__context ~self:sr in
Expand Down Expand Up @@ -89,7 +125,7 @@ let check_sr_can_host_statefile ~__context ~sr ~cluster_stack =
]
)
)
| (_, sm) :: _ -> (
| (_, sm) :: _ ->
if
(not (List.mem_assoc "VDI_GENERATE_CONFIG" sm.Db_actions.sM_features))
&& not (List.mem_assoc "VDI_ATTACH_OFFLINE" sm.Db_actions.sM_features)
Expand All @@ -98,40 +134,17 @@ let check_sr_can_host_statefile ~__context ~sr ~cluster_stack =
(Api_errors.Server_error
(Api_errors.sr_operation_not_supported, [Ref.string_of sr])
) ;
let size = minimum_size in
let ha_fits self =
Db.VDI.get_type ~__context ~self = `ha_statefile
&& Db.VDI.get_virtual_size ~__context ~self >= size
in
match List.filter ha_fits (Db.SR.get_VDIs ~__context ~self:sr) with
| x :: _ ->
debug "Would re-use existing statefile: %s"
(Db.VDI.get_uuid ~__context ~self:x) ;
Some x
| [] ->
debug
"no suitable existing statefile found; would have to create a \
fresh one" ;
let self = sr in
let size = Db.SR.get_physical_size ~__context ~self in
let utilisation = Db.SR.get_physical_utilisation ~__context ~self in
let free_space = Int64.sub size utilisation in
if free_space < minimum_size then (
let sr = Ref.string_of sr in
info "%s: SR %s size=%Ld utilisation=%Ld free=%Ld needed=%Ld"
__FUNCTION__ sr size utilisation free_space minimum_size ;
raise
(Api_errors.Server_error
(Api_errors.sr_source_space_insufficient, [sr])
)
) else
None
)
ha_fits_sr ~__context ~what:"statefile" ~sr
~minimum_size:minimum_statefile_size ~typ:`ha_statefile

let assert_sr_can_host_statefile ~__context ~sr ~cluster_stack =
let (_ : 'a option) =
check_sr_can_host_statefile ~__context ~sr ~cluster_stack
in
let (_ : _ option) =
ha_fits_sr ~__context ~what:"redo-log" ~sr
~minimum_size:Redo_log.minimum_vdi_size ~typ:`redo_log
in
()

let list_srs_which_can_host_statefile ~__context ~cluster_stack =
Expand All @@ -146,7 +159,7 @@ let list_srs_which_can_host_statefile ~__context ~cluster_stack =

let create ~__context ~sr ~cluster_stack =
assert_sr_can_host_statefile ~__context ~sr ~cluster_stack ;
let size = minimum_size in
let size = minimum_statefile_size in
Helpers.call_api_functions ~__context (fun rpc session_id ->
Client.VDI.create ~rpc ~session_id ~name_label:"Statefile for HA"
~name_description:"Used for storage heartbeating" ~sR:sr
Expand Down

0 comments on commit 4f449c5

Please sign in to comment.