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:
parent
8c8005edc3
commit
6dfeee7e69
@ -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'
|
||||
|
@ -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())
|
||||
|
@ -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):
|
||||
|
Loading…
Reference in New Issue
Block a user