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()) {


Reply via email to