Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » EMF "Technology" (Ecore Tools, EMFatic, etc)  » [EMFStore] command stack notification storms
[EMFStore] command stack notification storms [message #1162611] Wed, 30 October 2013 13:53 Go to next message
Scott Dybiec is currently offline Scott DybiecFriend
Messages: 148
Registered: July 2009
Senior Member
My application makes use of a CommandStackListener to update
persistence-related actions --- Save, SaveAs, etc.

Upon startup of the application that has several models loaded in to
EMFStore, I'm seeing huge numbers of commands being executed (many
thousands). When I trace them back I found that even getters like this
one are executed using commands.

A related issue is looping. In some cases, my action update methods end
up calling basic getters like ESLocalProject.getProjectName(), which in
turn creates another command, which invokes the CommandStackListener,
and so on creating a loop.

Is there another application pattern I should be using with EMFStore?
Should I be going around the external API and using the internal API
instead.

org.eclipse.emf.emfstore.internal.client.model.impl.api.ESLocalProjectImpl:

/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.client.ESProject#getProjectName()
*/
public String getProjectName() {
return RunESCommand.runWithResult(new Callable<String>() {
public String call() throws Exception {
return toInternalAPI().getProjectName();
}
});
}
Re: [EMFStore] command stack notification storms [message #1164338 is a reply to message #1162611] Thu, 31 October 2013 16:04 Go to previous messageGo to next message
Maximilian Koegel is currently offline Maximilian KoegelFriend
Messages: 253
Registered: July 2009
Senior Member
Hi Scott,

thank you for your report! Comments inline...
> Upon startup of the application that has several models loaded in to
> EMFStore, I'm seeing huge numbers of commands being executed (many
> thousands). When I trace them back I found that even getters like this
> one are executed using commands.
I would expect a couple of commands per adding one model. Is it many
models or many EObjects that you add? Does it slow down your start-up
significantly?

> A related issue is looping. In some cases, my action update methods end
> up calling basic getters like ESLocalProject.getProjectName(), which in
> turn creates another command, which invokes the CommandStackListener,
> and so on creating a loop.
> Is there another application pattern I should be using with EMFStore?
> Should I be going around the external API and using the internal API
> instead.
The actions are UI actions I assume? Do you want to track if there are
changes to be saved locally or changes pending to be synchronized with
the server? A client could have pending changes for the server but still
everything saved locally. For the following I assume you want to track
the clients local save state:
I think it would be a better to track changes to the dirty state of a
project differently. You could register a
org.eclipse.emf.emfstore.internal.client.observer.SaveStateChangedObserver
with ESWorkspaceProviderImpl.getObserverBus().register(observer) to be
notified about changes in the save state of a project.
Let me know if I got your wrong here.

Hope this helps!

Cheers,
Maximilian


--
Maximilian Kögel

Get Professional Eclipse Support: http://eclipsesource.com/munich
Re: [EMFStore] command stack notification storms [message #1164482 is a reply to message #1164338] Thu, 31 October 2013 18:11 Go to previous messageGo to next message
Scott Dybiec is currently offline Scott DybiecFriend
Messages: 148
Registered: July 2009
Senior Member
Yes, the appl is tracking local save state.

I found the source of the storm to be the
ESLocalProject.getProjectName() call.

First as little background. To make naming, identifying and accessing
model element more user friendly, I have grafted a virtual project
hierarchical directory structure on top of EMFStore's flat model element
project space. This project directory model is modeled in Ecore
(naturally!) and an instance of this model is stored as a model element
in each project. As you can imagine with all access to model elements at
startup going through this project directory there were lots of calls to
ESLocalProject.getProjectName(). By modifying the
ESLocalProject.getProjectName() method to eliminate the Command creation
from this API method, both the looping and storms problems went away. Is
the ESCommand creation necessary for this getter method? If not, I'd
like to request that you remove it.

Since my application has to use both file-based XMI resources as well as
EMFStore resources, if possible I'd prefer to use the same code to
monitor local save state ---- a CommandStackListener in this case. If
that really won't work, then I'll adopt the SaveStateChangedObserver.

Lastly, is there any thought in creating a feature to support a
hierarchical naming structure similar to my project directory idea on
top of EMFStore?

Scott

On 10/31/2013 12:04 PM, Maximilian Koegel wrote:
> Hi Scott,
>
> thank you for your report! Comments inline...
>> Upon startup of the application that has several models loaded in to
>> EMFStore, I'm seeing huge numbers of commands being executed (many
>> thousands). When I trace them back I found that even getters like this
>> one are executed using commands.
> I would expect a couple of commands per adding one model. Is it many
> models or many EObjects that you add? Does it slow down your start-up
> significantly?
>
>> A related issue is looping. In some cases, my action update methods end
>> up calling basic getters like ESLocalProject.getProjectName(), which in
>> turn creates another command, which invokes the CommandStackListener,
>> and so on creating a loop.
>> Is there another application pattern I should be using with EMFStore?
>> Should I be going around the external API and using the internal API
>> instead.
> The actions are UI actions I assume? Do you want to track if there are
> changes to be saved locally or changes pending to be synchronized with
> the server? A client could have pending changes for the server but still
> everything saved locally. For the following I assume you want to track
> the clients local save state:
> I think it would be a better to track changes to the dirty state of a
> project differently. You could register a
> org.eclipse.emf.emfstore.internal.client.observer.SaveStateChangedObserver
> with ESWorkspaceProviderImpl.getObserverBus().register(observer) to be
> notified about changes in the save state of a project.
> Let me know if I got your wrong here.
>
> Hope this helps!
>
> Cheers,
> Maximilian
>
>
Re: [EMFStore] command stack notification storms [message #1170478 is a reply to message #1164482] Mon, 04 November 2013 17:20 Go to previous messageGo to next message
Edgar Mueller is currently offline Edgar MuellerFriend
Messages: 89
Registered: March 2011
Member
Hi Scott,

Comments inline.

> Yes, the appl is tracking local save state.
>
> I found the source of the storm to be the
> ESLocalProject.getProjectName() call.
>
> First as little background. To make naming, identifying and accessing
> model element more user friendly, I have grafted a virtual project
> hierarchical directory structure on top of EMFStore's flat model element
> project space. This project directory model is modeled in Ecore
> (naturally!) and an instance of this model is stored as a model element
> in each project. As you can imagine with all access to model elements at
> startup going through this project directory there were lots of calls to
> ESLocalProject.getProjectName(). By modifying the
> ESLocalProject.getProjectName() method to eliminate the Command creation
> from this API method, both the looping and storms problems went away. Is
> the ESCommand creation necessary for this getter method? If not, I'd
> like to request that you remove it.

The command wrapping happens because we'd like to ensure that getters
work as expected when using EMFStore in conjunction with EMF
Transaction. Otherwise it would be possible to change the project's name
while someone is reading it.
I'm afraid that we won't change this behaviour and that you either have
to stick with using the internal API, or as Max suggested, using the
SaveStateChangedObserver. The latter currently is internal API but it
would be no problem to make it part of the public API.

>
> Since my application has to use both file-based XMI resources as well as
> EMFStore resources, if possible I'd prefer to use the same code to
> monitor local save state ---- a CommandStackListener in this case. If
> that really won't work, then I'll adopt the SaveStateChangedObserver.
>
> Lastly, is there any thought in creating a feature to support a
> hierarchical naming structure similar to my project directory idea on
> top of EMFStore?

Please open up a feature request in Bugzilla:
https://bugs.eclipse.org/bugs/enter_bug.cgi?product=EMFStore

Thanks!

Cheers,
Edgar


--
Edgar Mueller

Get Professional Eclipse Support: http://eclipsesource.com/munich
Re: [EMFStore] command stack notification storms [message #1170874 is a reply to message #1170478] Mon, 04 November 2013 23:21 Go to previous messageGo to next message
Scott Dybiec is currently offline Scott DybiecFriend
Messages: 148
Registered: July 2009
Senior Member
Edgar,

I see the need for supporting transactional access to EMFStore and
understand your design decision. If a command is created even for
reads, then making the SaveStateChangedObserver part of the public API
is quite important.

However, I don't think that the TransactionalEditingDomain requires a
command to maintain exclusive access during reads. This pattern should work:

public T runReadTransaction(RunnableWithResult<T> runnable)
throws InterruptedException {
TransactionalEditingDomain domain = (TransactionalEditingDomain)
getEditingDomain();
domain.runExclusive(runnable);
return runnable.getResult();
}

I ran into a similar problem with my application's support for
TransactionalEditingDomain, but opted for a solution that keeps access
lightweight for client's that don't need to support multi-threaded
access or those that want to manage the locking themselves outside of
the TransactionalEditingDomain.

Not sure, but perhaps the TransactionRunnerFactory pattern below could
be adapted to provide EMFStore-based applications with a way to choose
the transactional quality of service (TransactionManagementMethod),
while avoiding the creation of commands for reads.

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.edit.command.ChangeCommand;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.RunnableWithResult;
import org.eclipse.emf.transaction.TransactionalEditingDomain;

public abstract class PersistenceManager implements IPersistenceManager {

private static Logger logger =
LogManager.getLogger(PersistenceManager.class);

protected TransactionManagementMethod transactionManagementMethod;
protected AdapterFactoryEditingDomain editingDomain;
protected EClass rootModelEClass;
private ReadWriteLock lock = new ReentrantReadWriteLock();


public PersistenceManager(EClass rootModelEClass,
TransactionManagementMethod transactionManagementMethod) {
super();
this.transactionManagementMethod = transactionManagementMethod;
this.rootModelEClass = rootModelEClass;
}


public interface ITransactionRunner<T> {
public T runReadTransaction(RunnableWithResult<T> runnable) throws
InterruptedException;

public void runWriteTransaction(Runnable runnable);
}

public class TransactionRunnerFactory<T> {
public ITransactionRunner<T> createTransactionRunner() {
ITransactionRunner<T> runner;
switch (transactionManagementMethod) {
case NON_TRANSACTIONAL:
runner = new ITransactionRunner<T>() {

@Override
public void runWriteTransaction(final Runnable runnable) {
Command changeCommand = new ChangeCommand(getEditingDomain()
.getResourceSet()) {
@Override
protected void doExecute() {
runnable.run();
}
};
getEditingDomain().getCommandStack().execute(changeCommand);
}

@Override
public T runReadTransaction(RunnableWithResult<T> runnable) {
runnable.run();
return runnable.getResult();
}
};
break;
case READ_WRITE_LOCK:
runner = new ITransactionRunner<T>() {

@Override
public void runWriteTransaction(final Runnable runnable) {
lock.writeLock().lock();
try {
Command changeCommand = new ChangeCommand(getEditingDomain()
.getResourceSet()) {
@Override
protected void doExecute() {
runnable.run();
}
};
getEditingDomain().getCommandStack().execute(changeCommand);
} finally {
lock.writeLock().unlock();
}
}

@Override
public T runReadTransaction(RunnableWithResult<T> runnable) {
lock.readLock().lock();
try {
runnable.run();
} finally {
lock.readLock().unlock();
}
return runnable.getResult();
}
};
break;
case TRANSACTIONAL_EDITING_DOMAIN:
runner = new ITransactionRunner<T>() {

@Override
public void runWriteTransaction(final Runnable runnable) {
TransactionalEditingDomain domain = (TransactionalEditingDomain)
getEditingDomain();
Command cmd = new RecordingCommand(domain) {
@Override
protected void doExecute() {
runnable.run();
}
};
domain.getCommandStack().execute(cmd);
}

@Override
public T runReadTransaction(RunnableWithResult<T> runnable)
throws InterruptedException {
TransactionalEditingDomain domain = (TransactionalEditingDomain)
getEditingDomain();
domain.runExclusive(runnable);
return runnable.getResult();
}
};
break;
default:
logger.error("Unsupported Transaction method: " +
transactionManagementMethod);
runner = null;
}
return runner;
}
}

public void runWriteTransaction(Runnable runnable) {
TransactionRunnerFactory<Object> factory = new
TransactionRunnerFactory<Object>();
ITransactionRunner<Object> runner = factory.createTransactionRunner();
runner.runWriteTransaction(runnable);
}

public <T> T runReadTransaction(RunnableWithResult<T> runnable) throws
InterruptedException {
TransactionRunnerFactory<T> factory = new TransactionRunnerFactory<T>();
ITransactionRunner<T> runner = factory.createTransactionRunner();
return runner.runReadTransaction(runnable);
}

/*
* (non-Javadoc)
*
* @see
com.humanfactor.emf.emodel.manager.IModelManager#getAdapterFactory()
*/
@Override
public ComposedAdapterFactory getAdapterFactory() {
return (ComposedAdapterFactory) getEditingDomain().getAdapterFactory();
}

public ResourceSet getResourceSet() {
return getEditingDomain().getResourceSet();
}

public MonitoredCommandStack getCommandStack() {
return (MonitoredCommandStack) getEditingDomain().getCommandStack();
}

public TransactionManagementMethod getTransactionManagementMethod() {
return transactionManagementMethod;
}

}


On 11/4/2013 12:20 PM, Edgar Mueller wrote:
> Hi Scott,
>
> Comments inline.
>
>> Yes, the appl is tracking local save state.
>>
>> I found the source of the storm to be the
>> ESLocalProject.getProjectName() call.
>>
>> First as little background. To make naming, identifying and accessing
>> model element more user friendly, I have grafted a virtual project
>> hierarchical directory structure on top of EMFStore's flat model element
>> project space. This project directory model is modeled in Ecore
>> (naturally!) and an instance of this model is stored as a model element
>> in each project. As you can imagine with all access to model elements at
>> startup going through this project directory there were lots of calls to
>> ESLocalProject.getProjectName(). By modifying the
>> ESLocalProject.getProjectName() method to eliminate the Command creation
>> from this API method, both the looping and storms problems went away. Is
>> the ESCommand creation necessary for this getter method? If not, I'd
>> like to request that you remove it.
>
> The command wrapping happens because we'd like to ensure that getters
> work as expected when using EMFStore in conjunction with EMF
> Transaction. Otherwise it would be possible to change the project's name
> while someone is reading it.
> I'm afraid that we won't change this behaviour and that you either have
> to stick with using the internal API, or as Max suggested, using the
> SaveStateChangedObserver. The latter currently is internal API but it
> would be no problem to make it part of the public API.
>
>>
>> Since my application has to use both file-based XMI resources as well as
>> EMFStore resources, if possible I'd prefer to use the same code to
>> monitor local save state ---- a CommandStackListener in this case. If
>> that really won't work, then I'll adopt the SaveStateChangedObserver.
>>
>> Lastly, is there any thought in creating a feature to support a
>> hierarchical naming structure similar to my project directory idea on
>> top of EMFStore?
>
> Please open up a feature request in Bugzilla:
> https://bugs.eclipse.org/bugs/enter_bug.cgi?product=EMFStore
>
> Thanks!
>
> Cheers,
> Edgar
>
>
Re: [EMFStore] command stack notification storms [message #1172079 is a reply to message #1170874] Tue, 05 November 2013 17:37 Go to previous messageGo to next message
Edgar Mueller is currently offline Edgar MuellerFriend
Messages: 89
Registered: March 2011
Member
Hi Scott,

comments inline

> I see the need for supporting transactional access to EMFStore and
> understand your design decision. If a command is created even for
> reads, then making the SaveStateChangedObserver part of the public API
> is quite important.
Ok, we'll make the observer part of the public API then in the next release.

> However, I don't think that the TransactionalEditingDomain requires a
> command to maintain exclusive access during reads. This pattern should
> work:
Yes, this would work, but it would also add a dependency to EMF
transaction. Currently, the actual editing domain in use is completely
transparent to EMFStore . In fact, transaction support is gained by
adding a single plugin (org.eclipse.emf.emfstore.client.transaction).

We'll discuss your proposed pattern and see if we can come up with a
solution which would not make it necessary to add a EMF transaction
dependency to the core, but I don't think that an actual solution will
make it anytime soon into a release.

Cheers,
Edgar

--
Edgar Mueller

Get Professional Eclipse Support: http://eclipsesource.com/munich
Re: [EMFStore] command stack notification storms [message #1172200 is a reply to message #1172079] Tue, 05 November 2013 19:25 Go to previous message
Scott Dybiec is currently offline Scott DybiecFriend
Messages: 148
Registered: July 2009
Senior Member
Like your ESEditingDomainProvider extension, perhaps the
TransactionRunnerFactory could be an extension, making the dependency on
EMF Transaction optional.

Scott

On 11/5/2013 12:37 PM, Edgar Mueller wrote:
> Hi Scott,
>
> comments inline
>
>> I see the need for supporting transactional access to EMFStore and
>> understand your design decision. If a command is created even for
>> reads, then making the SaveStateChangedObserver part of the public API
>> is quite important.
> Ok, we'll make the observer part of the public API then in the next
> release.
>
>> However, I don't think that the TransactionalEditingDomain requires a
>> command to maintain exclusive access during reads. This pattern should
>> work:
> Yes, this would work, but it would also add a dependency to EMF
> transaction. Currently, the actual editing domain in use is completely
> transparent to EMFStore . In fact, transaction support is gained by
> adding a single plugin (org.eclipse.emf.emfstore.client.transaction).
>
> We'll discuss your proposed pattern and see if we can come up with a
> solution which would not make it necessary to add a EMF transaction
> dependency to the core, but I don't think that an actual solution will
> make it anytime soon into a release.
>
> Cheers,
> Edgar
>
Previous Topic:[EMFStore] Commit failed
Next Topic:[EMF][Teneo] Order of children in references
Goto Forum:
  


Current Time: Fri Apr 19 23:23:11 GMT 2024

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

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

Back to the top