Add a rw_ctx.psum_res_by_rp_rc, for clarity

In _merge_candidates we need a final _exceeds_capacity check to
make sure a multi-part granular request has not exceeded capacity
limits. This uses a dict that maps resource provider uuid and resource
class name to a ProviderSummaryResource.

Rather than creating this dict in _merge_candidates, we now have it
as a member on the RequestWideSearchContext and add to it when
creating the ProviderSummaryResource.

This allows us to remove some looping in _merge_candidates and is
also a bit more tidy. This is only possible with the advent of
the RequestWideSearchContext, which is newer than _merge_candidates.

_exceeds_capacity is moved to the RequestWideSearchContext as
exceeds_capacity as it now makes sense as a method.

Because _rp_rc_key ended up used from two different modules and for
two different purposes, the method is instead removed and callers
create their own keys directly.

Change-Id: Id74c01215956fc998f2dadcd9d84801ac58c2d3d
This commit is contained in:
Chris Dent 2019-08-13 16:32:14 +01:00
parent 803d673c1f
commit 5dda479f5b
2 changed files with 42 additions and 49 deletions

View File

@ -571,6 +571,11 @@ def _build_provider_summaries(context, rw_ctx, prov_traits):
used=used,
max_unit=usage['max_unit'],
)
# Construct a dict, keyed by resource provider + resource class, of
# ProviderSummaryResource. This will be used to do a final capacity
# check/filter on each merged AllocationRequest.
psum_key = (rp_id, rc_name)
rw_ctx.psum_res_by_rp_rc[psum_key] = rpsr
summary.resources.append(rpsr)
@ -653,7 +658,7 @@ def _consolidate_allocation_requests(areqs, rw_ctx):
"`_consolidate_allocation_requests` to have the same "
"anchor!")
for arr in areq.resource_requests:
key = _rp_rc_key(arr.resource_provider, arr.resource_class)
key = (arr.resource_provider.id, arr.resource_class)
if key not in arrs_by_rp_rc:
arrs_by_rp_rc[key] = rw_ctx.copy_arr_if_needed(arr)
else:
@ -666,39 +671,6 @@ def _consolidate_allocation_requests(areqs, rw_ctx):
mappings=mappings)
def _exceeds_capacity(areq, psum_res_by_rp_rc):
"""Checks a (consolidated) AllocationRequest against the provider summaries
to ensure that it does not exceed capacity.
Exceeding capacity can mean the total amount (already used plus this
allocation) exceeds the total inventory amount; or this allocation exceeds
the max_unit in the inventory record.
:param areq: An AllocationRequest produced by the
`_consolidate_allocation_requests` method.
:param psum_res_by_rp_rc: A dict, keyed by provider + resource class via
_rp_rc_key, of ProviderSummaryResource.
:return: True if areq exceeds capacity; False otherwise.
"""
for arr in areq.resource_requests:
key = _rp_rc_key(arr.resource_provider, arr.resource_class)
psum_res = psum_res_by_rp_rc[key]
if psum_res.used + arr.amount > psum_res.capacity:
LOG.debug('Excluding the following AllocationRequest because used '
'(%d) + amount (%d) > capacity (%d) for resource class '
'%s: %s',
psum_res.used, arr.amount, psum_res.capacity,
arr.resource_class, str(areq))
return True
if arr.amount > psum_res.max_unit:
LOG.debug('Excluding the following AllocationRequest because '
'amount (%d) > max_unit (%d) for resource class %s: %s',
arr.amount, psum_res.max_unit, arr.resource_class,
str(areq))
return True
return False
# TODO(efried): Move _merge_candidates to rw_ctx?
def _merge_candidates(candidates, rw_ctx):
"""Given a dict, keyed by RequestGroup suffix, of tuples of
@ -736,20 +708,12 @@ def _merge_candidates(candidates, rw_ctx):
lambda: collections.defaultdict(list))
# Save off all the provider summaries lists - we'll use 'em later.
all_psums = []
# Construct a dict, keyed by resource provider + resource class, of
# ProviderSummaryResource. This will be used to do a final capacity
# check/filter on each merged AllocationRequest.
psum_res_by_rp_rc = {}
for suffix, (areqs, psums) in candidates.items():
for areq in areqs:
anchor = areq.anchor_root_provider_uuid
areq_lists_by_anchor[anchor][suffix].append(areq)
for psum in psums:
all_psums.append(psum)
for psum_res in psum.resources:
key = _rp_rc_key(
psum.resource_provider, psum_res.resource_class)
psum_res_by_rp_rc[key] = psum_res
# Create all combinations picking one AllocationRequest from each list
# for each anchor.
@ -811,8 +775,7 @@ def _merge_candidates(candidates, rw_ctx):
# *independent* queries, it's possible that the combined result
# now exceeds capacity where amounts of the same RP+RC were
# folded together. So do a final capacity check/filter.
# TODO(efried): Move _exceeds_capacity to rw_ctx?
if _exceeds_capacity(areq, psum_res_by_rp_rc):
if rw_ctx.exceeds_capacity(areq):
continue
areqs.add(areq)
@ -836,11 +799,6 @@ def _merge_candidates(candidates, rw_ctx):
return list(areqs), psums
def _rp_rc_key(rp, rc):
"""Creates hashable key unique to a provider + resource class."""
return rp.id, rc
def _satisfies_group_policy(areqs, group_policy, num_granular_groups):
"""Applies group_policy to a list of AllocationRequest.

View File

@ -212,6 +212,10 @@ class RequestWideSearchContext(object):
# A mapping of resource provider uuid to parent provider uuid, used
# when merging allocation candidates.
self.parent_uuid_by_rp_uuid = {}
# Dict mapping (resource provier uuid, resource class name) to a
# ProviderSummaryResource. Used during _exceeds_capacity in
# _merge_candidates.
self.psum_res_by_rp_rc = {}
def _process_anchor_traits(self, rqparams):
"""Set or filter self.anchor_root_ids according to anchor
@ -358,6 +362,37 @@ class RequestWideSearchContext(object):
return copy.copy(arr)
return arr
def exceeds_capacity(self, areq):
"""Checks a (consolidated) AllocationRequest against the provider
summaries to ensure that it does not exceed capacity.
Exceeding capacity can mean the total amount (already used plus this
allocation) exceeds the total inventory amount; or this allocation
exceeds the max_unit in the inventory record.
:param areq: An AllocationRequest produced by the
`_consolidate_allocation_requests` method.
:return: True if areq exceeds capacity; False otherwise.
"""
for arr in areq.resource_requests:
key = (arr.resource_provider.id, arr.resource_class)
psum_res = self.psum_res_by_rp_rc[key]
if psum_res.used + arr.amount > psum_res.capacity:
LOG.debug('Excluding the following AllocationRequest because '
'used (%d) + amount (%d) > capacity (%d) for '
'resource class %s: %s',
psum_res.used, arr.amount, psum_res.capacity,
arr.resource_class, str(areq))
return True
if arr.amount > psum_res.max_unit:
LOG.debug('Excluding the following AllocationRequest because '
'amount (%d) > max_unit (%d) for resource class '
'%s: %s',
arr.amount, psum_res.max_unit, arr.resource_class,
str(areq))
return True
return False
@db_api.placement_context_manager.reader
def provider_ids_from_uuid(context, uuid):