Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF-IncQuery » Concurrency in incquery
Concurrency in incquery [message #1352320] Tue, 13 May 2014 12:04 Go to next message
Balázs Grill is currently offline Balázs GrillFriend
Messages: 8
Registered: July 2009
Junior Member
Hello,

We've been experiencing some problems since we switched to tag 0.8.0M3. When the incquery is accessed concurrently from multiple threads, it starts throwing exceptions and causes the whole workbench to freeze.

The situation is as follows:
Our models are contained in projects and there is a view which content is calculated using queries. When the user opens a project, a resourceSet is created, and a job is started to read its content. In the meantime, the view tries to initialize its content and instantiates its queries. The following is the first exception which occurs during initialization of the query:

Thread [main] (Suspended (exception ConcurrentModificationException))
owns: ReteBoundary (id=153)
owns: ReteEngine (id=154)
HashMap$EntryIterator(HashMap$HashIterator<E>).nextEntry() line: not available
HashMap$EntryIterator.next() line: not available
HashMap$EntryIterator.next() line: not available
StandardTable$Column$EntrySetIterator.computeNext() line: 620
StandardTable$Column$EntrySetIterator.computeNext() line: 615
StandardTable$Column$EntrySetIterator(AbstractIterator<T>).tryToComputeNext() line: 141
StandardTable$Column$EntrySetIterator(AbstractIterator<T>).hasNext() line: 136
NavigationHelperImpl.processAllFeatureInstances(EStructuralFeature, IEStructuralFeatureProcessor) line: 289
EMFPatternMatcherRuntimeContext.enumerateDirectBinaryEdgeInstances(Object, IPatternMatcherRuntimeContext$ModelElementPairCrawler) line: 125
EMFPatternMatcherRuntimeContext.enumerateAllBinaryEdgeInstances(Object, IPatternMatcherRuntimeContext$ModelElementPairCrawler) line: 137
ReferenceFeeder.feed() line: 36
ReteBoundary.accessBinaryEdgeRoot(Object) line: 254
ReteContainerCompiler.binaryEdgeTypePlan(Tuple, Object) line: 185
SubPlanProcessor.processConstraint(TypeBinary) line: 135
SubPlanProcessor.dispatchConstraint(EnumerablePConstraint) line: 86
SubPlanProcessor.processEnumerableConstraint(EnumerablePConstraint) line: 58
QuasiTreeLayout$Scaffold.run() line: 81
QuasiTreeLayout.layout(PBody, IOperationCompiler<?>, IPatternMatcherContext) line: 45
EPMBuildScaffold<Collector>.construct(PQuery) line: 53
EPMBuilder<Collector>.construct(PQuery) line: 54
ReteBoundary.construct(PQuery) line: 528
ReteBoundary.accessProduction(PQuery) line: 460
ReteContainerCompiler.patternCallPlan(Tuple, PQuery) line: 157
SubPlanProcessor.processConstraint(PositivePatternCall) line: 131
SubPlanProcessor.dispatchConstraint(EnumerablePConstraint) line: 84
SubPlanProcessor.processEnumerableConstraint(EnumerablePConstraint) line: 58
QuasiTreeLayout$Scaffold.run() line: 81
QuasiTreeLayout.layout(PBody, IOperationCompiler<?>, IPatternMatcherContext) line: 45
EPMBuildScaffold<Collector>.construct(PQuery) line: 53
EPMBuilder<Collector>.construct(PQuery) line: 54
ReteBoundary.construct(PQuery) line: 528
ReteBoundary.accessProduction(PQuery) line: 460
ReteEngine$1.call() line: 178
ReteEngine$1.call() line: 1
NavigationHelperImpl.coalesceTraversals(Callable<V>) line: 971
EMFPatternMatcherRuntimeContext.coalesceTraversals(Callable<V>) line: 86
ReteEngine.constructionWrapper(Callable<Void>) line: 226
ReteEngine.accessMatcher(PQuery) line: 174
ShortnamePathCollisionMatcher(BaseMatcher<Match>).accessMatcher(IncQueryEngineImpl, IQuerySpecification<BaseMatcher<Match>>) line: 71
ShortnamePathCollisionMatcher(BaseMatcher<Match>).<init>(IncQueryEngine, IQuerySpecification<BaseMatcher<Match>>) line: 60
generic.eiq line: 7
generic.eiq line: 7
generic.eiq line: 7
generic.eiq line: 7
ShortnamePathCollisionQuerySpecification(BaseQuerySpecification<Matcher>).getMatcher(IncQueryEngine) line: 68
IncQueryEventSource<Match>.<init>(IncQueryEventRealm, IncQueryEventSourceSpecification<Match>) line: 44
IncQueryEventRealm.createSource(EventSourceSpecification<Match>) line: 50
IncQueryRuleInstanceBuilder<Match>.prepareRuleInstance(RuleInstance<Match>, EventFilter<? super Match>) line: 34
RuleSpecification<EventAtom>.instantiateRule(EventRealm, EventFilter<? super EventAtom>) line: 85
RuleBase.instantiateRule(RuleSpecification<EventAtom>, EventFilter<? super EventAtom>) line: 78
ExecutionSchema(RuleEngine).addRule(RuleSpecification<EventAtom>, EventFilter<? super EventAtom>) line: 113
ObservableCollectionHelper.prepareRuleEngine(IncQueryEngine, RuleSpecification<Match>, EventFilter<Match>) line: 116
ObservablePatternMatchList<Match>.<init>(IQuerySpecification<Matcher>, IncQueryEngine) line: 84
IncQueryObservables.observeMatchesAsList(IQuerySpecification<Matcher>, IncQueryEngine) line: 84

When this happens, the worker thread is currently doing the on-load model traversal:

Thread [Worker-4] (Suspended)
BasicNotifierImpl$EAdapterList<E>.newData(int) line: 108
BasicNotifierImpl$EAdapterList<E>(BasicEList<E>).grow(int) line: 727
BasicNotifierImpl$EAdapterList<E>(BasicEList<E>).addUnique(E) line: 416
BasicNotifierImpl$EAdapterList<E>(AbstractEList<E>).add(E) line: 301
BasicNotifierImpl$EAdapterList<E>.add(E) line: 193
.
.
.
NavigationHelperContentAdapter(EContentAdapter).addAdapter(Notifier) line: 349
NavigationHelperContentAdapter.access$1(NavigationHelperContentAdapter, Notifier) line: 1
NavigationHelperContentAdapter$1.call() line: 297
NavigationHelperContentAdapter$1.call() line: 1
NavigationHelperImpl.coalesceTraversals(Callable<V>) line: 987
NavigationHelperContentAdapter.addAdapter(Notifier) line: 289
NavigationHelperContentAdapter(EContentAdapter).handleContainment(Notification) line: 139
NavigationHelperContentAdapter(EContentAdapter).selfAdapt(Notification) line: 63
NavigationHelperContentAdapter(EContentAdapter).notifyChanged(Notification) line: 40
NavigationHelperContentAdapter.notifyChanged(Notification) line: 201
ARResourceImpl(BasicNotifierImpl).eNotify(Notification) line: 374
ResourceImpl$ContentsEList<E>(NotifyingListImpl<E>).dispatchNotification(Notification) line: 261
ResourceImpl$ContentsEList<E>(NotifyingListImpl<E>).addUnique(E) line: 294
ResourceImpl$ContentsEList<E>(AbstractEList<E>).add(E) line: 301
ARLoad.load(XMLResource, InputStream, Map<?,?>) line: 38
ARResourceImpl(XMLResourceImpl).doLoad(InputStream, Map<?,?>) line: 253
ARResourceImpl(ResourceImpl).load(InputStream, Map<?,?>) line: 1518
ARResourceImpl(ResourceImpl).load(Map<?,?>) line: 1297

Does concurrent calls causes this? Do I need to take extra measures to avoid concurrent calls even when the model is written on one thread? Do I need to delay query initialization until the model is loaded?

Thanks in advance
Balázs Grill;
Re: Concurrency in incquery [message #1352623 is a reply to message #1352320] Tue, 13 May 2014 14:53 Go to previous messageGo to next message
Gabor Bergmann is currently offline Gabor BergmannFriend
Messages: 23
Registered: July 2009
Junior Member
Hi Balázs,

currently there is no support in EMF-IncQuery for multiple threads accessing the same model concurrently. Not even for concurrent reads.

In fact, EMF itself isn't thread-safe either (especially with proxy resolution). See here: http://wiki.eclipse.org/EMF/FAQ#Is_EMF_thread-safe.3F
I suggest that you either (a) access an EMF model from a single thread only, or (b) use an exclusive lock to control access to that model. Using EMF-IncQuery makes no difference.

Hope that helps.
Re: Concurrency in incquery [message #1356594 is a reply to message #1352623] Thu, 15 May 2014 06:19 Go to previous messageGo to next message
Balázs Grill is currently offline Balázs GrillFriend
Messages: 8
Registered: July 2009
Junior Member
In fact, our resourceSet is transactional, therefore all modifications are serialized by a command queue. Do we need to instantiate queries in transactions?
Re: Concurrency in incquery [message #1356621 is a reply to message #1356594] Thu, 15 May 2014 06:34 Go to previous messageGo to next message
Abel Hegedus is currently offline Abel HegedusFriend
Messages: 115
Registered: July 2009
Senior Member
The problem is that the query initialization uses an iterator on the index (see NavigationHelperImpl.processAllFeatureInstances(EStructuralFeature, IEStructuralFeatureProcessor) line: 289) to fill up the Rete network. In the same time, the load modifies the model and the notifications are handled by the index (see NavigationHelperContentAdapter.notifyChanged(Notification) line: 201) and as a result a new element is added to the collection that the iterator is using.

The short answer is yes, you have to either: initialize queries _before_ loading the resource or wait for the initialization after the load is finished.

[Edit:] You may encounter this now as in earlier versions the collection was copied instead of iterated. I'm not sure when the change happened.

[Updated on: Thu, 15 May 2014 06:37]

Report message to a moderator

Re: Concurrency in incquery [message #1356671 is a reply to message #1356621] Thu, 15 May 2014 07:01 Go to previous message
Balázs Grill is currently offline Balázs GrillFriend
Messages: 8
Registered: July 2009
Junior Member
Now this explains everything. I've encapsulated our query initializations into transactions and now it works as expected.

Thanks for the help

Balázs;
Previous Topic:Another "Ambiguous variable type defintions" problem
Next Topic:Use IncQueryObservables outside eclipse context (Rap)
Goto Forum:
  


Current Time: Thu Apr 02 04:52:55 GMT 2015

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

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