{-
-Copyright (C) 2009, 2010, 2011 Google Inc.
+Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
, setSec
, setMdsk
, setMcpu
+ , setPolicy
-- * Tag maps
, addTags
, delTags
, fDsk :: Int -- ^ Free disk space (MiB)
, tCpu :: Double -- ^ Total CPU count
, uCpu :: Int -- ^ Used VCPU count
+ , spindleCount :: Int -- ^ Node spindles (spindle_count node parameter)
, pList :: [T.Idx] -- ^ List of primary instance indices
, sList :: [T.Idx] -- ^ List of secondary instance indices
, idx :: T.Ndx -- ^ Internal index for book-keeping
, pRem :: Double -- ^ Percent of reserved memory
, pCpu :: Double -- ^ Ratio of virtual to physical CPUs
, mDsk :: Double -- ^ Minimum free disk ratio
- , mCpu :: Double -- ^ Max ratio of virt-to-phys CPUs
, loDsk :: Int -- ^ Autocomputed from mDsk low disk
-- threshold
, hiCpu :: Int -- ^ Autocomputed from mCpu high cpu
-- threshold
+ , hiSpindles :: Double -- ^ Auto-computed from policy spindle_ratio
+ -- and the node spindle count
+ , instSpindles :: Double -- ^ Spindles used by instances
, offline :: Bool -- ^ Whether the node should not be used for
-- allocations and skipped from score
-- computations
, utilLoad :: T.DynUtil -- ^ Sum of instance utilisation
, pTags :: TagMap -- ^ Map of primary instance tags and their count
, group :: T.Gdx -- ^ The node's group (index)
+ , iPolicy :: T.IPolicy -- ^ The instance policy (of the node's group)
} deriving (Show, Read, Eq)
instance T.Element Node where
conflictingPrimaries :: Node -> Int
conflictingPrimaries (Node { pTags = t }) = Foldable.sum t - Map.size t
+-- | Helper function to increment a base value depending on the passed
+-- boolean argument.
+incIf :: (Num a) => Bool -> a -> a -> a
+incIf True base delta = base + delta
+incIf False base _ = base
+
+-- | Helper function to decrement a base value depending on the passed
+-- boolean argument.
+decIf :: (Num a) => Bool -> a -> a -> a
+decIf True base delta = base - delta
+decIf False base _ = base
+
-- * Initialization functions
-- | Create a new node.
-- The index and the peers maps are empty, and will be need to be
-- update later via the 'setIdx' and 'buildPeers' functions.
create :: String -> Double -> Int -> Int -> Double
- -> Int -> Double -> Bool -> T.Gdx -> Node
+ -> Int -> Double -> Bool -> Int -> T.Gdx -> Node
create name_init mem_t_init mem_n_init mem_f_init
- dsk_t_init dsk_f_init cpu_t_init offline_init group_init =
+ dsk_t_init dsk_f_init cpu_t_init offline_init spindles_init
+ group_init =
Node { name = name_init
, alias = name_init
, tMem = mem_t_init
, tDsk = dsk_t_init
, fDsk = dsk_f_init
, tCpu = cpu_t_init
+ , spindleCount = spindles_init
, uCpu = 0
, pList = []
, sList = []
, peers = P.empty
, rMem = 0
, pMem = fromIntegral mem_f_init / mem_t_init
- , pDsk = fromIntegral dsk_f_init / dsk_t_init
+ , pDsk = computePDsk dsk_f_init dsk_t_init
, pRem = 0
, pCpu = 0
, offline = offline_init
, xMem = 0
, mDsk = T.defReservedDiskRatio
- , mCpu = T.defVcpuRatio
, loDsk = mDskToloDsk T.defReservedDiskRatio dsk_t_init
- , hiCpu = mCpuTohiCpu T.defVcpuRatio cpu_t_init
+ , hiCpu = mCpuTohiCpu (T.iPolicyVcpuRatio T.defIPolicy) cpu_t_init
+ , hiSpindles = computeHiSpindles (T.iPolicySpindleRatio T.defIPolicy)
+ spindles_init
+ , instSpindles = 0
, utilPool = T.baseUtil
, utilLoad = T.zeroUtil
, pTags = Map.empty
, group = group_init
+ , iPolicy = T.defIPolicy
}
-- | Conversion formula from mDsk\/tDsk to loDsk.
mCpuTohiCpu :: Double -> Double -> Int
mCpuTohiCpu mval = floor . (mval *)
+-- | Conversiojn formula from spindles and spindle ratio to hiSpindles.
+computeHiSpindles :: Double -> Int -> Double
+computeHiSpindles spindle_ratio = (spindle_ratio *) . fromIntegral
+
-- | Changes the index.
--
-- This is used only during the building of the data structures.
setMdsk :: Node -> Double -> Node
setMdsk t val = t { mDsk = val, loDsk = mDskToloDsk val (tDsk t) }
--- | Sets the max cpu usage ratio.
+-- | Sets the max cpu usage ratio. This will update the node's
+-- ipolicy, losing sharing (but it should be a seldomly done operation).
setMcpu :: Node -> Double -> Node
-setMcpu t val = t { mCpu = val, hiCpu = mCpuTohiCpu val (tCpu t) }
+setMcpu t val =
+ let new_ipol = (iPolicy t) { T.iPolicyVcpuRatio = val }
+ in t { hiCpu = mCpuTohiCpu val (tCpu t), iPolicy = new_ipol }
+
+-- | Sets the policy.
+setPolicy :: T.IPolicy -> Node -> Node
+setPolicy pol node =
+ node { iPolicy = pol
+ , hiCpu = mCpuTohiCpu (T.iPolicyVcpuRatio pol) (tCpu node)
+ , hiSpindles = computeHiSpindles (T.iPolicySpindleRatio pol)
+ (spindleCount node)
+ }
-- | Computes the maximum reserved memory for peers from a peer map.
computeMaxRes :: P.PeerMap -> P.Elem
buildPeers t il =
let mdata = map
(\i_idx -> let inst = Container.find i_idx il
- mem = if Instance.autoBalance inst
+ mem = if Instance.usesSecMem inst
then Instance.mem inst
else 0
in (Instance.pNode inst, mem))
new_prem = fromIntegral new_rmem / tMem t
in t {peers=pmap, failN1 = new_failN1, rMem = new_rmem, pRem = new_prem}
+-- | Calculate the new spindle usage
+calcSpindleUse :: Node -> Instance.Instance -> Double
+calcSpindleUse n i = incIf (Instance.usesLocalStorage i) (instSpindles n)
+ (fromIntegral $ Instance.spindleUse i)
+
-- | Assigns an instance to a node as primary and update the used VCPU
-- count, utilisation data and tags map.
setPri :: Node -> Instance.Instance -> Node
, pCpu = fromIntegral new_count / tCpu t
, utilLoad = utilLoad t `T.addUtil` Instance.util inst
, pTags = addTags (pTags t) (Instance.tags inst)
+ , instSpindles = calcSpindleUse t inst
}
- where new_count = uCpu t + Instance.vcpus inst
+ where new_count = Instance.applyIfOnline inst (+ Instance.vcpus inst)
+ (uCpu t )
-- | Assigns an instance to a node as secondary without other updates.
setSec :: Node -> Instance.Instance -> Node
setSec t inst = t { sList = Instance.idx inst:sList t
, utilLoad = old_load { T.dskWeight = T.dskWeight old_load +
T.dskWeight (Instance.util inst) }
+ , instSpindles = calcSpindleUse t inst
}
where old_load = utilLoad t
+-- | Computes the new 'pDsk' value, handling nodes without local disk
+-- storage (we consider all their disk used).
+computePDsk :: Int -> Double -> Double
+computePDsk _ 0 = 1
+computePDsk used total = fromIntegral used / total
+
-- * Update functions
-- | Sets the free memory.
removePri :: Node -> Instance.Instance -> Node
removePri t inst =
let iname = Instance.idx inst
+ i_online = Instance.notOffline inst
+ uses_disk = Instance.usesLocalStorage inst
new_plist = delete iname (pList t)
- new_mem = Instance.applyIfOnline inst (+ Instance.mem inst) (fMem t)
- new_dsk = fDsk t + Instance.dsk inst
+ new_mem = incIf i_online (fMem t) (Instance.mem inst)
+ new_dsk = incIf uses_disk (fDsk t) (Instance.dsk inst)
+ new_spindles = decIf uses_disk (instSpindles t) 1
new_mp = fromIntegral new_mem / tMem t
- new_dp = fromIntegral new_dsk / tDsk t
+ new_dp = computePDsk new_dsk (tDsk t)
new_failn1 = new_mem <= rMem t
- new_ucpu = Instance.applyIfOnline inst
- (\x -> x - Instance.vcpus inst) (uCpu t)
+ new_ucpu = decIf i_online (uCpu t) (Instance.vcpus inst)
new_rcpu = fromIntegral new_ucpu / tCpu t
new_load = utilLoad t `T.subUtil` Instance.util inst
in t { pList = new_plist, fMem = new_mem, fDsk = new_dsk
, failN1 = new_failn1, pMem = new_mp, pDsk = new_dp
, uCpu = new_ucpu, pCpu = new_rcpu, utilLoad = new_load
- , pTags = delTags (pTags t) (Instance.tags inst) }
+ , pTags = delTags (pTags t) (Instance.tags inst)
+ , instSpindles = new_spindles
+ }
-- | Removes a secondary instance.
removeSec :: Node -> Instance.Instance -> Node
removeSec t inst =
let iname = Instance.idx inst
+ uses_disk = Instance.usesLocalStorage inst
cur_dsk = fDsk t
pnode = Instance.pNode inst
new_slist = delete iname (sList t)
- new_dsk = if Instance.usesLocalStorage inst
- then cur_dsk + Instance.dsk inst
- else cur_dsk
+ new_dsk = incIf uses_disk cur_dsk (Instance.dsk inst)
+ new_spindles = decIf uses_disk (instSpindles t) 1
old_peers = peers t
old_peem = P.find pnode old_peers
- new_peem = if Instance.autoBalance inst
- then old_peem - Instance.mem inst
- else old_peem
+ new_peem = decIf (Instance.usesSecMem inst) old_peem (Instance.mem inst)
new_peers = if new_peem > 0
then P.add pnode new_peem old_peers
else P.remove pnode old_peers
else computeMaxRes new_peers
new_prem = fromIntegral new_rmem / tMem t
new_failn1 = fMem t <= new_rmem
- new_dp = fromIntegral new_dsk / tDsk t
+ new_dp = computePDsk new_dsk (tDsk t)
old_load = utilLoad t
new_load = old_load { T.dskWeight = T.dskWeight old_load -
T.dskWeight (Instance.util inst) }
in t { sList = new_slist, fDsk = new_dsk, peers = new_peers
, failN1 = new_failn1, rMem = new_rmem, pDsk = new_dp
- , pRem = new_prem, utilLoad = new_load }
+ , pRem = new_prem, utilLoad = new_load
+ , instSpindles = new_spindles
+ }
-- | Adds a primary instance (basic version).
addPri :: Node -> Instance.Instance -> T.OpResult Node
-- or a failure mode
addPriEx force t inst =
let iname = Instance.idx inst
+ i_online = Instance.notOffline inst
uses_disk = Instance.usesLocalStorage inst
cur_dsk = fDsk t
- new_mem = Instance.applyIfOnline inst
- (\x -> x - Instance.mem inst) (fMem t)
- new_dsk = if uses_disk
- then cur_dsk - Instance.dsk inst
- else cur_dsk
+ new_mem = decIf i_online (fMem t) (Instance.mem inst)
+ new_dsk = decIf uses_disk cur_dsk (Instance.dsk inst)
+ new_spindles = incIf uses_disk (instSpindles t) 1
new_failn1 = new_mem <= rMem t
- new_ucpu = Instance.applyIfOnline inst (+ Instance.vcpus inst) (uCpu t)
+ new_ucpu = incIf i_online (uCpu t) (Instance.vcpus inst)
new_pcpu = fromIntegral new_ucpu / tCpu t
- new_dp = fromIntegral new_dsk / tDsk t
- l_cpu = mCpu t
+ new_dp = computePDsk new_dsk (tDsk t)
+ l_cpu = T.iPolicyVcpuRatio $ iPolicy t
new_load = utilLoad t `T.addUtil` Instance.util inst
inst_tags = Instance.tags inst
old_tags = pTags t
_ | new_mem <= 0 -> T.OpFail T.FailMem
| uses_disk && new_dsk <= 0 -> T.OpFail T.FailDisk
| uses_disk && mDsk t > new_dp && strict -> T.OpFail T.FailDisk
+ | uses_disk && new_spindles > hiSpindles t
+ && strict -> T.OpFail T.FailDisk
| new_failn1 && not (failN1 t) && strict -> T.OpFail T.FailMem
| l_cpu >= 0 && l_cpu < new_pcpu && strict -> T.OpFail T.FailCPU
| rejectAddTags old_tags inst_tags -> T.OpFail T.FailTags
, failN1 = new_failn1, pMem = new_mp, pDsk = new_dp
, uCpu = new_ucpu, pCpu = new_pcpu
, utilLoad = new_load
- , pTags = addTags old_tags inst_tags }
+ , pTags = addTags old_tags inst_tags
+ , instSpindles = new_spindles
+ }
in T.OpGood r
-- | Adds a secondary instance (basic version).
old_peers = peers t
old_mem = fMem t
new_dsk = fDsk t - Instance.dsk inst
- secondary_needed_mem = if Instance.autoBalance inst &&
- not (Instance.instanceOffline inst)
+ new_spindles = instSpindles t + 1
+ secondary_needed_mem = if Instance.usesSecMem inst
then Instance.mem inst
else 0
new_peem = P.find pdx old_peers + secondary_needed_mem
new_rmem = max (rMem t) new_peem
new_prem = fromIntegral new_rmem / tMem t
new_failn1 = old_mem <= new_rmem
- new_dp = fromIntegral new_dsk / tDsk t
+ new_dp = computePDsk new_dsk (tDsk t)
old_load = utilLoad t
new_load = old_load { T.dskWeight = T.dskWeight old_load +
T.dskWeight (Instance.util inst) }
_ | not (Instance.hasSecondary inst) -> T.OpFail T.FailDisk
| new_dsk <= 0 -> T.OpFail T.FailDisk
| mDsk t > new_dp && strict -> T.OpFail T.FailDisk
+ | new_spindles > hiSpindles t && strict -> T.OpFail T.FailDisk
| secondary_needed_mem >= old_mem && strict -> T.OpFail T.FailMem
| new_failn1 && not (failN1 t) && strict -> T.OpFail T.FailMem
| otherwise ->
r = t { sList = new_slist, fDsk = new_dsk
, peers = new_peers, failN1 = new_failn1
, rMem = new_rmem, pDsk = new_dp
- , pRem = new_prem, utilLoad = new_load }
+ , pRem = new_prem, utilLoad = new_load
+ , instSpindles = new_spindles
+ }
in T.OpGood r
-- * Stats functions
"ptags" -> intercalate "," . map (uncurry (printf "%s=%d")) .
Map.toList $ pTags t
"peermap" -> show $ peers t
+ "spindle_count" -> show $ spindleCount t
+ "hi_spindles" -> show $ hiSpindles t
+ "inst_spindles" -> show $ instSpindles t
_ -> T.unknownField
where
T.DynUtil { T.cpuWeight = uC, T.memWeight = uM,
"nload" -> ("lNet", True)
"ptags" -> ("PrimaryTags", False)
"peermap" -> ("PeerMap", False)
+ "spindle_count" -> ("NodeSpindles", True)
+ "hi_spindles" -> ("MaxSpindles", True)
+ "inst_spindles" -> ("InstSpindles", True)
-- TODO: add node fields (group.uuid, group)
_ -> (T.unknownField, False)