[Transaction] Lifecycle events for nested transactions [message #1828193] |
Wed, 03 June 2020 14:42 |
Felix Dorner Messages: 392 Registered: December 2015 |
Senior Member |
|
|
Hi,
I am confused about this documentation vs behaviour discrepancy:
The doc for TransactionalEditingDomainListener.transactionStarted() states:
"Signals that a transaction has been activated. This event is not sent for nested transactions, nor for a transaction'sresumption from the yielded state. "
Now, if I run a write command which triggers a precommit command, the order of received events is:
Start Start Stop Stop. So, no matter how I try to think through, this looks like a bug, either in code or documentation:
A precommit transaction is either nested or not:
a) If a precommit transaction is a nested transaction, then there should only be one start/stop notification (or the documentation is wrong)
b) If a precommit transaction is not a nested transaction, then the order should be
start stop start stop
Am I missing something?
For my specific usecase, I only want to know if a transaction is active or not, so I can still do that by maintaining a stack, where start events push, and stop events pop, so no dealbreaker, but still it feels weird.
|
|
|
Re: [Transaction] Lifecycle events for nested transactions [message #1828196 is a reply to message #1828193] |
Wed, 03 June 2020 15:24 |
|
Hi, Felix,
That was the intention initially, that the started/closed events were only sent for root transactions. And the TransactionImpl::start() method looks like it will only send the started event for a root transaction.
Is it possible that you have a transaction implementation that overrides this? Or that you actually have two different editing domains, each with a root transaction?
Or perhaps the nested transactions involved in the pre-commit processing are a special case that for whatever reason does notify. Do you see the same pattern of notifications for a nested "user transaction"? (i.e., one created explicitly by the application or perhaps indirectly via nested AbstractEMFOperations)
HTH,
Christian
|
|
|
Re: [Transaction] Lifecycle events for nested transactions [message #1828218 is a reply to message #1828196] |
Thu, 04 June 2020 09:17 |
Felix Dorner Messages: 392 Registered: December 2015 |
Senior Member |
|
|
No, no special cases here, single simple test.
It really seems that the documentation does not apply to the precommit transactions. TransactionImpl.deactivate() sets activeTransaction to null, then processes precommits, and since active transaction is null, a new Transaction is started, triggering the second start notification. Only after that. Here's a stack that stops at the second received start event:
LifeCycleTests$2.transactionStarted(TransactionalEditingDomainEvent) line: 48
TransactionalEditingDomainImpl$LifecycleImpl.fireLifecycleEvent(int, Transaction) line: 1377
TransactionalEditingDomainImpl$LifecycleImpl.transactionStarted(InternalTransaction) line: 1418
TransactionImpl.start() line: 268
TransactionalEditingDomainImpl.startTransaction(boolean, Map<?,?>) line: 424
TransactionalEditingDomainImpl.runExclusive(Runnable) line: 321
TransactionalEditingDomainImpl.postcommit(InternalTransaction) line: 771
TransactionalEditingDomainImpl.deactivate(InternalTransaction) line: 543
EMFCommandTransaction(TransactionImpl).close() line: 712
EMFCommandTransaction(TransactionImpl).commit() line: 474
|
|
|
Re: [Transaction] Lifecycle events for nested transactions [message #1828224 is a reply to message #1828218] |
Thu, 04 June 2020 11:25 |
Felix Dorner Messages: 392 Registered: December 2015 |
Senior Member |
|
|
Sorry, my description is plain wrong. A precommit listener isn't even needed. It's the postcommit execution that causes the nested start/stop cycle. I just realized that from looking at the stack in my previous comment. The good thing about this, is the example gets even simpler:
class LifeCycleTests {
@Test
void testPostCommitLifeCycle() {
TransactionalEditingDomain domain = new TransactionalEditingDomainImpl(new AdapterFactoryImpl());
Lifecycle lc = TransactionUtil.getAdapter(domain, Lifecycle.class);
lc.addTransactionalEditingDomainListener(new TransactionalEditingDomainListenerImpl() {
@Override
public void transactionClosed(TransactionalEditingDomainEvent event) {
System.out.println("closed " + event + " readOnly: " + event.getTransaction().isReadOnly());
}
@Override
public void transactionStarted(TransactionalEditingDomainEvent event) {
System.out.println("start " + event + " readOnly: " + event.getTransaction().isReadOnly());
}
});
domain.getCommandStack().execute(new RecordingCommand(domain) {
@Override
protected void doExecute() {
domain.getResourceSet().getResources().add(new ResourceImpl());
}
});
}
}
This prints out
tart org.eclipse.emf.transaction.TransactionalEditingDomainEvent[source=org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl@6042b613] readOnly: false
start org.eclipse.emf.transaction.TransactionalEditingDomainEvent[source=org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl@6042b613] readOnly: true
closed org.eclipse.emf.transaction.TransactionalEditingDomainEvent[source=org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl@6042b613] readOnly: true
closed org.eclipse.emf.transaction.TransactionalEditingDomainEvent[source=org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl@6042b613] readOnly: false
So probably you can say: A postcommit transaction is a root transaction, and because of that, I get the second start, just the order in which the start/close are dispached is confusing.
[Updated on: Thu, 04 June 2020 11:25] Report message to a moderator
|
|
|
Re: [Transaction] Lifecycle events for nested transactions [message #1828225 is a reply to message #1828224] |
Thu, 04 June 2020 11:30 |
|
Hi, Felix,
Thanks for looking into this in such detail. This makes sense. My memory is now very fuzzy after the passage of years, but I do recall that it necessary for the read-only transaction that notifies post-commit listeners to be a root (it is *post* commit, after all) but also that the application in which this API had its origins needed notification of closure of the original transaction only after all post-commit processing had completed.
So, yes, this is an exceptional case vis-a-vis the listener API documentation that you originally cited, which IMO should be amended to call it out. I should have done that a decade ago :-/
Thanks!
Christian
|
|
|
|
Powered by
FUDForum. Page generated in 0.06484 seconds