Bug #44
Error during transaction.commit() causes infinite recursion and looping
Start date:
Due date:
% Done:
0%
Estimated time:
Resolution:
fixed
Description
This is svn head (rev <a href="http://mulgara.org/trac/changeset/189">189</a>), i.e. with the new transaction code.
<br/>
<br/>
Here's a small snippet of the stack when the error is triggered:
<br/>
<br/>
at org.objectweb.jotm.TransactionImpl.commit(TransactionImpl.java:222)
<br/>
at org.mulgara.resolver.MulgaraTransaction.terminateTransaction(MulgaraTransaction.java:330)
<br/>
at org.mulgara.resolver.MulgaraTransaction.deactivate(MulgaraTransaction.java:154)
<br/>
at org.mulgara.resolver.MulgaraTransaction.execute(MulgaraTransaction.java:207)
<br/>
<br/>
If commit() throws an exception, implicitRollback() will be invoked at
<br/>
line 333, which in turn call checkActivated() on line 262, which in
<br/>
turn calls implicitRollback() on line 442 because inuse is 0 (from
<br/>
deactivate()).
<br/>
<br/>
At this point things go horribly wrong...
<br/>
<br/>
An easy way to trigger this is run out of disk space where the db
<br/>
resides (e.g. on linux create a fs on a small file and mount using the
<br/>
loop device: 'dd if=/dev/zero of=/tmp/mdb bs=4096 count=1000',
<br/>
'mke2fs /tmp/mdb', 'mount -o loop /tmp/mdb /mnt/disk').
<br/>
<br/>
Updated by Andrae Muys - over 16 years ago
I'll address this next week, for now just comment out the call to checkActivated() - it shouldn't ever fail - for those times it probably manages to anyway, I'll figure what to do there next week.
Updated by ronald - over 16 years ago
Just to confirm: we're talking about commenting out line 263 (as of rev <a href="http://mulgara.org/trac/changeset/192">192</a>), right?
Updated by Andrae Muys - over 16 years ago
Yes.
<br/>
<br/>
try {
<br/>
// checkActivated();
<br/>
rollback = IMPLICIT_ROLLBACK;
<br/>
rollbackCause = cause;
<br/>
failTransaction();
<br/>
return new [[MulgaraTransactionException]]("Transaction in Rollback", cause);
<br/>
} catch (Throwable th) {
<br/>
abortTransaction("Failed to rollback normally", th);
<br/>
throw new [[MulgaraTransactionException]]("Abort failed to throw exception", th);
<br/>
}
<br/>
<br/>
The check is there as a defensive measure as execution should only reach that point if the transaction is activated. Removing it will ensure rollback get's set, which will short-circuit any future call to implicitRollback().
<br/>
<br/>
I'll take a closer look and determine what the permanent fix should be next week.
Updated by ronald - over 16 years ago
I had to make one small additional modification: line 357 needs to
<br/>
be protect with an if:
<br/>
<br/>
try {
<br/>
if (manager != null)
<br/>
manager.transactionComplete(this);
<br/>
} finally {
<br/>
manager = null;
<br/>
inuse = 0;
<br/>
<br/>
This is because on line 335 terminateTransaction() is called recursively,
<br/>
and the third finally clause sets manager to null, so after the
<br/>
terminateTransaction() returns the first time you get a NPE otherwise.
<br/>
<br/>
This is just an FYI in case somebody else needs this fix in the mean
<br/>
time. With these two changes things seem to run well.
<br/>
<br/>
Updated by Andrae Muys - about 16 years ago
Fixed in revision <a href="http://mulgara.org/trac/changeset/207">207</a>