Author: timothyjward Date: Wed Sep 21 08:14:21 2016 New Revision: 1761694 URL: http://svn.apache.org/viewvc?rev=1761694&view=rev Log: ARIES-1616 Force the transaction log to close when Transaction Control shuts down
Modified: aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java aries/trunk/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java Modified: aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java?rev=1761694&r1=1761693&r2=1761694&view=diff ============================================================================== --- aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java (original) +++ aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/Activator.java Wed Sep 21 08:14:21 2016 @@ -143,7 +143,7 @@ public class Activator implements Bundle } boolean cleanUp = true; synchronized (Activator.this) { - if(configuration == newConfig) { + if(configuration == newConfig && open) { txControlImpl = impl; txControlReg = newReg; cleanUp = false; Modified: aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java?rev=1761694&r1=1761693&r2=1761694&view=diff ============================================================================== --- aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java (original) +++ aries/trunk/tx-control/tx-control-service-xa/src/main/java/org/apache/aries/tx/control/service/xa/impl/TransactionControlImpl.java Wed Sep 21 08:14:21 2016 @@ -24,6 +24,7 @@ import static org.apache.aries.tx.contro import static org.apache.aries.tx.control.service.xa.impl.LocalResourceSupport.ENFORCE_SINGLE; import java.io.File; +import java.lang.reflect.Field; import java.util.Dictionary; import java.util.HashMap; import java.util.Hashtable; @@ -202,16 +203,54 @@ public class TransactionControlImpl exte @Override public void close() { - super.close(); - if(recoverableResources != null) { - recoverableResources.close(); - } - if(log != null) { - try { - log.doStop(); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + try { + super.close(); + if(recoverableResources != null) { + recoverableResources.close(); + } + } finally { + if(log != null) { + try { + log.doStop(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // The HOWL log does not reliably close the FlushManager + // and the project hasn't been updated in ten years... + // Do some horrible reflection to force it closed so that + // we don't leak classloaders and memory. + // Note that the thread is daemon, so it won't stop shutdown + try { + Field f = HOWLLog.class.getDeclaredField("logger"); + f.setAccessible(true); + org.objectweb.howl.log.Logger howlLogger = (org.objectweb.howl.log.Logger) f.get(log); + + f = org.objectweb.howl.log.Logger.class.getDeclaredField("bmgr"); + f.setAccessible(true); + Object logBufferManager = f.get(howlLogger); + + f = logBufferManager.getClass().getDeclaredField("flushManager"); + f.setAccessible(true); + Thread flushThread = (Thread) f.get(logBufferManager); + + if(flushThread.isAlive()) { + // Briefly Join this thread in case it is going to stop properly. + // Pick the shorter of 250 milliseconds or twice the flush interval. + int toWait = Math.min(250, 2* log.getFlushSleepTimeMilliseconds()); + flushThread.join(toWait); + + if(flushThread.isAlive()) { + // Still alive after waiting, time to pull the trigger ourselves + flushThread.interrupt(); + + // Let the thread react to interruption + flushThread.join(toWait); + } + } + } catch (Exception e) { + logger.error("An error ocurred while trying to close the HOWL flush thread.", e); + } } } } Modified: aries/trunk/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java?rev=1761694&r1=1761693&r2=1761694&view=diff ============================================================================== --- aries/trunk/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java (original) +++ aries/trunk/tx-control/tx-control-service-xa/src/test/java/org/apache/aries/tx/control/service/xa/impl/TransactionLogTest.java Wed Sep 21 08:14:21 2016 @@ -25,6 +25,7 @@ import static org.junit.Assert.assertTru import static org.osgi.service.transaction.control.TransactionStatus.ROLLED_BACK; import java.io.File; +import java.lang.reflect.Field; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; @@ -37,6 +38,7 @@ import java.util.function.BiConsumer; import javax.sql.XAConnection; import javax.transaction.xa.XAResource; +import org.apache.geronimo.transaction.log.HOWLLog; import org.h2.jdbcx.JdbcDataSource; import org.h2.tools.Server; import org.junit.After; @@ -106,8 +108,10 @@ public class TransactionLogTest { } @After - public void destroy() { + public void destroy() throws Exception { txControl.close(); + + checkLogClosed(txControl); try (Connection conn = dataSource.getConnection()) { conn.createStatement().execute("shutdown immediately"); } catch (SQLException e) { @@ -118,6 +122,37 @@ public class TransactionLogTest { delete(new File("target/recovery-test")); } + private void checkLogClosed(TransactionControlImpl toCheck) throws Exception { + + Field f = TransactionControlImpl.class.getDeclaredField("log"); + f.setAccessible(true); + HOWLLog log = (HOWLLog) f.get(toCheck); + + f = HOWLLog.class.getDeclaredField("logger"); + f.setAccessible(true); + org.objectweb.howl.log.Logger howlLogger = (org.objectweb.howl.log.Logger) f.get(log); + + f = org.objectweb.howl.log.Logger.class.getDeclaredField("bmgr"); + f.setAccessible(true); + Object logBufferManager = f.get(howlLogger); + + f = logBufferManager.getClass().getDeclaredField("flushManager"); + f.setAccessible(true); + Thread flushThread = (Thread) f.get(logBufferManager); + + assertFalse(flushThread.isAlive()); + + f = org.objectweb.howl.log.Logger.class.getDeclaredField("lfmgr"); + f.setAccessible(true); + Object logFileManager = f.get(howlLogger); + + f = logFileManager.getClass().getDeclaredField("eventManagerThread"); + f.setAccessible(true); + Thread eventManagerThread = (Thread) f.get(logFileManager); + + assertFalse(eventManagerThread.isAlive()); + } + private void delete(File file) { if(file.isDirectory()) { for(File f : file.listFiles()) {