Efficient passing of attrs during traversals

Two improvements:

Do not iterate through stack outputs when determining what attributes
to send as input_data to the next resources in a traversal; it is at
best extra processing and at worse results in extra attributes being
included in input_data.

Do not re-resolve attributes / re-calculate input_data when we already
have it. I.e., when a resource constructs input_data to send to a
requirer resource, that same input_data may be used for all other
requirer resources.

Change-Id: I64089fb0774c10f172d986c3f87090e91cb3f263
Closes-Bug: #1656125
This commit is contained in:
Crag Wolfe 2017-01-10 16:12:54 -08:00
parent 4507322675
commit efabef60d0
3 changed files with 25 additions and 33 deletions

View File

@ -203,9 +203,13 @@ class CheckResource(object):
# for the next traversal.
graph_key = (rsrc.replaces, is_update)
def _get_input_data(req, fwd):
def _get_input_data(req, fwd, input_forward_data=None):
if fwd:
if input_forward_data is None:
return construct_input_data(rsrc, stack)
else:
# do not re-resolve attrs
return input_forward_data
else:
# Don't send data if initiating clean-up for self i.e.
# initiating delete of a replaced resource
@ -217,8 +221,11 @@ class CheckResource(object):
return None
try:
input_forward_data = None
for req, fwd in deps.required_by(graph_key):
input_data = _get_input_data(req, fwd)
input_data = _get_input_data(req, fwd, input_forward_data)
if fwd:
input_forward_data = input_data
propagate_check_resource(
cnxt, self._rpc_client, req, current_traversal,
set(graph[(req, fwd)]), graph_key, input_data, fwd,
@ -311,9 +318,7 @@ def _resolve_attributes(dep_attrs, rsrc):
def construct_input_data(rsrc, curr_stack):
dep_attrs = curr_stack.get_dep_attrs(
six.itervalues(curr_stack.resources),
curr_stack.outputs,
rsrc.name,
curr_stack.t.OUTPUT_VALUE)
rsrc.name)
input_data = {'id': rsrc.id,
'name': rsrc.name,
'reference_id': rsrc.get_reference_id(),

View File

@ -462,17 +462,14 @@ class Stack(collections.Mapping):
LOG.warning(_LW("Unable to set parameters StackId identifier"))
@staticmethod
def get_dep_attrs(resources, outputs, resource_name, value_sec):
def get_dep_attrs(resources, resource_name):
"""Return the attributes of the specified resource that are referenced.
Return an iterator over any attributes of the specified resource that
are referenced.
are referenced in resources.
"""
attr_lists = itertools.chain((res.dep_attrs(resource_name)
for res in resources),
(out.dep_attrs(resource_name)
for out in six.itervalues(outputs)))
return set(itertools.chain.from_iterable(attr_lists))
return set(itertools.chain.from_iterable(
res.dep_attrs(resource_name) for res in resources))
def _get_dependencies(self, ignore_errors=True):
"""Return the dependency graph for a list of resources."""

View File

@ -192,8 +192,7 @@ class DepAttrsTest(common.HeatTestCase):
('one_res_several_attrs',
dict(tmpl=tmpl3,
expected={'AResource': {'attr_A1', 'attr_A2', 'attr_A3',
'meta_A1', 'meta_A2', 'out_A1',
'out_A2'},
'meta_A1', 'meta_A2'},
'BResource': set()})),
('several_res_one_attr',
dict(tmpl=tmpl4,
@ -203,25 +202,19 @@ class DepAttrsTest(common.HeatTestCase):
'DResource': set()})),
('several_res_several_attrs',
dict(tmpl=tmpl5,
expected={'AResource': {'attr_A1', 'attr_A2', 'meta_A1',
'attr_A3', 'attr_A4'},
'BResource': {'attr_B1', 'attr_B2', 'meta_B2',
'attr_B3'},
expected={'AResource': {'attr_A1', 'attr_A2', 'meta_A1'},
'BResource': {'attr_B1', 'attr_B2', 'meta_B2'},
'CResource': set()})),
('nested_attr',
dict(tmpl=tmpl6,
expected={'AResource': set([(u'flat_dict', u'key2'),
(u'list', 1),
(u'nested_dict', u'dict', u'b'),
(u'nested_dict', u'string')]),
'BResource': set(['attr_B3'])})),
expected={'AResource': set([(u'list', 1),
(u'nested_dict', u'dict', u'b')]),
'BResource': set([])})),
('several_res_several_attrs_and_all_attrs',
dict(tmpl=tmpl7,
expected={'AResource': {'attr_A1', 'attr_A2', 'meta_A1',
'attr_A3', 'attr_A4'},
'BResource': {'attr_B1', 'attr_B2', 'meta_B2',
'attr_B3'},
'CResource': {'foo', 'Foo', 'show'}}))
expected={'AResource': {'attr_A1', 'attr_A2', 'meta_A1'},
'BResource': {'attr_B1', 'attr_B2', 'meta_B2'},
'CResource': set()}))
]
def setUp(self):
@ -234,11 +227,8 @@ class DepAttrsTest(common.HeatTestCase):
template.Template(parsed_tmpl))
for res in six.itervalues(self.stack):
outputs = self.stack.outputs
resources = six.itervalues(self.stack.resources)
self.assertEqual(self.expected[res.name],
self.stack.get_dep_attrs(
resources,
outputs,
res.name,
self.stack.t.OUTPUT_VALUE))
res.name))