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
This commit is contained in:
Stan Lagun 2015-09-20 21:57:45 +03:00
parent 8c8005edc3
commit 6dfeee7e69
3 changed files with 16 additions and 15 deletions

View File

@ -31,6 +31,7 @@ CTX_PACKAGE_LOADER = '$?packageLoader'
CTX_SKIP_FRAME = '$?skipFrame' CTX_SKIP_FRAME = '$?skipFrame'
CTX_THIS = '$?this' CTX_THIS = '$?this'
CTX_TYPE = '$?type' CTX_TYPE = '$?type'
CTX_VARIABLE_SCOPE = '$?variableScope'
CTX_YAQL_ENGINE = '$?yaqlEngine' CTX_YAQL_ENGINE = '$?yaqlEngine'
DM_OBJECTS = 'Objects' DM_OBJECTS = 'Objects'

View File

@ -15,14 +15,13 @@
import itertools import itertools
import types import types
from yaql.language import expressions
from yaql.language import specs from yaql.language import specs
from yaql.language import utils from yaql.language import utils
from yaql.language import yaqltypes from yaql.language import yaqltypes
from murano.dsl import constants
from murano.dsl import dsl_types from murano.dsl import dsl_types
from murano.dsl import exceptions from murano.dsl import exceptions
from murano.dsl import yaql_expression
from murano.dsl import yaql_integration from murano.dsl import yaql_integration
@ -39,24 +38,22 @@ class LhsExpression(object):
self._setter(value) self._setter(value)
def __init__(self, expression): def __init__(self, expression):
if isinstance(expression, (yaql_expression.YaqlExpression, self._expression = expression
expressions.Statement)):
self._expression = expression
else:
self._expression = yaql_integration.parse(str(expression))
def _create_context(self, root_context): def _create_context(self, root_context):
@specs.parameter('path', yaqltypes.Lambda(with_context=True)) @specs.parameter('name', yaqltypes.StringConstant())
def get_context_data(path): def get_context_data(name):
path = path(root_context)
def set_data(value): def set_data(value):
if not path or path == '$' or path == '$this': if not name or name == '$' or name == '$this':
raise ValueError() raise ValueError('Cannot assign to {0}'.format(name))
root_context[path] = value ctx = root_context
while constants.CTX_VARIABLE_SCOPE not in ctx:
ctx = ctx.parent
ctx[name] = value
return LhsExpression.Property( return LhsExpression.Property(
lambda: root_context[path], set_data) lambda: root_context[name], set_data)
@specs.parameter('this', LhsExpression.Property) @specs.parameter('this', LhsExpression.Property)
@specs.parameter('key', yaqltypes.Keyword()) @specs.parameter('key', yaqltypes.Keyword())

View File

@ -51,6 +51,7 @@ class MethodBlock(CodeBlock):
def execute(self, context): def execute(self, context):
new_context = context.create_child_context() new_context = context.create_child_context()
new_context[constants.CTX_VARIABLE_SCOPE] = True
try: try:
super(MethodBlock, self).execute(new_context) super(MethodBlock, self).execute(new_context)
except exceptions.ReturnException as e: except exceptions.ReturnException as e:
@ -102,7 +103,9 @@ class ParallelMacro(CodeBlock):
return return
limit = helpers.evaluate(self._limit, context) limit = helpers.evaluate(self._limit, context)
helpers.parallel_select( 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): class IfMacro(expressions.DslExpression):