Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TransactionLogAppender's FileChannel is closed on interrupt and never reopened #45

Open
tbilles opened this issue Jul 9, 2015 · 5 comments

Comments

@tbilles
Copy link

tbilles commented Jul 9, 2015

When an interrupt happens on a thread during writing the transaction log, the underlying FileChannel is closed as a result. Any further use will throw a java.nio.channels.ClosedChannelException rendering the transaction manager unusable since the transaction logs are never reopened. The main issue here is that no other threads can use it any more.

Are there any solutions to situations like this?

Caused by: org.hibernate.TransactionException: JTA commit failed: 
        at org.hibernate.engine.transaction.internal.jta.JtaTransaction.doCommit(JtaTransaction.java:157) ~[hibernate-core.jar:4.3.8.Final]
        at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:180) ~[hibernate-core.jar:4.3.8.Final]
        ... 19 common frames omitted
Caused by: bitronix.tm.internal.BitronixSystemException: error logging status
        at bitronix.tm.BitronixTransaction.setStatus(BitronixTransaction.java:409) ~[btm.jar:3.0.0-SNAPSHOT]
        at bitronix.tm.BitronixTransaction.setStatus(BitronixTransaction.java:387) ~[btm.jar:3.0.0-SNAPSHOT]
        at bitronix.tm.twopc.Preparer.prepare(Preparer.java:64) ~[btm.jar:3.0.0-SNAPSHOT]
        at bitronix.tm.BitronixTransaction.commit(BitronixTransaction.java:281) ~[btm.jar:3.0.0-SNAPSHOT]
        at bitronix.tm.BitronixTransactionManager.commit(BitronixTransactionManager.java:183) ~[btm.jar:3.0.0-SNAPSHOT]
        at org.hibernate.engine.transaction.internal.jta.JtaTransaction.doCommit(JtaTransaction.java:152) ~[hibernate-core.jar:4.3.8.Final]
        ... 20 common frames omitted
Caused by: java.nio.channels.ClosedChannelException: null
        at sun.nio.ch.FileChannelImpl.ensureOpen(FileChannelImpl.java:99) ~[na:1.7.0_51]
        at sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:717) ~[na:1.7.0_51]
        at bitronix.tm.journal.TransactionLogHeader.setPosition(TransactionLogHeader.java:205) ~[btm.jar:3.0.0-SNAPSHOT]
        at bitronix.tm.journal.TransactionLogAppender.writeLog(TransactionLogAppender.java:154) ~[btm.jar:3.0.0-SNAPSHOT]
        at bitronix.tm.journal.DiskJournal.log(DiskJournal.java:144) ~[btm.jar:3.0.0-SNAPSHOT]
        at bitronix.tm.BitronixTransaction.setStatus(BitronixTransaction.java:398) ~[btm.jar:3.0.0-SNAPSHOT]
        ... 25 common frames omitted
palacsint pushed a commit to palacsint/btm that referenced this issue Jul 20, 2015
When an interrupt happened on a thread during writing the transaction
log, the underlying FileChannel was closed as a result. Any further
use (even from another threads) threw a
java.nio.channels.ClosedChannelException rendering the transaction
manager unusable since the transaction logs were never reopened. This
commit changes this behavior, log file operations reopen the file if
it was closed by an interrupt of another thread.

fixes scalar-labs#45

Commit by Tibor Billes, Miklós Karakó, Balázs Póka
palacsint pushed a commit to palacsint/btm that referenced this issue Jul 20, 2015
When an interrupt happened on a thread during writing the transaction
log, the underlying FileChannel was closed as a result. Any further
use (even from another threads) threw a
java.nio.channels.ClosedChannelException rendering the transaction
manager unusable since the transaction logs were never reopened. This
commit changes this behavior, log file operations reopen the file if
it was closed by an interrupt of another thread.

fixes scalar-labs#45

Commit by Tibor Billes, Miklós Karakó, Balázs Póka
palacsint pushed a commit to palacsint/btm that referenced this issue Jul 21, 2015
When an interrupt happened on a thread during writing the transaction
log, the underlying FileChannel was closed as a result. Any further
use (even from another threads) threw a
java.nio.channels.ClosedChannelException rendering the transaction
manager unusable since the transaction logs were never reopened. This
commit changes this behavior, log file operations reopen the file if
it was closed by an interrupt of another thread.

fixes scalar-labs#45

Commit by Tibor Billes, Miklós Karakó, Balázs Póka
palacsint pushed a commit to palacsint/btm that referenced this issue Jul 21, 2015
When an interrupt happened on a thread during writing the transaction
log, the underlying FileChannel was closed as a result. Any further
use (even from another threads) threw a
java.nio.channels.ClosedChannelException rendering the transaction
manager unusable since the transaction logs were never reopened. This
commit changes this behavior, log file operations reopen the file if
it was closed by an interrupt of another thread.

fixes scalar-labs#45

Commit by Tibor Billes, Miklós Karakó, Balázs Póka
@krokodylowy
Copy link

According to old "Multithreaded Programming with JAVA™ Technology" avoid interruption and cancellation if at all possible.
But sometimes we can override Future.cancel(), Therad.interrupt() or SecurityManager methods and do some things in transaction manager before thread exit.
So the question is what we can do before interruption and closed channel occur?
Does TransactionManagerServices.getTransactionManager().rollback(); or something else is correct way to stop permanent fail of transaction log?

@lorban
Copy link
Contributor

lorban commented Feb 23, 2016

There is an ugly workaround that would work: when you get such ClosedChannelException - which can be done by checking the root cause of the exception - clearing the interrupt flag then closing and reopening the disk journal will make BTM resume where it left, ie:

    try {
      ...
    } catch (org.hibernate.TransactionException e) {
      Throwable rootCause = null;
      while (rootCause != e.getCause()) {
        rootCause = e.getCause();
      }
      if (rootCause instanceof ClosedChannelException) {
        if (Thread.interrupted()) { // will also clear interrupted flag
          TransactionManagerServices.getJournal().close();
          TransactionManagerServices.getJournal().open();
        }
      }
      throw e;
    }

You'll get some error in the logs complaining that the journal couldn't be properly closed but all aborted transactions should be recovered and new ones should start flowing again happily.

This is not ideal, but should safely work around the problem.

@krokodylowy
Copy link

Thanks. We will try.

baptistemesta pushed a commit to bonitasoft/bonita-engine that referenced this issue Nov 12, 2016
threadPoolExecutor.shutdownNow() that is too brutal
See scalar-labs/btm#45 for explainations...
educhastenier added a commit to bonitasoft/bonita-engine that referenced this issue Oct 30, 2017
threadPoolExecutor.shutdownNow() that is too brutal
See scalar-labs/btm#45 for explainations...
@ghost
Copy link

ghost commented Jun 4, 2018

We had the same issue. @lorban , thank you for the solution.
But as for me it is not an ideal solution. It would be great if some kind of fix can be added into Bitronix code (somewhere into bitronix.tm.journal.DiskJournal or another place).

@lorban
Copy link
Contributor

lorban commented Jun 4, 2018

The team behind BTM moved off to other horizons, BTM has been unmaintained for a few years now and is still looking for someone to take over its maintenance.

For as long as this will be the case, no bug fixes nor new features will be made.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants