You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by jl...@apache.org on 2016/12/03 16:56:07 UTC

[13/50] tomee git commit: TOMEE-1806 patch from Javier Pedrido + ensuring we can find managed connection during eviction

TOMEE-1806 patch from Javier Pedrido + ensuring we can find managed connection during eviction


Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/0fd8e6ca
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/0fd8e6ca
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/0fd8e6ca

Branch: refs/heads/tomee-1.7.x
Commit: 0fd8e6cab662b6f53eddb6c42651b3378a4b62a2
Parents: 446e785
Author: Romain manni-Bucau <rm...@gmail.com>
Authored: Thu May 12 10:10:32 2016 +0200
Committer: Jonathan Gallimore <jo...@jrg.me.uk>
Committed: Mon May 30 21:24:48 2016 +0100

----------------------------------------------------------------------
 .../openejb/resource/AutoConnectionTracker.java |   5 +
 .../GeronimoConnectionManagerFactory.java       | 105 +++++++----
 .../GeronimoConnectionManagerFactoryTest.java   | 184 +++++++++++++++++++
 3 files changed, 261 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/0fd8e6ca/container/openejb-core/src/main/java/org/apache/openejb/resource/AutoConnectionTracker.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/AutoConnectionTracker.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/AutoConnectionTracker.java
index 915e7d9..1c14c5e 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/resource/AutoConnectionTracker.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/AutoConnectionTracker.java
@@ -31,6 +31,7 @@ import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
@@ -38,6 +39,10 @@ public class AutoConnectionTracker implements ConnectionTracker {
     private final ConcurrentMap<ManagedConnectionInfo, ProxyPhantomReference> references = new ConcurrentHashMap<ManagedConnectionInfo, ProxyPhantomReference>();
     private final ReferenceQueue referenceQueue = new ReferenceQueue();
 
+    public Set<ManagedConnectionInfo> connections() {
+        return references.keySet();
+    }
+
     /**
      * Releases any managed connections held by a garbage collected connection proxy.
      *

http://git-wip-us.apache.org/repos/asf/tomee/blob/0fd8e6ca/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoConnectionManagerFactory.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoConnectionManagerFactory.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoConnectionManagerFactory.java
index 20ae9ce..9f22091 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoConnectionManagerFactory.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoConnectionManagerFactory.java
@@ -78,10 +78,19 @@ public class GeronimoConnectionManagerFactory {
     private int poolMaxSize = 10;
     private int poolMinSize;
     private boolean allConnectionsEqual = true;
+    private boolean assumeOneMatch = false;
     private int connectionMaxWaitMilliseconds = 5000;
     private int connectionMaxIdleMinutes = 15;
-    private int validationInterval = -1;
     private ManagedConnectionFactory mcf;
+    private int validationIntervalMs = -1;
+
+    public boolean isAssumeOneMatch() {
+        return assumeOneMatch;
+    }
+
+    public void setAssumeOneMatch(final boolean assumeOneMatch) {
+        this.assumeOneMatch = assumeOneMatch;
+    }
 
     public ManagedConnectionFactory getMcf() {
         return mcf;
@@ -196,19 +205,18 @@ public class GeronimoConnectionManagerFactory {
     }
 
     public int getValidationInterval() {
-        return validationInterval;
+        return validationIntervalMs < 0 ? -1 : (int) TimeUnit.MILLISECONDS.toMinutes(validationIntervalMs);
     }
 
     public void setValidationInterval(final int validationInterval) {
-        this.validationInterval = validationInterval;
+        this.validationIntervalMs = validationInterval < 0 ? -1 : (int) TimeUnit.MINUTES.toMillis(validationInterval);
     }
 
     public void setValidationInterval(final Duration validationInterval) {
         if (validationInterval.getUnit() == null) {
             validationInterval.setUnit(TimeUnit.MINUTES);
         }
-        final long minutes = TimeUnit.MINUTES.convert(validationInterval.getTime(), validationInterval.getUnit());
-        setValidationInterval((int) minutes);
+        validationIntervalMs = (int) validationInterval.getUnit().toMillis(validationInterval.getTime());
     }
 
     public GenericConnectionManager create() {
@@ -234,18 +242,24 @@ public class GeronimoConnectionManagerFactory {
             if (txSupport.isRecoverable()) {
                 throw new OpenEJBRuntimeException("currently recoverable tx support (xa) needs a geronimo tx manager");
             }
-            tm = new SimpleRecoverableTransactionManager(transactionManager);
+            tm = new SimpleRecoverableTransactionManager(transactionManager, name);
         }
 
-        if (validationInterval >= 0 && mcf instanceof ValidatingManagedConnectionFactory) {
-            return new ValidatingGenericConnectionManager(txSupport, poolingSupport,
-                null, new AutoConnectionTracker(), tm,
-                mcf, name, classLoader, validationInterval);
+        final GenericConnectionManager mgr;
+        if (validationIntervalMs >= 0 && mcf instanceof ValidatingManagedConnectionFactory) {
+            if (name == null) {
+                name = getClass().getSimpleName();
+            }
+            mgr = new ValidatingGenericConnectionManager(txSupport, poolingSupport,
+                    null, new AutoConnectionTracker(), tm,
+                    mcf, name, classLoader, validationIntervalMs);
+        } else {
+            mgr = new GenericConnectionManager(txSupport, poolingSupport,
+                    null, new AutoConnectionTracker(), tm,
+                    mcf, name, classLoader);
         }
 
-        return new GenericConnectionManager(txSupport, poolingSupport,
-            null, new AutoConnectionTracker(), tm,
-            mcf, name, classLoader);
+        return mgr;
     }
 
     private TransactionSupport createTransactionSupport() {
@@ -271,12 +285,12 @@ public class GeronimoConnectionManagerFactory {
 
             // unpartitioned pool
             return new SinglePool(poolMaxSize,
-                poolMinSize,
-                connectionMaxWaitMilliseconds,
-                connectionMaxIdleMinutes,
-                allConnectionsEqual,
-                !allConnectionsEqual,
-                false);
+                    poolMinSize,
+                    connectionMaxWaitMilliseconds,
+                    connectionMaxIdleMinutes,
+                    allConnectionsEqual,
+                    !allConnectionsEqual,
+                    assumeOneMatch);
 
         } else if ("by-connector-properties".equalsIgnoreCase(partitionStrategy)) {
 
@@ -287,7 +301,7 @@ public class GeronimoConnectionManagerFactory {
                 connectionMaxIdleMinutes,
                 allConnectionsEqual,
                 !allConnectionsEqual,
-                false,
+                assumeOneMatch,
                 true,
                 false);
         } else if ("by-subject".equalsIgnoreCase(partitionStrategy)) {
@@ -299,19 +313,21 @@ public class GeronimoConnectionManagerFactory {
                 connectionMaxIdleMinutes,
                 allConnectionsEqual,
                 !allConnectionsEqual,
-                false,
+                assumeOneMatch,
                 false,
                 true);
-        } else {
-            throw new IllegalArgumentException("Unknown partition strategy " + partitionStrategy);
         }
+
+        throw new IllegalArgumentException("Unknown partition strategy " + partitionStrategy);
     }
 
     private class SimpleRecoverableTransactionManager implements RecoverableTransactionManager {
         private final TransactionManager delegate;
+        private final String name;
 
-        public SimpleRecoverableTransactionManager(final TransactionManager transactionManager) {
-            delegate = transactionManager;
+        public SimpleRecoverableTransactionManager(final TransactionManager transactionManager, final String name) {
+            this.delegate = transactionManager;
+            this.name = name;
         }
 
         @Override
@@ -320,10 +336,17 @@ public class GeronimoConnectionManagerFactory {
         }
 
         public void registerNamedXAResourceFactory(final NamedXAResourceFactory namedXAResourceFactory) {
+            if ((name == null && namedXAResourceFactory == null || (namedXAResourceFactory != null && namedXAResourceFactory.getName() == null)) ||
+                    (name != null && namedXAResourceFactory != null && name.equals(namedXAResourceFactory.getName()))) {
+                return;
+            }
             throw new UnsupportedOperationException();
         }
 
         public void unregisterNamedXAResourceFactory(final String namedXAResourceFactoryName) {
+            if ((name == null && namedXAResourceFactoryName == null) || (name != null && name.equals(namedXAResourceFactoryName))) {
+                return;
+            }
             throw new UnsupportedOperationException();
         }
 
@@ -382,7 +405,9 @@ public class GeronimoConnectionManagerFactory {
         private final ReadWriteLock lock;
         private final Object pool;
 
-        public ValidatingGenericConnectionManager(final TransactionSupport txSupport, final PoolingSupport poolingSupport, final SubjectSource o, final AutoConnectionTracker autoConnectionTracker, final RecoverableTransactionManager tm, final ManagedConnectionFactory mcf, final String name, final ClassLoader classLoader, final long interval) {
+        public ValidatingGenericConnectionManager(final TransactionSupport txSupport, final PoolingSupport poolingSupport, final SubjectSource o,
+                                                  final AutoConnectionTracker autoConnectionTracker, final RecoverableTransactionManager tm,
+                                                  final ManagedConnectionFactory mcf, final String name, final ClassLoader classLoader, final long interval) {
             super(txSupport, poolingSupport, o, autoConnectionTracker, tm, mcf, name, classLoader);
             validationInterval = interval;
 
@@ -414,14 +439,14 @@ public class GeronimoConnectionManagerFactory {
 
             Object foundPool = null;
             if (current instanceof AbstractSinglePoolConnectionInterceptor) {
-                foundPool = Reflections.get(stack, "pool");
+                foundPool = Reflections.get(current, "pool");
             } else if (current instanceof MultiPoolConnectionInterceptor) {
                 log.warn("validation on stack " + stack + " not supported");
             }
             this.pool = foundPool;
 
             if (pool != null) {
-                validatingTask = new ValidatingTask(current, lock, pool);
+                validatingTask = new ValidatingTask(current, lock, pool, autoConnectionTracker);
             } else {
                 validatingTask = null;
             }
@@ -447,11 +472,18 @@ public class GeronimoConnectionManagerFactory {
             private final ConnectionInterceptor stack;
             private final ReadWriteLock lock;
             private final Object pool;
+            private final AutoConnectionTracker autoConnectionTracker;
 
-            public ValidatingTask(final ConnectionInterceptor stack, final ReadWriteLock lock, final Object pool) {
+            public ValidatingTask(final ConnectionInterceptor stack, final ReadWriteLock lock, final Object pool,
+                                  final AutoConnectionTracker autoConnectionTracker) {
                 this.stack = stack;
                 this.lock = lock;
                 this.pool = pool;
+                this.autoConnectionTracker = autoConnectionTracker;
+
+                if (!SinglePoolConnectionInterceptor.class.isInstance(stack) && !SinglePoolMatchAllConnectionInterceptor.class.isInstance(stack)) {
+                    log.info("stack " + stack + " currently not supported, only AutoConnectionTracker ref will be used for validation");
+                }
             }
 
             @Override
@@ -463,15 +495,17 @@ public class GeronimoConnectionManagerFactory {
                 try {
                     final Map<ManagedConnection, ManagedConnectionInfo> connections;
                     if (stack instanceof SinglePoolConnectionInterceptor) {
-                        connections = new HashMap<ManagedConnection, ManagedConnectionInfo>();
+                        connections = new HashMap<>();
                         for (final ManagedConnectionInfo info : (List<ManagedConnectionInfo>) pool) {
                             connections.put(info.getManagedConnection(), info);
                         }
                     } else if (stack instanceof SinglePoolMatchAllConnectionInterceptor) {
                         connections = (Map<ManagedConnection, ManagedConnectionInfo>) pool;
                     } else {
-                        log.warn("stack " + stack + " currently not supported");
-                        return;
+                        connections = new HashMap<>();
+                    }
+                    for (final ManagedConnectionInfo info : autoConnectionTracker.connections()) {
+                        connections.put(info.getManagedConnection(), info);
                     }
 
                     // destroy invalid connections
@@ -480,7 +514,12 @@ public class GeronimoConnectionManagerFactory {
                             .getInvalidConnections(connections.keySet());
                         if (invalids != null) {
                             for (final ManagedConnection invalid : invalids) {
-                                stack.returnConnection(new ConnectionInfo(connections.get(invalid)), ConnectionReturnAction.DESTROY);
+                                final ManagedConnectionInfo mci = connections.get(invalid);
+                                if (mci != null) {
+                                    stack.returnConnection(new ConnectionInfo(mci), ConnectionReturnAction.DESTROY);
+                                    continue;
+                                }
+                                log.error("Can't find " + invalid + " in " + pool);
                             }
                         }
                     } catch (final ResourceException e) {

http://git-wip-us.apache.org/repos/asf/tomee/blob/0fd8e6ca/container/openejb-core/src/test/java/org/apache/openejb/resource/GeronimoConnectionManagerFactoryTest.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/test/java/org/apache/openejb/resource/GeronimoConnectionManagerFactoryTest.java b/container/openejb-core/src/test/java/org/apache/openejb/resource/GeronimoConnectionManagerFactoryTest.java
new file mode 100644
index 0000000..e2a5646
--- /dev/null
+++ b/container/openejb-core/src/test/java/org/apache/openejb/resource/GeronimoConnectionManagerFactoryTest.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openejb.resource;
+
+import org.apache.geronimo.connector.outbound.GenericConnectionManager;
+import org.apache.geronimo.transaction.manager.TransactionManagerImpl;
+import org.apache.openejb.util.Duration;
+import org.junit.Test;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionEventListener;
+import javax.resource.spi.ConnectionManager;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.LocalTransaction;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.resource.spi.ManagedConnectionMetaData;
+import javax.resource.spi.ValidatingManagedConnectionFactory;
+import javax.security.auth.Subject;
+import javax.transaction.xa.XAResource;
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static java.lang.Thread.sleep;
+import static org.junit.Assert.assertTrue;
+
+public class GeronimoConnectionManagerFactoryTest {
+    @Test // ensure we don't have an exception TOMEE-1806
+    public void eviction() throws Exception {
+        final MyMcf mcf = new MyMcf();
+
+        final GeronimoConnectionManagerFactory factory = new GeronimoConnectionManagerFactory();
+        factory.setValidationInterval(new Duration("1 second"));
+        factory.setTransactionSupport("local");
+        factory.setMcf(mcf);
+        factory.setPooling(true);
+        factory.setPartitionStrategy("none");
+        factory.setTransactionManager(new TransactionManagerImpl());
+        factory.setPoolMinSize(1);
+        factory.setAllConnectionsEqual(false);
+        final GenericConnectionManager mgr = factory.create();
+        mgr.doStart();
+        try {
+            mgr.allocateConnection(mcf, new ConnectionRequestInfo() { // just to use it
+            });
+            sleep(2500);
+            assertTrue(mcf.evicted.get());
+            assertTrue(mcf.destroyed.get());
+        } finally {
+            mgr.doStop();
+        }
+    }
+
+    public static class MyMcf implements ManagedConnectionFactory, ValidatingManagedConnectionFactory {
+        private final Set<ManagedConnection> connections = new HashSet<>();
+        private final AtomicBoolean evicted = new AtomicBoolean(false);
+        private final AtomicBoolean destroyed = new AtomicBoolean(false);
+
+        @Override
+        public Object createConnectionFactory(final ConnectionManager cxManager) throws ResourceException {
+            return null;
+        }
+
+        @Override
+        public Object createConnectionFactory() throws ResourceException {
+            return null;
+        }
+
+        @Override
+        public ManagedConnection createManagedConnection(final Subject subject, final ConnectionRequestInfo cxRequestInfo) throws ResourceException {
+            return new ManagedConnection() {
+                @Override
+                public Object getConnection(Subject subject, ConnectionRequestInfo cxRequestInfo) throws ResourceException {
+                    connections.add(this);
+                    return this;
+                }
+
+                @Override
+                public void destroy() throws ResourceException {
+                    connections.remove(this);
+                    destroyed.set(true);
+                }
+
+                @Override
+                public void cleanup() throws ResourceException {
+                    // no-op
+                }
+
+                @Override
+                public void associateConnection(Object connection) throws ResourceException {
+                    // no-op
+                }
+
+                @Override
+                public void addConnectionEventListener(ConnectionEventListener listener) {
+                    // no-op
+                }
+
+                @Override
+                public void removeConnectionEventListener(ConnectionEventListener listener) {
+                    // no-op
+                }
+
+                @Override
+                public XAResource getXAResource() throws ResourceException {
+                    return null;
+                }
+
+                @Override
+                public LocalTransaction getLocalTransaction() throws ResourceException {
+                    return new LocalTransaction() {
+                        @Override
+                        public void begin() throws ResourceException {
+
+                        }
+
+                        @Override
+                        public void commit() throws ResourceException {
+
+                        }
+
+                        @Override
+                        public void rollback() throws ResourceException {
+
+                        }
+                    };
+                }
+
+                @Override
+                public ManagedConnectionMetaData getMetaData() throws ResourceException {
+                    return null;
+                }
+
+                @Override
+                public void setLogWriter(PrintWriter out) throws ResourceException {
+                    // no-op
+                }
+
+                @Override
+                public PrintWriter getLogWriter() throws ResourceException {
+                    return null;
+                }
+            };
+        }
+
+        @Override
+        public ManagedConnection matchManagedConnections(final Set connectionSet, final Subject subject,
+                                                         final ConnectionRequestInfo cxRequestInfo) throws ResourceException {
+            return null;
+        }
+
+        @Override
+        public void setLogWriter(PrintWriter out) throws ResourceException {
+            // no-op
+        }
+
+        @Override
+        public PrintWriter getLogWriter() throws ResourceException {
+            return null;
+        }
+
+        @Override
+        public Set getInvalidConnections(final Set connectionSet) throws ResourceException {
+            evicted.set(true);
+            return connections;
+        }
+    }
+}