Repository: cayenne
Updated Branches:
  refs/heads/master c2ce2dfa6 -> e1a3d9788


CAY-2009 Non-blocking connection pool

* unit tests
* upgrade notes


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

Branch: refs/heads/master
Commit: e1a3d978891dad12a730dd7bc5cb0c284378abce
Parents: c2ce2df
Author: aadamchik <[email protected]>
Authored: Sun May 3 05:14:19 2015 -0400
Committer: aadamchik <[email protected]>
Committed: Sun May 3 06:13:21 2015 -0400

----------------------------------------------------------------------
 .../datasource/ManagedPoolingDataSource.java    | 17 +++-
 .../datasource/PoolingDataSourceManager.java    | 25 +++--
 .../ManagedPoolingDataSourceTest.java           | 97 ++++++++++++++++++++
 .../datasource/PoolDataSourceManagerTest.java   | 80 ++++++++++++++++
 docs/doc/src/main/resources/UPGRADE.txt         | 10 ++
 5 files changed, 219 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/e1a3d978/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 65083b1..182ad75 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
@@ -42,20 +42,33 @@ public class ManagedPoolingDataSource implements 
DataSource, ScopeEventListener
        public ManagedPoolingDataSource(PoolingDataSource dataSource) {
 
                this.dataSource = dataSource;
-               this.dataSourceManager = new 
PoolingDataSourceManager(dataSource);
+
+               // wake every 2 minutes...
+               this.dataSourceManager = new 
PoolingDataSourceManager(dataSource, 120000);
 
                dataSourceManager.start();
        }
 
+       PoolingDataSourceManager getDataSourceManager() {
+               return dataSourceManager;
+       }
+
+       /**
+        * Calls {@link #shutdown()} to drain the underlying pool, close open
+        * connections and block the DataSource from creating any new 
connections.
+        */
        @Override
        public void beforeScopeEnd() {
+               shutdown();
+       }
 
+       public void shutdown() {
                // swap the underlying DataSource to prevent further 
interaction with
                // the callers
                this.dataSource = new StoppedDataSource(dataSource);
 
                // shut down the thread..
-               dataSourceManager.shutdown();
+               this.dataSourceManager.shutdown();
        }
 
        @Override

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e1a3d978/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceManager.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceManager.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceManager.java
index 6dacdd6..3d2f93a 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceManager.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/datasource/PoolingDataSourceManager.java
@@ -19,9 +19,9 @@
 package org.apache.cayenne.datasource;
 
 /**
- * Manages the state of a {@link PoolingDataSource} instance, performing
- * periodic expansion/contraction of pooled connections, and orchestrating
- * shutdown.
+ * A thread that manages the state of a {@link PoolingDataSource} instance,
+ * performing periodic expansion/contraction of pooled connections, and
+ * orchestrating shutdown.
  * 
  * @since 4.0
  */
@@ -29,28 +29,37 @@ class PoolingDataSourceManager extends Thread {
 
        private volatile boolean shouldStop;
        private PoolingDataSource dataSource;
+       private long managerWakeTime;
 
-       PoolingDataSourceManager(PoolingDataSource dataSource) {
-               setName("PoolManagerCleanup-" + dataSource.hashCode());
+       PoolingDataSourceManager(PoolingDataSource dataSource, long 
managerWakeTime) {
+               setName("PoolingDataSourceManager-" + dataSource.hashCode());
                setDaemon(true);
 
                this.dataSource = dataSource;
                this.shouldStop = false;
+               this.managerWakeTime = managerWakeTime;
        }
 
-       public void shutdown() {
+       void shutdown() {
                shouldStop = true;
                dataSource.shutdown();
                interrupt();
        }
 
+       PoolingDataSource getDataSource() {
+               return dataSource;
+       }
+
+       boolean isStopped() {
+               return shouldStop;
+       }
+
        @Override
        public void run() {
                while (true) {
 
                        try {
-                               // don't do it too often
-                               Thread.sleep(600000);
+                               Thread.sleep(managerWakeTime);
                        } catch (InterruptedException iex) {
                                // ignore...
                        }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e1a3d978/cayenne-server/src/test/java/org/apache/cayenne/datasource/ManagedPoolingDataSourceTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/datasource/ManagedPoolingDataSourceTest.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/datasource/ManagedPoolingDataSourceTest.java
new file mode 100644
index 0000000..c728956
--- /dev/null
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/datasource/ManagedPoolingDataSourceTest.java
@@ -0,0 +1,97 @@
+/*****************************************************************
+ *   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.cayenne.datasource;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ManagedPoolingDataSourceTest {
+
+       private Connection[] mockConnections;
+       private PoolingDataSource mockPoolingDataSource;
+       private ManagedPoolingDataSource dataSource;
+
+       @Before
+       public void before() throws SQLException {
+
+               this.mockConnections = new Connection[4];
+               for (int i = 0; i < mockConnections.length; i++) {
+                       mockConnections[i] = mock(Connection.class);
+               }
+
+               this.mockPoolingDataSource = mock(PoolingDataSource.class);
+               
when(mockPoolingDataSource.getConnection()).thenReturn(mockConnections[0], 
mockConnections[1],
+                               mockConnections[2], mockConnections[3]);
+
+               this.dataSource = new 
ManagedPoolingDataSource(mockPoolingDataSource);
+       }
+
+       @After
+       public void after() {
+               dataSource.beforeScopeEnd();
+       }
+
+       @Test
+       public void testGetConnection() throws SQLException {
+               assertSame(mockConnections[0], dataSource.getConnection());
+               assertSame(mockConnections[1], dataSource.getConnection());
+               assertSame(mockConnections[2], dataSource.getConnection());
+               assertSame(mockConnections[3], dataSource.getConnection());
+       }
+
+       @Test
+       public void testShutdown() throws SQLException, InterruptedException {
+               assertNotNull(dataSource.getConnection());
+
+               // state before shutdown
+               verify(mockPoolingDataSource, times(0)).shutdown();
+               assertFalse(dataSource.getDataSourceManager().isStopped());
+               assertTrue(dataSource.getDataSourceManager().isAlive());
+
+               dataSource.shutdown();
+
+               // state after shutdown
+               verify(mockPoolingDataSource, times(1)).shutdown();
+               assertTrue(dataSource.getDataSourceManager().isStopped());
+
+               // give the thread some time to process interrupt and die
+               Thread.sleep(200);
+               assertFalse(dataSource.getDataSourceManager().isAlive());
+
+               try {
+                       dataSource.getConnection();
+               } catch (SQLException e) {
+                       // expected , DataSource should not give out 
connections any longer
+               }
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e1a3d978/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolDataSourceManagerTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolDataSourceManagerTest.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolDataSourceManagerTest.java
new file mode 100644
index 0000000..58b8983
--- /dev/null
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/datasource/PoolDataSourceManagerTest.java
@@ -0,0 +1,80 @@
+/*****************************************************************
+ *   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.cayenne.datasource;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+
+import java.sql.SQLException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class PoolDataSourceManagerTest {
+
+       private PoolingDataSource mockPoolingDataSource;
+       private PoolingDataSourceManager dataSourceManager;
+
+       @Before
+       public void before() throws SQLException {
+               this.mockPoolingDataSource = mock(PoolingDataSource.class);
+               this.dataSourceManager = new 
PoolingDataSourceManager(mockPoolingDataSource, 100);
+       }
+
+       @After
+       public void after() {
+               dataSourceManager.shutdown();
+       }
+
+       @Test
+       public void testRun_Manage() throws InterruptedException {
+
+               final int[] counter = new int[1];
+
+               doAnswer(new Answer<Object>() {
+                       @Override
+                       public Object answer(InvocationOnMock invocation) 
throws Throwable {
+                               counter[0]++;
+                               return null;
+                       }
+               }).when(mockPoolingDataSource).managePool();
+
+               dataSourceManager.start();
+
+               // we can't predict the number of 'managePool' invocations, but 
it
+               // should be incrementing as the time goes
+
+               int c0 = counter[0];
+               assertEquals(0, c0);
+               Thread.sleep(300);
+
+               int c1 = counter[0];
+               assertTrue(c1 > c0);
+
+               Thread.sleep(300);
+
+               int c2 = counter[0];
+               assertTrue(c2 > c1);
+       }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/e1a3d978/docs/doc/src/main/resources/UPGRADE.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/UPGRADE.txt 
b/docs/doc/src/main/resources/UPGRADE.txt
index cc5cda1..c29320d 100644
--- a/docs/doc/src/main/resources/UPGRADE.txt
+++ b/docs/doc/src/main/resources/UPGRADE.txt
@@ -12,6 +12,16 @@ UPGRADING TO 4.0.M3
   Note if you have references to @Deprecated String properties and you run 
cgen without "createPropertyNames" flag,
   there will be errors. Reference Jira: CAY-1991
 
+* Per CAY-2010 DataSource building methods were refactored out of 
ServerRuntimeBuilder and into a standalone 
+  org.apache.cayenne.datasource.DataSourceBuilder. So creating a DataSource in 
runtime may look like this:
+
+  DataSource ds = DataSourceBuilder.url(dbUrl).driver(dbDriver).build();
+  ServerRuntime runtime = 
ServerRuntimeBuilder.builder().dataSource(ds).build();
+
+* Per CAY-2008, CAY-2009 we got rid of org.apache.cayenne.conn.PoolManager and 
associated classes that made up a 
+  pooling DataSource. A replacement is non-blocking DataSource under 
org.apache.cayenne.datasource (PoolingDataSource, ManagedPoolingDataSource),
+  best assembled using org.apache.cayenne.datasource.DataSourceBuilder.
+
 
 UPGRADING TO 4.0.M2
 

Reply via email to