You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2016/03/09 20:29:13 UTC
[3/4] cayenne git commit: Cayenne 4.0 connection pool is occasionally
running out of connections
Cayenne 4.0 connection pool is occasionally running out of connections
* trying to reproduce
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/0a9974bd
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/0a9974bd
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/0a9974bd
Branch: refs/heads/master
Commit: 0a9974bd1674857ca492789b46858ec3eb8249f4
Parents: ab6faea
Author: Andrus Adamchik <an...@objectstyle.com>
Authored: Wed Mar 9 07:49:10 2016 -0800
Committer: Andrus Adamchik <an...@objectstyle.com>
Committed: Wed Mar 9 08:52:55 2016 -0800
----------------------------------------------------------------------
.../datasource/ManagedPoolingDataSource.java | 8 ++
.../datasource/ManagedPoolingDataSourceIT.java | 123 +++++++++++++++++++
2 files changed, 131 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/0a9974bd/cayenne-server/src/main/java/org/apache/cayenne/datasource/ManagedPoolingDataSource.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/datasource/ManagedPoolingDataSource.java b/cayenne-server/src/main/java/org/apache/cayenne/datasource/ManagedPoolingDataSource.java
index 3a794de..1075e3d 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/datasource/ManagedPoolingDataSource.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/datasource/ManagedPoolingDataSource.java
@@ -55,6 +55,14 @@ public class ManagedPoolingDataSource implements PoolingDataSource, ScopeEventLi
return dataSourceManager;
}
+ int poolSize() {
+ return dataSourceManager.getDataSource().poolSize();
+ }
+
+ int availableSize() {
+ return dataSourceManager.getDataSource().availableSize();
+ }
+
/**
* Calls {@link #shutdown()} to drain the underlying pool, close open
* connections and block the DataSource from creating any new connections.
http://git-wip-us.apache.org/repos/asf/cayenne/blob/0a9974bd/cayenne-server/src/test/java/org/apache/cayenne/datasource/ManagedPoolingDataSourceIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/datasource/ManagedPoolingDataSourceIT.java b/cayenne-server/src/test/java/org/apache/cayenne/datasource/ManagedPoolingDataSourceIT.java
new file mode 100644
index 0000000..1580ce5
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/datasource/ManagedPoolingDataSourceIT.java
@@ -0,0 +1,123 @@
+package org.apache.cayenne.datasource;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.sql.DataSource;
+
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.mockito.stubbing.OngoingStubbing;
+
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class ManagedPoolingDataSourceIT {
+
+ private int poolSize;
+ private Map<ExpiringConnection, Object> connections;
+ private UnmanagedPoolingDataSource unmanagedPool;
+ private ManagedPoolingDataSource managedPool;
+
+ @Before
+ public void before() throws SQLException {
+
+ this.poolSize = 3;
+ this.connections = new ConcurrentHashMap<>();
+
+ DataSource mockDataSource = mock(DataSource.class);
+ when(mockDataSource.getConnection()).thenAnswer(new Answer<Connection>() {
+
+ @Override
+ public Connection answer(InvocationOnMock invocation) throws Throwable {
+ return createMockConnection();
+ }
+ });
+
+ PoolingDataSourceParameters parameters = new PoolingDataSourceParameters();
+ parameters.setMaxConnections(poolSize);
+ parameters.setMinConnections(poolSize - 1);
+ parameters.setMaxQueueWaitTime(500);
+ parameters.setValidationQuery("SELECT 1");
+ this.unmanagedPool = new UnmanagedPoolingDataSource(mockDataSource, parameters);
+
+ this.managedPool = new ManagedPoolingDataSource(unmanagedPool, 10000);
+ }
+
+ private Connection createMockConnection() throws SQLException {
+ ExpiringConnection connectionWrapper = new ExpiringConnection();
+ connections.put(connectionWrapper, 1);
+ return connectionWrapper.mockConnection;
+ }
+
+ @After
+ public void after() {
+ if (managedPool != null) {
+ managedPool.close();
+ }
+ }
+
+ private void expireConnections() throws SQLException {
+ Iterator<ExpiringConnection> it = connections.keySet().iterator();
+ while (it.hasNext()) {
+ ExpiringConnection c = it.next();
+ it.remove();
+ c.expire();
+ }
+ }
+
+ @Test
+ public void testAbruptReset() throws SQLException {
+
+ assertTrue(managedPool.poolSize() > 0);
+ assertTrue(managedPool.availableSize() > 0);
+
+ // make sure conn
+ expireConnections();
+
+ // CAY-2067 ... this should work on an invalid pool
+ assertNotNull(managedPool.getConnection());
+ }
+
+ static class ExpiringConnection {
+
+ private Connection mockConnection;
+ private OngoingStubbing<Statement> createStatementMock;
+
+ ExpiringConnection() throws SQLException {
+ this.mockConnection = mock(Connection.class);
+ this.createStatementMock = when(mockConnection.createStatement());
+
+ createStatementMock.thenAnswer(new Answer<Statement>() {
+ @Override
+ public Statement answer(InvocationOnMock invocation) throws Throwable {
+
+ ResultSet mockRs = mock(ResultSet.class);
+ when(mockRs.next()).thenReturn(true, false, false, false);
+
+ Statement mockStatement = mock(Statement.class);
+ when(mockStatement.executeQuery(anyString())).thenReturn(mockRs);
+ return mockStatement;
+ }
+ });
+ }
+
+ void expire() throws SQLException {
+ createStatementMock.thenThrow(new SQLException("Expired"));
+ }
+ }
+}