From 6dfeee7e69f5d82f568fea622ad51cdaf08025b2 Mon Sep 17 00:00:00 2001 From: Stan Lagun Date: Sun, 20 Sep 2015 21:57:45 +0300 Subject: [PATCH] Function caller was incorrect when called from Parallel block Current instruction is tracked as a value in yaql context. But in Parallel block individual instructions executed in separate threads. As a result when those threads get scheduled current instruction in caller context already changes to the last one (which is a synchronization point for the Parallel block). To solve this all spawned threads need to work in their own dedicated child contexts. Then each of those contexts will have its own "current instruction". However this also brings a side effect: all local variable modifications made by spawned threads will be go to those new contexts and will be lost upon exit from Parallel. To solve this context that local variable need to be in is marked with special flag. When executing "$var: value" expressions DSL will scan context chain up to the context with that flag. Currently the only context with the flag is a method context that defines local variable scope. Change-Id: I0647915c104dfe4e00dd86c17726245d1bbc3beb Closes-Bug: #1497772 --- murano/dsl/constants.py | 1 + murano/dsl/lhs_expression.py | 25 +++++++++++-------------- murano/dsl/macros.py | 5 ++++- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/murano/dsl/constants.py b/murano/dsl/constants.py index 1c904f19..b24dc57e 100644 --- a/murano/dsl/constants.py +++ b/murano/dsl/constants.py @@ -31,6 +31,7 @@ CTX_PACKAGE_LOADER = '$?packageLoader' CTX_SKIP_FRAME = '$?skipFrame' CTX_THIS = '$?this' CTX_TYPE = '$?type' +CTX_VARIABLE_SCOPE = '$?variableScope' CTX_YAQL_ENGINE = '$?yaqlEngine' DM_OBJECTS = 'Objects' diff --git a/murano/dsl/lhs_expression.py b/murano/dsl/lhs_expression.py index 626f4c1d..c3ac973c 100644 --- a/murano/dsl/lhs_expression.py +++ b/murano/dsl/lhs_expression.py @@ -15,14 +15,13 @@ import itertools import types -from yaql.language import expressions from yaql.language import specs from yaql.language import utils from yaql.language import yaqltypes +from murano.dsl import constants from murano.dsl import dsl_types from murano.dsl import exceptions -from murano.dsl import yaql_expression from murano.dsl import yaql_integration @@ -39,24 +38,22 @@ class LhsExpression(object): self._setter(value) def __init__(self, expression): - if isinstance(expression, (yaql_expression.YaqlExpression, - expressions.Statement)): - self._expression = expression - else: - self._expression = yaql_integration.parse(str(expression)) + self._expression = expression def _create_context(self, root_context): - @specs.parameter('path', yaqltypes.Lambda(with_context=True)) - def get_context_data(path): - path = path(root_context) + @specs.parameter('name', yaqltypes.StringConstant()) + def get_context_data(name): def set_data(value): - if not path or path == '$' or path == '$this': - raise ValueError() - root_context[path] = value + if not name or name == '$' or name == '$this': + raise ValueError('Cannot assign to {0}'.format(name)) + ctx = root_context + while constants.CTX_VARIABLE_SCOPE not in ctx: + ctx = ctx.parent + ctx[name] = value return LhsExpression.Property( - lambda: root_context[path], set_data) + lambda: root_context[name], set_data) @specs.parameter('this', LhsExpression.Property) @specs.parameter('key', yaqltypes.Keyword()) diff --git a/murano/dsl/macros.py b/murano/dsl/macros.py index 30a0eabd..3b8e18cc 100644 --- a/murano/dsl/macros.py +++ b/murano/dsl/macros.py @@ -51,6 +51,7 @@ class MethodBlock(CodeBlock): def execute(self, context): new_context = context.create_child_context() + new_context[constants.CTX_VARIABLE_SCOPE] = True try: super(MethodBlock, self).execute(new_context) except exceptions.ReturnException as e: @@ -102,7 +103,9 @@ class ParallelMacro(CodeBlock): return limit = helpers.evaluate(self._limit, context) helpers.parallel_select( - self.code_block, lambda expr: expr.execute(context), limit) + self.code_block, + lambda expr: expr.execute(context.create_child_context()), + limit) class IfMacro(expressions.DslExpression):