ARTEMIS-210 count references
It is possible for the closure of one resource to potentially impact another since they are now sharing the same ServerLocator instance. Keep track of references to avoid this.
This commit is contained in:
parent
cbb6c63d00
commit
2eac97aaff
|
@ -301,7 +301,7 @@ public final class ActiveMQRAManagedConnection implements ManagedConnection, Exc
|
||||||
|
|
||||||
// we must close the ActiveMQConnectionFactory because it contains a ServerLocator
|
// we must close the ActiveMQConnectionFactory because it contains a ServerLocator
|
||||||
if (connectionFactory != null) {
|
if (connectionFactory != null) {
|
||||||
connectionFactory.close();
|
ra.closeConnectionFactory(mcf.getProperties());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Throwable e) {
|
catch (Throwable e) {
|
||||||
|
|
|
@ -35,6 +35,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@ -43,17 +44,18 @@ import org.apache.activemq.artemis.api.core.BroadcastEndpointFactory;
|
||||||
import org.apache.activemq.artemis.api.core.ChannelBroadcastEndpointFactory;
|
import org.apache.activemq.artemis.api.core.ChannelBroadcastEndpointFactory;
|
||||||
import org.apache.activemq.artemis.api.core.DiscoveryGroupConfiguration;
|
import org.apache.activemq.artemis.api.core.DiscoveryGroupConfiguration;
|
||||||
import org.apache.activemq.artemis.api.core.JGroupsFileBroadcastEndpointFactory;
|
import org.apache.activemq.artemis.api.core.JGroupsFileBroadcastEndpointFactory;
|
||||||
|
import org.apache.activemq.artemis.api.core.Pair;
|
||||||
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
import org.apache.activemq.artemis.api.core.TransportConfiguration;
|
||||||
import org.apache.activemq.artemis.api.core.UDPBroadcastEndpointFactory;
|
import org.apache.activemq.artemis.api.core.UDPBroadcastEndpointFactory;
|
||||||
|
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
|
||||||
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
import org.apache.activemq.artemis.api.core.client.ClientSession;
|
||||||
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
import org.apache.activemq.artemis.api.core.client.ClientSessionFactory;
|
||||||
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
|
|
||||||
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
|
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
|
||||||
import org.apache.activemq.artemis.api.jms.JMSFactoryType;
|
import org.apache.activemq.artemis.api.jms.JMSFactoryType;
|
||||||
|
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
||||||
import org.apache.activemq.artemis.ra.inflow.ActiveMQActivation;
|
import org.apache.activemq.artemis.ra.inflow.ActiveMQActivation;
|
||||||
import org.apache.activemq.artemis.ra.inflow.ActiveMQActivationSpec;
|
import org.apache.activemq.artemis.ra.inflow.ActiveMQActivationSpec;
|
||||||
import org.apache.activemq.artemis.ra.recovery.RecoveryManager;
|
import org.apache.activemq.artemis.ra.recovery.RecoveryManager;
|
||||||
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
|
|
||||||
import org.apache.activemq.artemis.service.extensions.ServiceUtils;
|
import org.apache.activemq.artemis.service.extensions.ServiceUtils;
|
||||||
import org.apache.activemq.artemis.service.extensions.xa.recovery.XARecoveryConfig;
|
import org.apache.activemq.artemis.service.extensions.xa.recovery.XARecoveryConfig;
|
||||||
import org.apache.activemq.artemis.utils.SensitiveDataCodec;
|
import org.apache.activemq.artemis.utils.SensitiveDataCodec;
|
||||||
|
@ -127,7 +129,7 @@ public class ActiveMQResourceAdapter implements ResourceAdapter, Serializable {
|
||||||
* configured the exact same way. Using the same connection factory instance also makes connection load-balancing
|
* configured the exact same way. Using the same connection factory instance also makes connection load-balancing
|
||||||
* behave as expected for outbound connections.
|
* behave as expected for outbound connections.
|
||||||
*/
|
*/
|
||||||
private final Map<ConnectionFactoryProperties, ActiveMQConnectionFactory> knownConnectionFactories = new HashMap<ConnectionFactoryProperties, ActiveMQConnectionFactory>();
|
private final Map<ConnectionFactoryProperties, Pair<ActiveMQConnectionFactory, AtomicInteger>> knownConnectionFactories = new HashMap<ConnectionFactoryProperties, Pair<ActiveMQConnectionFactory, AtomicInteger>>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -275,8 +277,8 @@ public class ActiveMQResourceAdapter implements ResourceAdapter, Serializable {
|
||||||
|
|
||||||
managedConnectionFactories.clear();
|
managedConnectionFactories.clear();
|
||||||
|
|
||||||
for (ActiveMQConnectionFactory knownConnectionFactory : knownConnectionFactories.values()) {
|
for (Pair<ActiveMQConnectionFactory, AtomicInteger> pair : knownConnectionFactories.values()) {
|
||||||
knownConnectionFactory.close();
|
pair.getA().close();
|
||||||
}
|
}
|
||||||
knownConnectionFactories.clear();
|
knownConnectionFactories.clear();
|
||||||
|
|
||||||
|
@ -1600,11 +1602,10 @@ public class ActiveMQResourceAdapter implements ResourceAdapter, Serializable {
|
||||||
raProperties.setJgroupsChannelRefName(jgroupsChannelRefName);
|
raProperties.setJgroupsChannelRefName(jgroupsChannelRefName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActiveMQConnectionFactory createActiveMQConnectionFactory(final ConnectionFactoryProperties overrideProperties) {
|
public synchronized ActiveMQConnectionFactory createActiveMQConnectionFactory(final ConnectionFactoryProperties overrideProperties) {
|
||||||
ActiveMQConnectionFactory cf;
|
ActiveMQConnectionFactory cf;
|
||||||
boolean known = false;
|
boolean known = false;
|
||||||
|
|
||||||
synchronized (knownConnectionFactories) {
|
|
||||||
if (!knownConnectionFactories.keySet().contains(overrideProperties)) {
|
if (!knownConnectionFactories.keySet().contains(overrideProperties)) {
|
||||||
List<String> connectorClassName = overrideProperties.getParsedConnectorClassNames() != null ? overrideProperties.getParsedConnectorClassNames() : raProperties.getParsedConnectorClassNames();
|
List<String> connectorClassName = overrideProperties.getParsedConnectorClassNames() != null ? overrideProperties.getParsedConnectorClassNames() : raProperties.getParsedConnectorClassNames();
|
||||||
|
|
||||||
|
@ -1707,13 +1708,14 @@ public class ActiveMQResourceAdapter implements ResourceAdapter, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
setParams(cf, overrideProperties);
|
setParams(cf, overrideProperties);
|
||||||
knownConnectionFactories.put(overrideProperties, cf);
|
knownConnectionFactories.put(overrideProperties, new Pair(cf, new AtomicInteger(1)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cf = knownConnectionFactories.get(overrideProperties);
|
Pair<ActiveMQConnectionFactory, AtomicInteger> pair = knownConnectionFactories.get(overrideProperties);
|
||||||
|
cf = pair.getA();
|
||||||
|
pair.getB().incrementAndGet();
|
||||||
known = true;
|
known = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (known && cf.getServerLocator().isClosed()) {
|
if (known && cf.getServerLocator().isClosed()) {
|
||||||
knownConnectionFactories.remove(overrideProperties);
|
knownConnectionFactories.remove(overrideProperties);
|
||||||
|
@ -1978,4 +1980,12 @@ public class ActiveMQResourceAdapter implements ResourceAdapter, Serializable {
|
||||||
public SensitiveDataCodec<String> getCodecInstance() {
|
public SensitiveDataCodec<String> getCodecInstance() {
|
||||||
return raProperties.getCodecInstance();
|
return raProperties.getCodecInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void closeConnectionFactory(ConnectionFactoryProperties properties) {
|
||||||
|
Pair<ActiveMQConnectionFactory, AtomicInteger> pair = knownConnectionFactories.get(properties);
|
||||||
|
int references = pair.getB().decrementAndGet();
|
||||||
|
if (pair.getA() != null && pair.getA() != defaultActiveMQConnectionFactory && references == 0) {
|
||||||
|
knownConnectionFactories.remove(properties).getA().close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -427,7 +427,7 @@ public class ActiveMQActivation {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spec.isHasBeenUpdated() && factory != null) {
|
if (spec.isHasBeenUpdated() && factory != null) {
|
||||||
factory.close();
|
ra.closeConnectionFactory(spec);
|
||||||
factory = null;
|
factory = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -363,4 +363,55 @@ public class OutgoingConnectionTest extends ActiveMQRATestBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSharedActiveMQConnectionFactoryWithClose() throws Exception {
|
||||||
|
Session s = null;
|
||||||
|
Session s2 = null;
|
||||||
|
ActiveMQRAManagedConnection mc = null;
|
||||||
|
ActiveMQRAManagedConnection mc2 = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
server.getConfiguration().setSecurityEnabled(false);
|
||||||
|
resourceAdapter = new ActiveMQResourceAdapter();
|
||||||
|
|
||||||
|
resourceAdapter.setConnectorClassName(InVMConnectorFactory.class.getName());
|
||||||
|
MyBootstrapContext ctx = new MyBootstrapContext();
|
||||||
|
resourceAdapter.start(ctx);
|
||||||
|
ActiveMQRAConnectionManager qraConnectionManager = new ActiveMQRAConnectionManager();
|
||||||
|
ActiveMQRAManagedConnectionFactory mcf = new ActiveMQRAManagedConnectionFactory();
|
||||||
|
mcf.setResourceAdapter(resourceAdapter);
|
||||||
|
ActiveMQRAConnectionFactory qraConnectionFactory = new ActiveMQRAConnectionFactoryImpl(mcf, qraConnectionManager);
|
||||||
|
|
||||||
|
QueueConnection queueConnection = qraConnectionFactory.createQueueConnection();
|
||||||
|
s = queueConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||||
|
mc = (ActiveMQRAManagedConnection) ((ActiveMQRASession) s).getManagedConnection();
|
||||||
|
|
||||||
|
QueueConnection queueConnection2 = qraConnectionFactory.createQueueConnection();
|
||||||
|
s2 = queueConnection2.createSession(false, Session.AUTO_ACKNOWLEDGE);
|
||||||
|
mc2 = (ActiveMQRAManagedConnection) ((ActiveMQRASession) s2).getManagedConnection();
|
||||||
|
|
||||||
|
mc.destroy();
|
||||||
|
|
||||||
|
MessageProducer producer = s2.createProducer(ActiveMQJMSClient.createQueue(MDBQUEUE));
|
||||||
|
producer.send(s2.createTextMessage("x"));
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (s != null) {
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mc != null) {
|
||||||
|
mc.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s2 != null) {
|
||||||
|
s2.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mc2 != null) {
|
||||||
|
mc2.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue