You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ti...@apache.org on 2016/09/01 15:30:56 UTC

svn commit: r1758793 - in /aries/trunk/tx-control: tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/connection/impl/

Author: timothyjward
Date: Thu Sep  1 15:30:56 2016
New Revision: 1758793

URL: http://svn.apache.org/viewvc?rev=1758793&view=rev
Log:
[tx-control] Ensure that XA Connections are released by the JDBCResourceProvider

Modified:
    aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java
    aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java
    aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/connection/impl/XAConnectionWrapper.java

Modified: aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java?rev=1758793&r1=1758792&r2=1758793&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java (original)
+++ aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/AbstractTransactionTest.java Thu Sep  1 15:30:56 2016
@@ -30,8 +30,10 @@ import java.sql.Connection;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Properties;
 
@@ -114,6 +116,11 @@ public abstract class AbstractTransactio
 			});
 	}
 
+	protected Map<String, Object> resourceProviderConfig() {
+		// No extra information by default
+		return new HashMap<>();
+	}
+
 	public boolean isConfigured() {
 		return System.getProperties().containsKey(CONFIGURED_PROVIDER_PROPERTY);
 	}
@@ -156,7 +163,8 @@ public abstract class AbstractTransactio
 		
 		DataSourceFactory dsf = getService(DataSourceFactory.class, 5000);
 		
-		return resourceProviderFactory.getProviderFor(dsf, jdbc, null).getResource(txControl);
+		return resourceProviderFactory.getProviderFor(dsf, jdbc, resourceProviderConfig())
+				.getResource(txControl);
 	}
 
 	@SuppressWarnings({ "unchecked", "rawtypes" })
@@ -172,6 +180,9 @@ public abstract class AbstractTransactio
 		
 		System.out.println("Configuring connection provider with pid " + pid);
 		
+		resourceProviderConfig().entrySet().stream()
+			.forEach(e -> jdbc.put(e.getKey(), e.getValue()));
+		
 		org.osgi.service.cm.Configuration config = cm.createFactoryConfiguration(
 				pid, "?");
 		config.update((Hashtable)jdbc);

Modified: aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java?rev=1758793&r1=1758792&r2=1758793&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java (original)
+++ aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ConnectionLifecycleTest.java Thu Sep  1 15:30:56 2016
@@ -26,8 +26,14 @@ import static org.junit.Assert.fail;
 
 import java.sql.ResultSet;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 import org.junit.Assume;
 import org.junit.Test;
@@ -47,6 +53,22 @@ import org.osgi.service.transaction.cont
 @ExamReactorStrategy(PerClass.class)
 public class ConnectionLifecycleTest extends AbstractTransactionTest {
 
+	private static final long LIFETIME = 30000;
+	
+	private static final int CONNECTIONS = 17;
+	
+	@Override
+	protected Map<String, Object> resourceProviderConfig() {
+		// Set a short lifecycle for pooled connections and force a non-standard number
+		Map<String, Object> config = new HashMap<>();
+		config.put(JDBCConnectionProviderFactory.IDLE_TIMEOUT, LIFETIME/2);
+		config.put(JDBCConnectionProviderFactory.CONNECTION_LIFETIME, LIFETIME);
+		config.put(JDBCConnectionProviderFactory.MAX_CONNECTIONS, CONNECTIONS);
+		config.put(JDBCConnectionProviderFactory.MIN_CONNECTIONS, CONNECTIONS);
+		
+		return config;
+	}
+
 	@Test
 	public void testStopOfTxControlBundle() {
 		doBundleStoppingTest(b -> b.getSymbolicName().contains("tx-control-service"),
@@ -55,41 +77,36 @@ public class ConnectionLifecycleTest ext
 
 	@Test
 	public void testStopOfJDBCBundle() {
-		doBundleStoppingTest(b -> b.getSymbolicName().contains("tx-control-provider-jdbc"), 
+		doBundleStoppingTest(b -> b.getSymbolicName().contains("tx-control-provider-jdbc"),
 				"There was a problem getting hold of a database connection");
 	}
 
 	private void doBundleStoppingTest(Predicate<Bundle> p, String exceptionMessage) {
-		txControl.required(() -> connection.createStatement()
-				.execute("Insert into TEST_TABLE values ( 'Hello World!' )"));
+		txControl.required(
+				() -> connection.createStatement().execute("Insert into TEST_TABLE values ( 'Hello World!' )"));
 
 		assertEquals("Hello World!", txControl.notSupported(() -> {
-			ResultSet rs = connection.createStatement()
-					.executeQuery("Select * from TEST_TABLE");
+			ResultSet rs = connection.createStatement().executeQuery("Select * from TEST_TABLE");
 			rs.next();
 			return rs.getString(1);
 		}));
-		
-		
-		List<Bundle> toStop = Arrays.stream(context.getBundles())
-			.filter(p)
-			.collect(toList());
-		
+
+		List<Bundle> toStop = Arrays.stream(context.getBundles()).filter(p).collect(toList());
+
 		System.out.println(toStop);
-		
+
 		try {
-			toStop.stream()
-				.forEach(b -> {
-					System.out.println("Stopping " + b.getSymbolicName());
-					try {
-						b.stop();
-					} catch (BundleException e) {}
-				});
-		
+			toStop.stream().forEach(b -> {
+				System.out.println("Stopping " + b.getSymbolicName());
+				try {
+					b.stop();
+				} catch (BundleException e) {
+				}
+			});
+
 			try {
 				assertEquals("Hello World!", txControl.notSupported(() -> {
-					ResultSet rs = connection.createStatement()
-							.executeQuery("Select * from TEST_TABLE");
+					ResultSet rs = connection.createStatement().executeQuery("Select * from TEST_TABLE");
 					rs.next();
 					return rs.getString(1);
 				}));
@@ -101,47 +118,43 @@ public class ConnectionLifecycleTest ext
 				assertEquals(exceptionMessage, te.getMessage());
 			}
 		} finally {
-			toStop.stream()
-				.forEach(b -> {
-					try {
-						b.start();
-					} catch (BundleException e) {}
-				});
+			toStop.stream().forEach(b -> {
+				try {
+					b.start();
+				} catch (BundleException e) {
+				}
+			});
 		}
 	}
 
 	@Test
 	public void testDeleteOfConfig() throws Exception {
 		Assume.assumeTrue("Not a configuration test", isConfigured());
-		
-		
-		txControl.required(() -> connection.createStatement()
-				.execute("Insert into TEST_TABLE values ( 'Hello World!' )"));
+
+		txControl.required(
+				() -> connection.createStatement().execute("Insert into TEST_TABLE values ( 'Hello World!' )"));
 
 		assertEquals("Hello World!", txControl.notSupported(() -> {
-			ResultSet rs = connection.createStatement()
-					.executeQuery("Select * from TEST_TABLE");
+			ResultSet rs = connection.createStatement().executeQuery("Select * from TEST_TABLE");
 			rs.next();
 			return rs.getString(1);
 		}));
-		
-		
+
 		ConfigurationAdmin cm = getService(ConfigurationAdmin.class, 5000);
-		
-		Configuration[] configurations = cm.listConfigurations(
-				"(service.factoryPid=org.apache.aries.tx.control.jdbc.*)");
-		
+
+		Configuration[] configurations = cm
+				.listConfigurations("(service.factoryPid=org.apache.aries.tx.control.jdbc.*)");
+
 		assertNotNull(configurations);
 		assertEquals(1, configurations.length);
-		
+
 		configurations[0].delete();
-		
+
 		Thread.sleep(2000);
-		
+
 		try {
 			assertEquals("Hello World!", txControl.notSupported(() -> {
-				ResultSet rs = connection.createStatement()
-						.executeQuery("Select * from TEST_TABLE");
+				ResultSet rs = connection.createStatement().executeQuery("Select * from TEST_TABLE");
 				rs.next();
 				return rs.getString(1);
 			}));
@@ -155,35 +168,31 @@ public class ConnectionLifecycleTest ext
 	@Test
 	public void testUpdateOfConfig() throws Exception {
 		Assume.assumeTrue("Not a configuration test", isConfigured());
-		
-		
-		txControl.required(() -> connection.createStatement()
-				.execute("Insert into TEST_TABLE values ( 'Hello World!' )"));
+
+		txControl.required(
+				() -> connection.createStatement().execute("Insert into TEST_TABLE values ( 'Hello World!' )"));
 
 		assertEquals("Hello World!", txControl.notSupported(() -> {
-			ResultSet rs = connection.createStatement()
-					.executeQuery("Select * from TEST_TABLE");
+			ResultSet rs = connection.createStatement().executeQuery("Select * from TEST_TABLE");
 			rs.next();
 			return rs.getString(1);
 		}));
-		
-		
+
 		ConfigurationAdmin cm = getService(ConfigurationAdmin.class, 5000);
-		
-		Configuration[] configurations = cm.listConfigurations(
-				"(service.factoryPid=org.apache.aries.tx.control.jdbc.*)");
-		
+
+		Configuration[] configurations = cm
+				.listConfigurations("(service.factoryPid=org.apache.aries.tx.control.jdbc.*)");
+
 		assertNotNull(configurations);
 		assertEquals(1, configurations.length);
-		
+
 		configurations[0].update();
-		
+
 		Thread.sleep(2000);
-		
+
 		try {
 			assertEquals("Hello World!", txControl.notSupported(() -> {
-				ResultSet rs = connection.createStatement()
-						.executeQuery("Select * from TEST_TABLE");
+				ResultSet rs = connection.createStatement().executeQuery("Select * from TEST_TABLE");
 				rs.next();
 				return rs.getString(1);
 			}));
@@ -193,32 +202,27 @@ public class ConnectionLifecycleTest ext
 			assertEquals("There was a problem getting hold of a database connection", swe.getCause().getMessage());
 		}
 	}
-	
+
 	@Test
 	public void testReleaseOfFactoryService() {
 		Assume.assumeFalse("Not a factory test", isConfigured());
-		
-		txControl.required(() -> connection.createStatement()
-				.execute("Insert into TEST_TABLE values ( 'Hello World!' )"));
+
+		txControl.required(
+				() -> connection.createStatement().execute("Insert into TEST_TABLE values ( 'Hello World!' )"));
 
 		assertEquals("Hello World!", txControl.notSupported(() -> {
-			ResultSet rs = connection.createStatement()
-					.executeQuery("Select * from TEST_TABLE");
+			ResultSet rs = connection.createStatement().executeQuery("Select * from TEST_TABLE");
 			rs.next();
 			return rs.getString(1);
 		}));
-		
-		
-		trackers.stream()
-			.filter(t -> t.getService() instanceof JDBCConnectionProviderFactory)
-			.findFirst()
-			.get().close();;
-		
-		
+
+		trackers.stream().filter(t -> t.getService() instanceof JDBCConnectionProviderFactory).findFirst().get()
+				.close();
+		;
+
 		try {
 			assertEquals("Hello World!", txControl.notSupported(() -> {
-				ResultSet rs = connection.createStatement()
-						.executeQuery("Select * from TEST_TABLE");
+				ResultSet rs = connection.createStatement().executeQuery("Select * from TEST_TABLE");
 				rs.next();
 				return rs.getString(1);
 			}));
@@ -228,4 +232,58 @@ public class ConnectionLifecycleTest ext
 			assertEquals("There was a problem getting hold of a database connection", swe.getCause().getMessage());
 		}
 	}
+
+	@Test
+	public void testPoolLifecycle() throws Exception {
+		Set<String> allIds = new TreeSet<>();
+
+		for(int i = 0; i < 100; i++) {
+			Set<String> ids = txControl.notSupported(() -> {
+				Set<String> sessionIds = new HashSet<>();
+				
+				ResultSet rs = connection.createStatement()
+						.executeQuery("Select ID, SESSION_START from INFORMATION_SCHEMA.SESSIONS");
+				while(rs.next()) {
+					String connectionId = rs.getString(1);
+					if(connectionId.length() == 1) {
+						connectionId = "0" + connectionId;
+					}
+					sessionIds.add(connectionId + "-"
+							+ rs.getString(2));
+				}
+				return sessionIds;
+			});
+			
+			Set<String> newIds = ids.stream()
+						.filter(id -> !allIds.contains(id))
+						.collect(Collectors.toSet());
+			
+			allIds.addAll(ids);
+			System.out.println("Currently there are " + ids.size() + " connections");
+			System.out.println("In total there have been " + allIds.size() + " connections");
+			
+			int currentConnections = ids.size();
+			
+			if(currentConnections > CONNECTIONS) {
+				if((currentConnections - newIds.size()) <= CONNECTIONS) {
+					System.out.println("The number of connections is too high at " + currentConnections +
+							", but " + newIds.size() + " new connections have just been added. The previous connections may be in the process of being closed and so this loop will not fail.");
+				} else {
+					fail("Too many sessions " + currentConnections);
+				}
+			}
+				
+			Thread.sleep(500);
+		}
+		
+		int size = allIds.size();
+		if(size <= CONNECTIONS + 1) {
+			assertEquals("Expected 34 sessions, but found " + size + " " + allIds, 34, size);
+		} else if(size <= (2 * CONNECTIONS)) {
+			System.out.println("We really should have 34 sessions, but " + size  + 
+					" is probably enough ");
+		} else {
+			fail("There should not need to be more than " + (2 * CONNECTIONS) + " connections");
+		}
+	}
 }

Modified: aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/connection/impl/XAConnectionWrapper.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/connection/impl/XAConnectionWrapper.java?rev=1758793&r1=1758792&r2=1758793&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/connection/impl/XAConnectionWrapper.java (original)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/connection/impl/XAConnectionWrapper.java Thu Sep  1 15:30:56 2016
@@ -31,8 +31,11 @@ public class XAConnectionWrapper extends
 	private final Connection connection;
 	
 	private final XAResource xaResource;
+
+	private final XAConnection xaConnection;
 	
 	public XAConnectionWrapper(XAConnection xaConnection) throws SQLException {
+		this.xaConnection = xaConnection;
 		this.connection = xaConnection.getConnection();
 		this.xaResource = xaConnection.getXAResource();
 	}
@@ -45,4 +48,11 @@ public class XAConnectionWrapper extends
 	public XAResource getXaResource() {
 		return xaResource;
 	}
+
+	@Override
+	public void close() throws SQLException {
+		xaConnection.close();
+	}
+	
+	
 }