Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » OCL » OCL Thread Safety
OCL Thread Safety [message #67696] Fri, 13 February 2009 00:53 Go to next message
Matthew Watson is currently offline Matthew WatsonFriend
Messages: 24
Registered: July 2009
Junior Member
Hi,

I am attempting to use OCL (1.2.2) in querying and evaluating expressions
on multiple model instances in multiple threads in a high-throughput
environment.

I have stumbled over some thread-safety aspects of queries, but was
interested in getting the "official" ocl view on how it was intended to be
used in a multi-threaded environment.

Creating a query every time I want to use it seems like a big overhead to
me. My Model never changes at runtime, so creating all the queries I need
on startup and evaluating them again and again is my preferred scenario.

There are 2 cases I've found where this is not thread safe.

1: QueryImpl.evaluate(Object) sets internal state and is not thread-safe.

QueryImpl.evaluate(Object) sets the "self" property on a per-query
evaluation environment - using the same query in multiple threads soon
gets an exception warning the self is already set.

Thus I have had to synchronize on the query (or rather, wrap it in a
SynchronizedQuery).

This should work as long as I don't set values explicitly in the
Evaluation Environment (which I don't).

2: OCLHelperImpl is not thread safe in parsing queries.

This surprises me, I don't understand why it needs to keep state for
parsing a query.

The best case scenario is it throws the exception below, the worst case is
that it returns a query from a different thread!!!

As far as I can tell, to make this thread safe, I'd have to synchronize
around the OCLHelper, or create a OCL per-thread and use the same
OCLHelper for all calls in a single thread.

Can someone tell me the recommended life-cycle of an OCLHelper and under
what circumstances I should discard it and get a new one? It seems very
light-weight to me, yet offering little case for having multiple instances.

Thanks for your help,
Matthew Watson

Caused by: org.eclipse.ocl.ParserException
at
org.eclipse.ocl.internal.helper.OCLHelperImpl.propagate(OCLH elperImpl.java:403)
at
org.eclipse.ocl.internal.helper.OCLHelperImpl.createQuery(OC LHelperImpl.java:178)
... 54 more
Caused by: java.util.ConcurrentModificationException
at
org.eclipse.emf.common.util.BasicEList$EIterator.checkModCou nt(BasicEList.java:1378)
at
org.eclipse.emf.common.util.BasicEList$EIterator.doNext(Basi cEList.java:1326)
at
org.eclipse.emf.common.util.BasicEList$EIterator.next(BasicE List.java:1312)
at
org.eclipse.ocl.ecore.TypeResolverImpl.findPackage(TypeResol verImpl.java:99)
at
org.eclipse.ocl.ecore.TypeResolverImpl.findPackage(TypeResol verImpl.java:1)
at
org.eclipse.ocl.AbstractTypeResolver.findAdditionalFeaturesP ackage(AbstractTypeResolver.java:732)
at
org.eclipse.ocl.AbstractTypeResolver.hasAdditionalFeatures(A bstractTypeResolver.java:864)
at
org.eclipse.ocl.AbstractTypeResolver.getAdditionalAttributes (AbstractTypeResolver.java:868)
at
org.eclipse.ocl.AbstractEnvironment.getAdditionalAttributes( AbstractEnvironment.java:403)
at
org.eclipse.ocl.AbstractEnvironment.getAdditionalAttributes( AbstractEnvironment.java:397)
at
org.eclipse.ocl.AbstractEnvironment.getAdditionalAttributes( AbstractEnvironment.java:397)
at org.eclipse.ocl.util.TypeUtil.getAttributes(TypeUtil.java:37 5)
at
org.eclipse.ocl.AbstractEnvironment.doLookupProperty(Abstrac tEnvironment.java:627)
at
org.eclipse.ocl.AbstractEnvironment.lookupProperty(AbstractE nvironment.java:608)
at
org.eclipse.ocl.AbstractEnvironment.tryLookupProperty(Abstra ctEnvironment.java:1015)
at
org.eclipse.ocl.AbstractEnvironment.safeTryLookupProperty(Ab stractEnvironment.java:815)
at
org.eclipse.ocl.AbstractEnvironment.lookupImplicitSourceForP roperty(AbstractEnvironment.java:796)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.simpleNameCS(Abst ractOCLAnalyzer.java:2234)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.variableExpCS(Abs tractOCLAnalyzer.java:1840)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.oclExpressionCS(A bstractOCLAnalyzer.java:1810)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.modelPropertyCall ExpCS(AbstractOCLAnalyzer.java:3506)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.propertyCallExpCS (AbstractOCLAnalyzer.java:3157)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.oclExpressionCS(A bstractOCLAnalyzer.java:1808)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.modelPropertyCall ExpCS(AbstractOCLAnalyzer.java:3506)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.propertyCallExpCS (AbstractOCLAnalyzer.java:3157)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.oclExpressionCS(A bstractOCLAnalyzer.java:1808)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.modelPropertyCall ExpCS(AbstractOCLAnalyzer.java:3506)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.propertyCallExpCS (AbstractOCLAnalyzer.java:3157)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.oclExpressionCS(A bstractOCLAnalyzer.java:1808)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.invCS(AbstractOCL Analyzer.java:1303)
at
org.eclipse.ocl.parser.AbstractOCLAnalyzer.invOrDefCS(Abstra ctOCLAnalyzer.java:1282)
at
org.eclipse.ocl.parser.OCLAnalyzer.parseInvOrDefCS(OCLAnalyz er.java:203)
at
org.eclipse.ocl.internal.helper.HelperUtil.parseQuery(Helper Util.java:164)
at
org.eclipse.ocl.internal.helper.OCLHelperImpl.createQuery(OC LHelperImpl.java:175)
Re: OCL Thread Safety [message #67720 is a reply to message #67696] Fri, 13 February 2009 21:40 Go to previous message
Eclipse UserFriend
Originally posted by: cdamus.zeligsoft.com

Hi, matthew,

See some replies in-line, below.

HTH,

Christian


Matthew Watson wrote:
> Hi,
>
> I am attempting to use OCL (1.2.2) in querying and evaluating
> expressions on multiple model instances in multiple threads in a
> high-throughput environment.

Ah, yes. I can see why you would want to perform concurrent OCL operations.

In general, there is no intent to provide thread-safety within the OCL
API. It is left to clients to supply synchronization, as you did with
custom code, or perhaps with a component like EMF Transaction.

What are you currently doing to to protect concurrent access to your
models (apart from OCL)? In EMF, even reading model data has
side-effects that are not thread safe (which is one motivation of the
read-only transactions in EMF Transaction).


> I have stumbled over some thread-safety aspects of queries, but was
> interested in getting the "official" ocl view on how it was intended to
> be used in a multi-threaded environment.
>
> Creating a query every time I want to use it seems like a big overhead
> to me. My Model never changes at runtime, so creating all the queries I
> need on startup and evaluating them again and again is my preferred
> scenario.

Yes. It is intended that you should be able to reuse a query to avoid
repeated parsing. It's just that the synchronization is left to the client.


> There are 2 cases I've found where this is not thread safe.
>
> 1: QueryImpl.evaluate(Object) sets internal state and is not thread-safe.
>
> QueryImpl.evaluate(Object) sets the "self" property on a per-query
> evaluation environment - using the same query in multiple threads soon
> gets an exception warning the self is already set.

Right. And not only "self" ... also local variable declarations in let
expressions and iterator expressions will have this problem. The Query
has an EvaluationEnvironment that, among other responsibilities,
maintains the current variable bindings. This environment will be
shared by all threads, so it has to be synchronized.

It would not be difficult, I shouldn't think, to implement a specialized
EvaluationEnvironment that maintains these values on a per-thread basis
(perhaps wrapping the name-value mapping in a ThreadLocal would be a
simple approach).


> Thus I have had to synchronize on the query (or rather, wrap it in a
> SynchronizedQuery).
>
> This should work as long as I don't set values explicitly in the
> Evaluation Environment (which I don't).

Ah, but it happens implicitly.


> 2: OCLHelperImpl is not thread safe in parsing queries.
>
> This surprises me, I don't understand why it needs to keep state for
> parsing a query.

The OCLHelper creates an Environment that tracks statically defined
variables, such as "self" (besides reflection services on the target
metamodel). As in the evaluation case, these also include
locally-scoped variables defined in let expressions and iterators.


> The best case scenario is it throws the exception below, the worst case
> is that it returns a query from a different thread!!!
>
> As far as I can tell, to make this thread safe, I'd have to synchronize
> around the OCLHelper, or create a OCL per-thread and use the same
> OCLHelper for all calls in a single thread.

The expression parsing and, therefore, synchronization on the OCLHelper
is, at least, only a one-time cost. I think the more severe issue is
the cost of synchronizing the evaluation, as this affects the
responsiveness of your concurrent threads more directly.

I don't think that discarding the OCLHelper would be necessary because,
as you indicated, your model is static.


> Can someone tell me the recommended life-cycle of an OCLHelper and under
> what circumstances I should discard it and get a new one? It seems very
> light-weight to me, yet offering little case for having multiple instances.

The usual reason to create multiple OCLHelpers is to configure them for
parsing expressions in different contexts, which basically amounts to
setting up the "self" variable and operation parameter variables (if
applicable).

But even this is inherently single-threaded (or, at least, synchronized)
because the Environment of a helper is a child of the Environment of the
OCL façade that created it. In a concurrent situation, you would have
to maintain multiple OCL instances, too, because the helper environments
push stuff into it, such as the constraints that they parse (including
definitions of additional operations and attributes).

I would recommend sticking with external synchronization of the
OCLHelper over managing multiple OCL instances, and focusing on making
the EvaluationEnvironment support concurrent evaluation.

That's a cool exception trace. The Environment maintains caches of
stuff that is (lazily) demand-created by the OCL parser, such as
collection types. For example, usage of Set(Foo) in some expression
requires the parser to ensure that the Set(Foo) type exists, and only
once in that environment. The TypeResolver also maintains the
additional operation and attribute definitions that are parsed in the
same environment.


> Thanks for your help,
> Matthew Watson
>
> Caused by: org.eclipse.ocl.ParserException
> at
> org.eclipse.ocl.internal.helper.OCLHelperImpl.propagate(OCLH elperImpl.java:403)
>
> at
> org.eclipse.ocl.internal.helper.OCLHelperImpl.createQuery(OC LHelperImpl.java:178)
>
> ... 54 more
> Caused by: java.util.ConcurrentModificationException
> at
> org.eclipse.emf.common.util.BasicEList$EIterator.checkModCou nt(BasicEList.java:1378)
>
> at
> org.eclipse.emf.common.util.BasicEList$EIterator.doNext(Basi cEList.java:1326)
>
> at
> org.eclipse.emf.common.util.BasicEList$EIterator.next(BasicE List.java:1312)
> at
> org.eclipse.ocl.ecore.TypeResolverImpl.findPackage(TypeResol verImpl.java:99)
>
> at
> org.eclipse.ocl.ecore.TypeResolverImpl.findPackage(TypeResol verImpl.java:1)
> at
> org.eclipse.ocl.AbstractTypeResolver.findAdditionalFeaturesP ackage(AbstractTypeResolver.java:732)
>
> at
> org.eclipse.ocl.AbstractTypeResolver.hasAdditionalFeatures(A bstractTypeResolver.java:864)
>
> at
> org.eclipse.ocl.AbstractTypeResolver.getAdditionalAttributes (AbstractTypeResolver.java:868)
>
> at
> org.eclipse.ocl.AbstractEnvironment.getAdditionalAttributes( AbstractEnvironment.java:403)
>
> at
> org.eclipse.ocl.AbstractEnvironment.getAdditionalAttributes( AbstractEnvironment.java:397)
>
> at
> org.eclipse.ocl.AbstractEnvironment.getAdditionalAttributes( AbstractEnvironment.java:397)
>
> at org.eclipse.ocl.util.TypeUtil.getAttributes(TypeUtil.java:37 5)
> at
> org.eclipse.ocl.AbstractEnvironment.doLookupProperty(Abstrac tEnvironment.java:627)
>
> at
> org.eclipse.ocl.AbstractEnvironment.lookupProperty(AbstractE nvironment.java:608)
>
> at
> org.eclipse.ocl.AbstractEnvironment.tryLookupProperty(Abstra ctEnvironment.java:1015)
>
> at
> org.eclipse.ocl.AbstractEnvironment.safeTryLookupProperty(Ab stractEnvironment.java:815)
>
> at
> org.eclipse.ocl.AbstractEnvironment.lookupImplicitSourceForP roperty(AbstractEnvironment.java:796)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.simpleNameCS(Abst ractOCLAnalyzer.java:2234)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.variableExpCS(Abs tractOCLAnalyzer.java:1840)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.oclExpressionCS(A bstractOCLAnalyzer.java:1810)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.modelPropertyCall ExpCS(AbstractOCLAnalyzer.java:3506)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.propertyCallExpCS (AbstractOCLAnalyzer.java:3157)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.oclExpressionCS(A bstractOCLAnalyzer.java:1808)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.modelPropertyCall ExpCS(AbstractOCLAnalyzer.java:3506)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.propertyCallExpCS (AbstractOCLAnalyzer.java:3157)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.oclExpressionCS(A bstractOCLAnalyzer.java:1808)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.modelPropertyCall ExpCS(AbstractOCLAnalyzer.java:3506)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.propertyCallExpCS (AbstractOCLAnalyzer.java:3157)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.oclExpressionCS(A bstractOCLAnalyzer.java:1808)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.invCS(AbstractOCL Analyzer.java:1303)
>
> at
> org.eclipse.ocl.parser.AbstractOCLAnalyzer.invOrDefCS(Abstra ctOCLAnalyzer.java:1282)
>
> at
> org.eclipse.ocl.parser.OCLAnalyzer.parseInvOrDefCS(OCLAnalyz er.java:203)
> at
> org.eclipse.ocl.internal.helper.HelperUtil.parseQuery(Helper Util.java:164)
> at
> org.eclipse.ocl.internal.helper.OCLHelperImpl.createQuery(OC LHelperImpl.java:175)
>
>
>
>
Previous Topic:problem with OCL.validate(OCLExpression)
Next Topic:[Announce] MDT OCL 1.3.0 I200902131557 is available
Goto Forum:
  


Current Time: Wed Sep 18 22:35:45 GMT 2024

Powered by FUDForum. Page generated in 0.03677 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top