, printSolution
, printSolutionLine
, formatCmds
- , printNodes
, involvedNodes
, splitJobs
+ -- * Display functions
+ , printNodes
+ , printInsts
-- * Balacing functions
, checkMove
, tryBalance
data Table = Table Node.List Instance.List Score [Placement]
deriving (Show)
-data CStats = CStats { cs_fmem :: Int -- ^ Cluster free mem
- , cs_fdsk :: Int -- ^ Cluster free disk
- , cs_amem :: Int -- ^ Cluster allocatable mem
- , cs_adsk :: Int -- ^ Cluster allocatable disk
- , cs_acpu :: Int -- ^ Cluster allocatable cpus
- , cs_mmem :: Int -- ^ Max node allocatable mem
- , cs_mdsk :: Int -- ^ Max node allocatable disk
- , cs_mcpu :: Int -- ^ Max node allocatable cpu
- , cs_imem :: Int -- ^ Instance used mem
- , cs_idsk :: Int -- ^ Instance used disk
- , cs_icpu :: Int -- ^ Instance used cpu
- , cs_tmem :: Double -- ^ Cluster total mem
- , cs_tdsk :: Double -- ^ Cluster total disk
- , cs_tcpu :: Double -- ^ Cluster total cpus
- , cs_xmem :: Int -- ^ Unnacounted for mem
- , cs_nmem :: Int -- ^ Node own memory
- , cs_score :: Score -- ^ The cluster score
- , cs_ninst :: Int -- ^ The total number of instances
+data CStats = CStats { csFmem :: Int -- ^ Cluster free mem
+ , csFdsk :: Int -- ^ Cluster free disk
+ , csAmem :: Int -- ^ Cluster allocatable mem
+ , csAdsk :: Int -- ^ Cluster allocatable disk
+ , csAcpu :: Int -- ^ Cluster allocatable cpus
+ , csMmem :: Int -- ^ Max node allocatable mem
+ , csMdsk :: Int -- ^ Max node allocatable disk
+ , csMcpu :: Int -- ^ Max node allocatable cpu
+ , csImem :: Int -- ^ Instance used mem
+ , csIdsk :: Int -- ^ Instance used disk
+ , csIcpu :: Int -- ^ Instance used cpu
+ , csTmem :: Double -- ^ Cluster total mem
+ , csTdsk :: Double -- ^ Cluster total disk
+ , csTcpu :: Double -- ^ Cluster total cpus
+ , csXmem :: Int -- ^ Unnacounted for mem
+ , csNmem :: Int -- ^ Node own memory
+ , csScore :: Score -- ^ The cluster score
+ , csNinst :: Int -- ^ The total number of instances
}
-- * Utility functions
let bad_nodes = verifyN1 $ getOnline nl
bad_instances = map (\idx -> Container.find idx il) .
sort . nub $
- concatMap (\ n -> Node.slist n ++ Node.plist n) bad_nodes
+ concatMap (\ n -> Node.sList n ++ Node.pList n) bad_nodes
in
(bad_nodes, bad_instances)
emptyCStats :: CStats
-emptyCStats = CStats { cs_fmem = 0
- , cs_fdsk = 0
- , cs_amem = 0
- , cs_adsk = 0
- , cs_acpu = 0
- , cs_mmem = 0
- , cs_mdsk = 0
- , cs_mcpu = 0
- , cs_imem = 0
- , cs_idsk = 0
- , cs_icpu = 0
- , cs_tmem = 0
- , cs_tdsk = 0
- , cs_tcpu = 0
- , cs_xmem = 0
- , cs_nmem = 0
- , cs_score = 0
- , cs_ninst = 0
+emptyCStats = CStats { csFmem = 0
+ , csFdsk = 0
+ , csAmem = 0
+ , csAdsk = 0
+ , csAcpu = 0
+ , csMmem = 0
+ , csMdsk = 0
+ , csMcpu = 0
+ , csImem = 0
+ , csIdsk = 0
+ , csIcpu = 0
+ , csTmem = 0
+ , csTdsk = 0
+ , csTcpu = 0
+ , csXmem = 0
+ , csNmem = 0
+ , csScore = 0
+ , csNinst = 0
}
updateCStats :: CStats -> Node.Node -> CStats
updateCStats cs node =
- let CStats { cs_fmem = x_fmem, cs_fdsk = x_fdsk,
- cs_amem = x_amem, cs_acpu = x_acpu, cs_adsk = x_adsk,
- cs_mmem = x_mmem, cs_mdsk = x_mdsk, cs_mcpu = x_mcpu,
- cs_imem = x_imem, cs_idsk = x_idsk, cs_icpu = x_icpu,
- cs_tmem = x_tmem, cs_tdsk = x_tdsk, cs_tcpu = x_tcpu,
- cs_xmem = x_xmem, cs_nmem = x_nmem, cs_ninst = x_ninst
+ let CStats { csFmem = x_fmem, csFdsk = x_fdsk,
+ csAmem = x_amem, csAcpu = x_acpu, csAdsk = x_adsk,
+ csMmem = x_mmem, csMdsk = x_mdsk, csMcpu = x_mcpu,
+ csImem = x_imem, csIdsk = x_idsk, csIcpu = x_icpu,
+ csTmem = x_tmem, csTdsk = x_tdsk, csTcpu = x_tcpu,
+ csXmem = x_xmem, csNmem = x_nmem, csNinst = x_ninst
}
= cs
- inc_amem = Node.f_mem node - Node.r_mem node
+ inc_amem = Node.fMem node - Node.rMem node
inc_amem' = if inc_amem > 0 then inc_amem else 0
inc_adsk = Node.availDisk node
- inc_imem = truncate (Node.t_mem node) - Node.n_mem node
- - Node.x_mem node - Node.f_mem node
- inc_icpu = Node.u_cpu node
- inc_idsk = truncate (Node.t_dsk node) - Node.f_dsk node
-
- in cs { cs_fmem = x_fmem + Node.f_mem node
- , cs_fdsk = x_fdsk + Node.f_dsk node
- , cs_amem = x_amem + inc_amem'
- , cs_adsk = x_adsk + inc_adsk
- , cs_acpu = x_acpu
- , cs_mmem = max x_mmem inc_amem'
- , cs_mdsk = max x_mdsk inc_adsk
- , cs_mcpu = x_mcpu
- , cs_imem = x_imem + inc_imem
- , cs_idsk = x_idsk + inc_idsk
- , cs_icpu = x_icpu + inc_icpu
- , cs_tmem = x_tmem + Node.t_mem node
- , cs_tdsk = x_tdsk + Node.t_dsk node
- , cs_tcpu = x_tcpu + Node.t_cpu node
- , cs_xmem = x_xmem + Node.x_mem node
- , cs_nmem = x_nmem + Node.n_mem node
- , cs_ninst = x_ninst + length (Node.plist node)
+ inc_imem = truncate (Node.tMem node) - Node.nMem node
+ - Node.xMem node - Node.fMem node
+ inc_icpu = Node.uCpu node
+ inc_idsk = truncate (Node.tDsk node) - Node.fDsk node
+
+ in cs { csFmem = x_fmem + Node.fMem node
+ , csFdsk = x_fdsk + Node.fDsk node
+ , csAmem = x_amem + inc_amem'
+ , csAdsk = x_adsk + inc_adsk
+ , csAcpu = x_acpu
+ , csMmem = max x_mmem inc_amem'
+ , csMdsk = max x_mdsk inc_adsk
+ , csMcpu = x_mcpu
+ , csImem = x_imem + inc_imem
+ , csIdsk = x_idsk + inc_idsk
+ , csIcpu = x_icpu + inc_icpu
+ , csTmem = x_tmem + Node.tMem node
+ , csTdsk = x_tdsk + Node.tDsk node
+ , csTcpu = x_tcpu + Node.tCpu node
+ , csXmem = x_xmem + Node.xMem node
+ , csNmem = x_nmem + Node.nMem node
+ , csNinst = x_ninst + length (Node.pList node)
}
-- | Compute the total free disk and memory in the cluster.
totalResources :: Node.List -> CStats
totalResources nl =
let cs = foldl' updateCStats emptyCStats . Container.elems $ nl
- in cs { cs_score = compCV nl }
+ in cs { csScore = compCV nl }
+
+-- | The names of the individual elements in the CV list
+detailedCVNames :: [String]
+detailedCVNames = [ "free_mem_cv"
+ , "free_disk_cv"
+ , "n1_score"
+ , "reserved_mem_cv"
+ , "offline_score"
+ , "vcpu_ratio_cv"
+ , "cpu_load_cv"
+ , "mem_load_cv"
+ , "disk_load_cv"
+ , "net_load_cv"
+ ]
-- | Compute the mem and disk covariance.
-compDetailedCV :: Node.List -> (Double, Double, Double, Double, Double, Double)
+compDetailedCV :: Node.List -> [Double]
compDetailedCV nl =
let
all_nodes = Container.elems nl
(offline, nodes) = partition Node.offline all_nodes
- mem_l = map Node.p_mem nodes
- dsk_l = map Node.p_dsk nodes
+ mem_l = map Node.pMem nodes
+ dsk_l = map Node.pDsk nodes
mem_cv = varianceCoeff mem_l
dsk_cv = varianceCoeff dsk_l
n1_l = length $ filter Node.failN1 nodes
n1_score = fromIntegral n1_l /
fromIntegral (length nodes)::Double
- res_l = map Node.p_rem nodes
+ res_l = map Node.pRem nodes
res_cv = varianceCoeff res_l
- offline_inst = sum . map (\n -> (length . Node.plist $ n) +
- (length . Node.slist $ n)) $ offline
- online_inst = sum . map (\n -> (length . Node.plist $ n) +
- (length . Node.slist $ n)) $ nodes
+ offline_inst = sum . map (\n -> (length . Node.pList $ n) +
+ (length . Node.sList $ n)) $ offline
+ online_inst = sum . map (\n -> (length . Node.pList $ n) +
+ (length . Node.sList $ n)) $ nodes
off_score = if offline_inst == 0
then 0::Double
else fromIntegral offline_inst /
fromIntegral (offline_inst + online_inst)::Double
- cpu_l = map Node.p_cpu nodes
+ cpu_l = map Node.pCpu nodes
cpu_cv = varianceCoeff cpu_l
- in (mem_cv, dsk_cv, n1_score, res_cv, off_score, cpu_cv)
+ (c_load, m_load, d_load, n_load) = unzip4 $
+ map (\n ->
+ let DynUtil c1 m1 d1 n1 = Node.utilLoad n
+ DynUtil c2 m2 d2 n2 = Node.utilPool n
+ in (c1/c2, m1/m2, d1/d2, n1/n2)
+ ) nodes
+ in [ mem_cv, dsk_cv, n1_score, res_cv, off_score, cpu_cv
+ , varianceCoeff c_load, varianceCoeff m_load
+ , varianceCoeff d_load, varianceCoeff n_load]
-- | Compute the /total/ variance.
compCV :: Node.List -> Double
-compCV nl =
- let (mem_cv, dsk_cv, n1_score, res_cv, off_score, cpu_cv) =
- compDetailedCV nl
- in mem_cv + dsk_cv + n1_score + res_cv + off_score + cpu_cv
+compCV = sum . compDetailedCV
-- | Compute online nodes from a Node.List
getOnline :: Node.List -> [Node.Node]
-> IMove -> OpResult (Node.List, Instance.Instance, Ndx, Ndx)
-- Failover (f)
applyMove nl inst Failover =
- let old_pdx = Instance.pnode inst
- old_sdx = Instance.snode inst
+ let old_pdx = Instance.pNode inst
+ old_sdx = Instance.sNode inst
old_p = Container.find old_pdx nl
old_s = Container.find old_sdx nl
int_p = Node.removePri old_p inst
-- Replace the primary (f:, r:np, f)
applyMove nl inst (ReplacePrimary new_pdx) =
- let old_pdx = Instance.pnode inst
- old_sdx = Instance.snode inst
+ let old_pdx = Instance.pNode inst
+ old_sdx = Instance.sNode inst
old_p = Container.find old_pdx nl
old_s = Container.find old_sdx nl
tgt_n = Container.find new_pdx nl
-- Replace the secondary (r:ns)
applyMove nl inst (ReplaceSecondary new_sdx) =
- let old_pdx = Instance.pnode inst
- old_sdx = Instance.snode inst
+ let old_pdx = Instance.pNode inst
+ old_sdx = Instance.sNode inst
old_s = Container.find old_sdx nl
tgt_n = Container.find new_sdx nl
int_s = Node.removeSec old_s inst
-- Replace the secondary and failover (r:np, f)
applyMove nl inst (ReplaceAndFailover new_pdx) =
- let old_pdx = Instance.pnode inst
- old_sdx = Instance.snode inst
+ let old_pdx = Instance.pNode inst
+ old_sdx = Instance.sNode inst
old_p = Container.find old_pdx nl
old_s = Container.find old_sdx nl
tgt_n = Container.find new_pdx nl
-- Failver and replace the secondary (f, r:ns)
applyMove nl inst (FailoverAndReplace new_sdx) =
- let old_pdx = Instance.pnode inst
- old_sdx = Instance.snode inst
+ let old_pdx = Instance.pNode inst
+ old_sdx = Instance.sNode inst
old_p = Container.find old_pdx nl
old_s = Container.find old_sdx nl
tgt_n = Container.find new_sdx nl
-> Table -- ^ Best new table for this instance
checkInstanceMove nodes_idx disk_moves ini_tbl target =
let
- opdx = Instance.pnode target
- osdx = Instance.snode target
+ opdx = Instance.pNode target
+ osdx = Instance.sNode target
nodes = filter (\idx -> idx /= opdx && idx /= osdx) nodes_idx
use_secondary = elem osdx nodes_idx
aft_failover = if use_secondary -- if allowed to failover
best_tbl =
foldl'
(\ step_tbl em ->
- if Instance.snode em == Node.noSecondary then step_tbl
+ if Instance.sNode em == Node.noSecondary then step_tbl
else compareTables step_tbl $
checkInstanceMove nodes_idx disk_moves ini_tbl em)
ini_tbl victims
tryReloc nl il xid 1 ex_idx =
let all_nodes = getOnline nl
inst = Container.find xid il
- ex_idx' = Instance.pnode inst:ex_idx
+ ex_idx' = Instance.pNode inst:ex_idx
valid_nodes = filter (not . flip elem ex_idx' . Node.idx) all_nodes
valid_idxes = map Node.idx valid_nodes
sols1 = foldl' (\cstate x ->
inam = Instance.name inst
npri = Container.nameOf nl p
nsec = Container.nameOf nl s
- opri = Container.nameOf nl $ Instance.pnode inst
- osec = Container.nameOf nl $ Instance.snode inst
+ opri = Container.nameOf nl $ Instance.pNode inst
+ osec = Container.nameOf nl $ Instance.sNode inst
(moves, cmds) = computeMoves inst inam opri osec npri nsec
ostr = printf "%s:%s" opri osec::String
nstr = printf "%s:%s" npri nsec::String
involvedNodes il plc =
let (i, np, ns, _, _) = plc
inst = Container.find i il
- op = Instance.pnode inst
- os = Instance.snode inst
+ op = Instance.pNode inst
+ os = Instance.sNode inst
in nub [np, ns, op, os]
-- | Inner function for splitJobs, that either appends the next job to
printNodes :: Node.List -> String
printNodes nl =
let snl = sortBy (compare `on` Node.idx) (Container.elems nl)
- m_name = maximum . map (length . Node.name) $ snl
- helper = Node.list m_name
- header = printf
- "%2s %-*s %5s %5s %5s %5s %5s %5s %5s %5s %4s %4s \
- \%3s %3s %6s %6s %5s"
- " F" m_name "Name"
- "t_mem" "n_mem" "i_mem" "x_mem" "f_mem" "r_mem"
- "t_dsk" "f_dsk" "pcpu" "vcpu"
- "pri" "sec" "p_fmem" "p_fdsk" "r_cpu"::String
- in unlines (header:map helper snl)
+ header = ["F", "Name"
+ , "t_mem", "n_mem", "i_mem", "x_mem", "f_mem", "r_mem"
+ , "t_dsk", "f_dsk", "pcpu", "vcpu", "pri", "sec"
+ , "p_fmem", "p_fdsk", "r_cpu"
+ , "lCpu", "lMem", "lDsk", "lNet" ]
+ isnum = False:False:repeat True
+ in unlines . map ((:) ' ' . intercalate " ") $
+ formatTable (header:map Node.list snl) isnum
+
+-- | Print the instance list.
+printInsts :: Node.List -> Instance.List -> String
+printInsts nl il =
+ let sil = sortBy (compare `on` Instance.idx) (Container.elems il)
+ helper inst = [ (Instance.name inst)
+ , (Container.nameOf nl (Instance.pNode inst))
+ , (let sdx = Instance.sNode inst
+ in if sdx == Node.noSecondary
+ then ""
+ else Container.nameOf nl sdx) ]
+ header = ["Name", "Pri_node", "Sec_node"]
+ isnum = repeat False
+ in unlines . map ((:) ' ' . intercalate " ") $
+ formatTable (header:map helper sil) isnum
-- | Shows statistics for a given node list.
printStats :: Node.List -> String
printStats nl =
- let (mem_cv, dsk_cv, n1_score, res_cv, off_score, cpu_cv) =
- compDetailedCV nl
- in printf "f_mem=%.8f, r_mem=%.8f, f_dsk=%.8f, n1=%.3f, \
- \uf=%.3f, r_cpu=%.3f"
- mem_cv res_cv dsk_cv n1_score off_score cpu_cv
+ let dcvs = compDetailedCV nl
+ hd = zip (detailedCVNames ++ repeat "unknown") dcvs
+ formatted = map (\(header, val) ->
+ printf "%s=%.8f" header val::String) hd
+ in intercalate ", " formatted
-- | Convert a placement into a list of OpCodes (basically a job).
iMoveToJob :: String -> Node.List -> Instance.List
-> Idx -> IMove -> [OpCodes.OpCode]
iMoveToJob csf nl il idx move =
- let iname = Container.nameOf il idx ++ csf
+ let inst = Container.find idx il
+ iname = Instance.name inst ++ csf
lookNode n = Just (Container.nameOf nl n ++ csf)
- opF = OpCodes.OpFailoverInstance iname False
+ opF = if Instance.running inst
+ then OpCodes.OpMigrateInstance iname True False
+ else OpCodes.OpFailoverInstance iname False
opR n = OpCodes.OpReplaceDisks iname (lookNode n)
OpCodes.ReplaceNewSecondary [] Nothing
in case move of