Factor out allocation candidate generation strategy
This is a pure refactor to pull out the logic of assembling an
allocation candidate.
The _get_areq_list_generators returns a set of
generators, one per root (anchoring) provider, that can generate all the
viable candidates for that root by applying a product on the solutions
for each request groups.
The _generate_areq_lists implements the strategy of consuming these
generators. The current behavior is that placement consumes the
generator for the first root fully before moving to the next
(depth-first).
A later patch will change _generate_areq_lists to be able to apply
different strategies, like round-robin easily.
Related-Bug: #2070257
Change-Id: I4f8c8491d21426310a82df7186b7689b2dad253e
(cherry picked from commit 04718d65b6)
This commit is contained in:
@@ -687,7 +687,44 @@ def _consolidate_allocation_requests(areqs, rw_ctx):
|
|||||||
mappings=mappings)
|
mappings=mappings)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_areq_list_generators(areq_lists_by_anchor, all_suffixes):
|
||||||
|
"""Returns a generator for each anchor provider that generates viable
|
||||||
|
candidates (areq_lists) for the given anchor
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
# We're using itertools.product to go from this:
|
||||||
|
# areq_lists_by_suffix = {
|
||||||
|
# '': [areq__A, areq__B, ...],
|
||||||
|
# '1': [areq_1_A, areq_1_B, ...],
|
||||||
|
# ...
|
||||||
|
# '42': [areq_42_A, areq_42_B, ...],
|
||||||
|
# }
|
||||||
|
# to this:
|
||||||
|
# [ [areq__A, areq_1_A, ..., areq_42_A], Each of these lists is one
|
||||||
|
# [areq__A, areq_1_A, ..., areq_42_B], solution to return.
|
||||||
|
# [areq__A, areq_1_B, ..., areq_42_A], Each solution contains one
|
||||||
|
# [areq__A, areq_1_B, ..., areq_42_B], AllocationRequest from each
|
||||||
|
# [areq__B, areq_1_A, ..., areq_42_A], RequestGroup. So taken as a
|
||||||
|
# [areq__B, areq_1_A, ..., areq_42_B], whole, each list is a viable
|
||||||
|
# [areq__B, areq_1_B, ..., areq_42_A], (preliminary) candidate to
|
||||||
|
# [areq__B, areq_1_B, ..., areq_42_B], return.
|
||||||
|
# ...,
|
||||||
|
# ]
|
||||||
|
itertools.product(*list(areq_lists_by_suffix.values()))
|
||||||
|
for areq_lists_by_suffix in areq_lists_by_anchor.values()
|
||||||
|
# Filter out any entries that don't have allocation requests for
|
||||||
|
# *all* suffixes (i.e. all RequestGroups)
|
||||||
|
if set(areq_lists_by_suffix) == all_suffixes
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_areq_lists(areq_lists_by_anchor, all_suffixes):
|
||||||
|
generators = _get_areq_list_generators(areq_lists_by_anchor, all_suffixes)
|
||||||
|
return itertools.chain(*generators)
|
||||||
|
|
||||||
# TODO(efried): Move _merge_candidates to rw_ctx?
|
# TODO(efried): Move _merge_candidates to rw_ctx?
|
||||||
|
|
||||||
|
|
||||||
def _merge_candidates(candidates, rw_ctx):
|
def _merge_candidates(candidates, rw_ctx):
|
||||||
"""Given a dict, keyed by RequestGroup suffix, of allocation_requests,
|
"""Given a dict, keyed by RequestGroup suffix, of allocation_requests,
|
||||||
produce a single tuple of (allocation_requests, provider_summaries) that
|
produce a single tuple of (allocation_requests, provider_summaries) that
|
||||||
@@ -732,35 +769,7 @@ def _merge_candidates(candidates, rw_ctx):
|
|||||||
all_suffixes = set(candidates)
|
all_suffixes = set(candidates)
|
||||||
num_granular_groups = len(all_suffixes - set(['']))
|
num_granular_groups = len(all_suffixes - set(['']))
|
||||||
max_a_c = rw_ctx.config.placement.max_allocation_candidates
|
max_a_c = rw_ctx.config.placement.max_allocation_candidates
|
||||||
for areq_lists_by_suffix in areq_lists_by_anchor.values():
|
for areq_list in _generate_areq_lists(areq_lists_by_anchor, all_suffixes):
|
||||||
# Filter out any entries that don't have allocation requests for
|
|
||||||
# *all* suffixes (i.e. all RequestGroups)
|
|
||||||
if set(areq_lists_by_suffix) != all_suffixes:
|
|
||||||
continue
|
|
||||||
# We're using itertools.product to go from this:
|
|
||||||
# areq_lists_by_suffix = {
|
|
||||||
# '': [areq__A, areq__B, ...],
|
|
||||||
# '1': [areq_1_A, areq_1_B, ...],
|
|
||||||
# ...
|
|
||||||
# '42': [areq_42_A, areq_42_B, ...],
|
|
||||||
# }
|
|
||||||
# to this:
|
|
||||||
# [ [areq__A, areq_1_A, ..., areq_42_A], Each of these lists is one
|
|
||||||
# [areq__A, areq_1_A, ..., areq_42_B], areq_list in the loop below.
|
|
||||||
# [areq__A, areq_1_B, ..., areq_42_A], each areq_list contains one
|
|
||||||
# [areq__A, areq_1_B, ..., areq_42_B], AllocationRequest from each
|
|
||||||
# [areq__B, areq_1_A, ..., areq_42_A], RequestGroup. So taken as a
|
|
||||||
# [areq__B, areq_1_A, ..., areq_42_B], whole, each list is a viable
|
|
||||||
# [areq__B, areq_1_B, ..., areq_42_A], (preliminary) candidate to
|
|
||||||
# [areq__B, areq_1_B, ..., areq_42_B], return.
|
|
||||||
# ...,
|
|
||||||
# ]
|
|
||||||
|
|
||||||
# This loops on each merged candidate where a candidate is represented
|
|
||||||
# by the areq_list containing the allocations that fulfills each
|
|
||||||
# request groups
|
|
||||||
for areq_list in itertools.product(
|
|
||||||
*list(areq_lists_by_suffix.values())):
|
|
||||||
# At this point, each AllocationRequest in areq_list is still
|
# At this point, each AllocationRequest in areq_list is still
|
||||||
# marked as use_same_provider. This is necessary to filter by group
|
# marked as use_same_provider. This is necessary to filter by group
|
||||||
# policy, which enforces how these interact with each other.
|
# policy, which enforces how these interact with each other.
|
||||||
@@ -795,11 +804,6 @@ def _merge_candidates(candidates, rw_ctx):
|
|||||||
continue
|
continue
|
||||||
areqs.add(areq)
|
areqs.add(areq)
|
||||||
|
|
||||||
if max_a_c >= 0 and len(areqs) >= max_a_c:
|
|
||||||
# This duplicated check will go away in the next patch that
|
|
||||||
# refactors this logic a bit.
|
|
||||||
break
|
|
||||||
|
|
||||||
if max_a_c >= 0 and len(areqs) >= max_a_c:
|
if max_a_c >= 0 and len(areqs) >= max_a_c:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user