db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kmars...@apache.org
Subject svn commit: r651835 - in /db/derby/code/branches/10.3/java: client/org/apache/derby/client/ client/org/apache/derby/client/am/ client/org/apache/derby/client/net/ testing/org/apache/derbyTesting/functionTests/tests/jdbc4/
Date Sat, 26 Apr 2008 15:39:33 GMT
Author: kmarsden
Date: Sat Apr 26 08:39:30 2008
New Revision: 651835

URL: http://svn.apache.org/viewvc?rev=651835&view=rev
Log:
DERBY-3379  "No Current connection" on PooledConnection.getConnection() if pooled connection
is reused during connectionClosed
ported revision 637805,642942

DERBY-3421 Remove unused code for caching of connect bytes
revision 628679

Contributed by Kritian Waagan ( Kristian dot Waagan at Sun dot com)



Modified:
    db/derby/code/branches/10.3/java/client/org/apache/derby/client/ClientPooledConnection.java
    db/derby/code/branches/10.3/java/client/org/apache/derby/client/am/Connection.java
    db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/NetConnection.java
    db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/NetConnectionReply.java
    db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/Request.java
    db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/DataSourceTest.java

Modified: db/derby/code/branches/10.3/java/client/org/apache/derby/client/ClientPooledConnection.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/client/org/apache/derby/client/ClientPooledConnection.java?rev=651835&r1=651834&r2=651835&view=diff
==============================================================================
--- db/derby/code/branches/10.3/java/client/org/apache/derby/client/ClientPooledConnection.java
(original)
+++ db/derby/code/branches/10.3/java/client/org/apache/derby/client/ClientPooledConnection.java
Sat Apr 26 08:39:30 2008
@@ -300,6 +300,10 @@
             physicalConnection_.agent_.logWriter_.traceEntry(this, "recycleConnection");
         }
 
+        // Null out the reference to the logical connection that is currently
+        // being closed.
+        this.logicalConnection_ = null;
+
         for (Iterator e = listeners_.iterator(); e.hasNext();) {
             ConnectionEventListener listener =
                     (ConnectionEventListener)e.next();
@@ -333,8 +337,8 @@
     }
 
     /**
-     * Used by <code>LogicalConnection.close</code> when it disassociates itself
-     * from the pooled connection.
+     * Used by {@code LogicalConnection.close} in some circumstances when
+     * it disassociates itself from the pooled connection.
      */
     public synchronized void nullLogicalConnection() {
         logicalConnection_ = null;

Modified: db/derby/code/branches/10.3/java/client/org/apache/derby/client/am/Connection.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/client/org/apache/derby/client/am/Connection.java?rev=651835&r1=651834&r2=651835&view=diff
==============================================================================
--- db/derby/code/branches/10.3/java/client/org/apache/derby/client/am/Connection.java (original)
+++ db/derby/code/branches/10.3/java/client/org/apache/derby/client/am/Connection.java Sat
Apr 26 08:39:30 2008
@@ -142,7 +142,6 @@
     public int clientSSLMode_ = ClientBaseDataSource.SSL_OFF;
 
     public java.util.Hashtable clientCursorNameCache_ = new java.util.Hashtable();
-    public boolean canUseCachedConnectBytes_ = false;
     public int commBufferSize_ = 32767;
 
     // indicates if a deferred reset connection is required

Modified: db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/NetConnection.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/NetConnection.java?rev=651835&r1=651834&r2=651835&view=diff
==============================================================================
--- db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/NetConnection.java
(original)
+++ db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/NetConnection.java
Sat Apr 26 08:39:30 2008
@@ -57,10 +57,6 @@
     // For XA Transaction
     protected int pendingEndXACallinfoOffset_ = -1;
 
-
-    // byte[] to save the connect flows for connection reset
-    protected byte[] cachedConnectBytes_ = null;
-    protected boolean wroteConnectFromCache_ = false;
     //-----------------------------state------------------------------------------
 
     // these variables store the manager levels for the connection.
@@ -870,108 +866,79 @@
                 netAgent_.typdef_);
     }
 
-    private void cacheConnectBytes(int beginOffset, int endOffset) {
-        int length = endOffset - beginOffset;
-        cachedConnectBytes_ = new byte[length];
-        netAgent_.netConnectionRequest_.finalizePreviousChainedDss(false);
-        System.arraycopy(netAgent_.netConnectionRequest_.bytes_,
-                beginOffset,
-                cachedConnectBytes_,
-                0,
-                length);
-        netAgent_.netConnectionRequest_.setDssLengthLocation(netAgent_.netConnectionRequest_.offset_);
-    }
-
     private void readSecurityCheckAndAccessRdb() throws SqlException {
         netAgent_.netConnectionReply_.readSecurityCheck(this);
         netAgent_.netConnectionReply_.readAccessDatabase(this);
     }
 
     void writeDeferredReset() throws SqlException {
-        if (canUseCachedConnectBytes_ && cachedConnectBytes_ != null &&
-                (securityMechanism_ == NetConfiguration.SECMEC_USRIDPWD ||
-                securityMechanism_ == NetConfiguration.SECMEC_USRIDONL)) {
-            writeDeferredResetFromCache();
-            wroteConnectFromCache_ = true;
-        } else {
-            int beginOffset = netAgent_.netConnectionRequest_.offset_;
-            int endOffset = 0;
-            // NetConfiguration.SECMEC_USRIDPWD
-            if (securityMechanism_ == NetConfiguration.SECMEC_USRIDPWD) {
-                writeAllConnectCommandsChained(NetConfiguration.SECMEC_USRIDPWD,
+        // NetConfiguration.SECMEC_USRIDPWD
+        if (securityMechanism_ == NetConfiguration.SECMEC_USRIDPWD) {
+            writeAllConnectCommandsChained(NetConfiguration.SECMEC_USRIDPWD,
+                    user_,
+                    getDeferredResetPassword());
+        }
+        // NetConfiguration.SECMEC_USRIDONL
+        else if (securityMechanism_ == NetConfiguration.SECMEC_USRIDONL) {
+            writeAllConnectCommandsChained(NetConfiguration.SECMEC_USRIDONL,
+                    user_,
+                    null);  //password
+        }
+        // Either NetConfiguration.SECMEC_USRENCPWD,
+        // NetConfiguration.SECMEC_EUSRIDPWD or
+        // NetConfiguration.SECMEC_USRSSBPWD
+        else {
+            if (securityMechanism_ == NetConfiguration.SECMEC_USRSSBPWD)
+                initializeClientSeed();
+            else // SECMEC_USRENCPWD, SECMEC_EUSRIDPWD
+                initializePublicKeyForEncryption();
+
+            // Set the resetConnectionAtFirstSql_ to false to avoid going in an
+            // infinite loop, since all the flow methods call beginWriteChain which then
+            // calls writeDeferredResetConnection where the check for resetConnectionAtFirstSql_
+            // is done. By setting the resetConnectionAtFirstSql_ to false will avoid calling
the
+            // writeDeferredReset method again.
+            resetConnectionAtFirstSql_ = false;
+
+            if (securityMechanism_ == NetConfiguration.SECMEC_USRSSBPWD)
+                flowSeedExchange(securityMechanism_, sourceSeed_);
+            else // SECMEC_USRENCPWD, SECMEC_EUSRIDPWD
+                flowServerAttributesAndKeyExchange(securityMechanism_, publicKey_);
+
+            agent_.beginWriteChainOutsideUOW();
+
+            // Reset the resetConnectionAtFirstSql_ to true since we are done
+            // with the flow method.
+            resetConnectionAtFirstSql_ = true;
+
+            // NetConfiguration.SECMEC_USRENCPWD
+            if (securityMechanism_ == NetConfiguration.SECMEC_USRENCPWD) {
+                writeSecurityCheckAndAccessRdb(NetConfiguration.SECMEC_USRENCPWD,
                         user_,
-                        getDeferredResetPassword());
-                endOffset = netAgent_.netConnectionRequest_.offset_;
-                cacheConnectBytes(beginOffset, endOffset);
+                        null, //password
+                        null, //encryptedUserid
+                        encryptedPasswordForUSRENCPWD(getDeferredResetPassword()));
             }
-            // NetConfiguration.SECMEC_USRIDONL
-            else if (securityMechanism_ == NetConfiguration.SECMEC_USRIDONL) {
-                writeAllConnectCommandsChained(NetConfiguration.SECMEC_USRIDONL,
+            // NetConfiguration.SECMEC_USRSSBPWD
+            else if (securityMechanism_ == NetConfiguration.SECMEC_USRSSBPWD) {
+                writeSecurityCheckAndAccessRdb(NetConfiguration.SECMEC_USRSSBPWD,
                         user_,
-                        null);  //password
-                endOffset = netAgent_.netConnectionRequest_.offset_;
-                cacheConnectBytes(beginOffset, endOffset);
+                        null,
+                        null,
+                        passwordSubstituteForUSRSSBPWD(getDeferredResetPassword()));
             }
-            // Either NetConfiguration.SECMEC_USRENCPWD,
-            // NetConfiguration.SECMEC_EUSRIDPWD or
-            // NetConfiguration.SECMEC_USRSSBPWD
-            else {
-                if (securityMechanism_ == NetConfiguration.SECMEC_USRSSBPWD)
-                    initializeClientSeed();
-                else // SECMEC_USRENCPWD, SECMEC_EUSRIDPWD
-                    initializePublicKeyForEncryption();
-
-                // Set the resetConnectionAtFirstSql_ to false to avoid going in an
-                // infinite loop, since all the flow methods call beginWriteChain which then
-                // calls writeDeferredResetConnection where the check for resetConnectionAtFirstSql_
-                // is done. By setting the resetConnectionAtFirstSql_ to false will avoid
calling the
-                // writeDeferredReset method again.
-                resetConnectionAtFirstSql_ = false;
-
-                if (securityMechanism_ == NetConfiguration.SECMEC_USRSSBPWD)
-                    flowSeedExchange(securityMechanism_, sourceSeed_);
-                else // SECMEC_USRENCPWD, SECMEC_EUSRIDPWD
-                    flowServerAttributesAndKeyExchange(securityMechanism_, publicKey_);
-
-                agent_.beginWriteChainOutsideUOW();
-
-                // Reset the resetConnectionAtFirstSql_ to true since we are done
-                // with the flow method.
-                resetConnectionAtFirstSql_ = true;
-
-                // NetConfiguration.SECMEC_USRENCPWD
-                if (securityMechanism_ == NetConfiguration.SECMEC_USRENCPWD) {
-                    writeSecurityCheckAndAccessRdb(NetConfiguration.SECMEC_USRENCPWD,
-                            user_,
-                            null, //password
-                            null, //encryptedUserid
-                            encryptedPasswordForUSRENCPWD(getDeferredResetPassword()));
-                }
-                // NetConfiguration.SECMEC_USRSSBPWD
-                else if (securityMechanism_ == NetConfiguration.SECMEC_USRSSBPWD) {
-                    writeSecurityCheckAndAccessRdb(NetConfiguration.SECMEC_USRSSBPWD,
-                            user_,
-                            null,
-                            null,
-                            passwordSubstituteForUSRSSBPWD(getDeferredResetPassword()));
-                }
-                else {  // NetConfiguration.SECMEC_EUSRIDPWD
-                    writeSecurityCheckAndAccessRdb(NetConfiguration.SECMEC_EUSRIDPWD,
-                            null, //user
-                            null, //password
-                            encryptedUseridForEUSRIDPWD(),
-                            encryptedPasswordForEUSRIDPWD(getDeferredResetPassword()));
-                }
+            else {  // NetConfiguration.SECMEC_EUSRIDPWD
+                writeSecurityCheckAndAccessRdb(NetConfiguration.SECMEC_EUSRIDPWD,
+                        null, //user
+                        null, //password
+                        encryptedUseridForEUSRIDPWD(),
+                        encryptedPasswordForEUSRIDPWD(getDeferredResetPassword()));
             }
         }
     }
 
     void readDeferredReset() throws SqlException {
         resetConnectionAtFirstSql_ = false;
-        if (wroteConnectFromCache_) {
-            netAgent_.netConnectionReply_.verifyDeferredReset();
-            return;
-        }
         // either NetConfiguration.SECMEC_USRIDPWD or NetConfiguration.SECMEC_USRIDONL
         if (securityMechanism_ == NetConfiguration.SECMEC_USRIDPWD ||
                 securityMechanism_ == NetConfiguration.SECMEC_USRIDONL) {
@@ -1525,19 +1492,6 @@
         }
         return array;
     }
-
-    private void writeDeferredResetFromCache() {
-        int length = cachedConnectBytes_.length;
-        System.arraycopy(cachedConnectBytes_,
-                0,
-                netAgent_.netConnectionRequest_.bytes_,
-                netAgent_.netConnectionRequest_.offset_,
-                length);
-        netAgent_.netConnectionRequest_.offset_ += length;
-        netAgent_.netConnectionRequest_.setDssLengthLocation(netAgent_.netConnectionRequest_.offset_);
-        netAgent_.netConnectionRequest_.setCorrelationID(4);
-    }
-
 
     public void writeCommitSubstitute_() throws SqlException {
         netAgent_.connectionRequest_.writeCommitSubstitute(this);

Modified: db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/NetConnectionReply.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/NetConnectionReply.java?rev=651835&r1=651834&r2=651835&view=diff
==============================================================================
--- db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/NetConnectionReply.java
(original)
+++ db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/NetConnectionReply.java
Sat Apr 26 08:39:30 2008
@@ -57,18 +57,6 @@
         agent_.checkForChainBreakingException_();
     }
 
-    void verifyDeferredReset() throws SqlException {
-        readDssHeader();
-        verifyConnectReply(CodePoint.EXCSATRD);
-        readDssHeader();
-        verifyConnectReply(CodePoint.ACCSECRD);
-        readDssHeader();
-        verifyConnectReply(CodePoint.SECCHKRM);
-        readDssHeader();
-        verifyConnectReply(CodePoint.ACCRDBRM);
-        agent_.checkForChainBreakingException_();
-    }
-
     void verifyConnectReply(int codept) throws SqlException {
         if (peekCodePoint() != codept) {
             parseConnectError();

Modified: db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/Request.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/Request.java?rev=651835&r1=651834&r2=651835&view=diff
==============================================================================
--- db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/Request.java (original)
+++ db/derby/code/branches/10.3/java/client/org/apache/derby/client/net/Request.java Sat Apr
26 08:39:30 2008
@@ -191,19 +191,21 @@
             }
         }
 
+        // RQSDSS header is 6 bytes long: (ll)(Cf)(rc)
         ensureLength(offset_ + 6);
 
-        // save the length position and skip
-        // note: the length position is saved so it can be updated
-        // with a different value later.
+        // Save the position of the length bytes, so they can be updated with a
+        // different value at a later time.
         dssLengthLocation_ = offset_;
-        // always turn on chaining flags... this is helpful for lobs...
-        // these bytes will get rest if dss lengths are finalized.
+        // Dummy values for the DSS length (token ll above).
+        // The correct length will be inserted when the DSS is finalized.
         bytes_[offset_++] = (byte) 0xFF;
         bytes_[offset_++] = (byte) 0xFF;
 
-        // insert the manditory 0xD0 and the dssType
+        // Insert the mandatory 0xD0 (token C).
         bytes_[offset_++] = (byte) 0xD0;
+        // Insert the dssType (token f), which also tells if the DSS is chained
+        // or not. See DSSFMT in the DRDA specification for details.
         if (chainedToNextStructure) {
             dssType |= DssConstants.GDSCHAIN;
             if (nextHasSameCorrelator) {
@@ -212,7 +214,7 @@
         }
         bytes_[offset_++] = (byte) (dssType & 0xff);
 
-        // write the request correlation id
+        // Write the request correlation id (two bytes, token rc).
         // use method that writes a short
         bytes_[offset_++] = (byte) ((corrId >>> 8) & 0xff);
         bytes_[offset_++] = (byte) (corrId & 0xff);
@@ -821,15 +823,20 @@
         return offset_ != 0;
     }
 
-    // signal the completion of a Dss Layer A object. The length of
-    // dss object will be calculated based on the difference between the
-    // start of the dss, saved on the beginDss call, and the current
-    // offset into the buffer which marks the end of the data.  In the event
-    // the length requires the use of continuation Dss headers, one for each 32k
-    // chunk of data, the data will be shifted and the continuation headers
-    // will be inserted with the correct values as needed.
-    // Note: In the future, we may try to optimize this approach
-    // in an attempt to avoid these shifts.
+    /**
+     * Signal the completion of a DSS Layer A object.
+     * <p>
+     * The length of the DSS object will be calculated based on the difference
+     * between the start of the DSS, saved in the variable
+     * {@link #dssLengthLocation_}, and the current offset into the buffer which
+     * marks the end of the data.
+     * <p>
+     * In the event the length requires the use of continuation DSS headers,
+     * one for each 32k chunk of data, the data will be shifted and the
+     * continuation headers will be inserted with the correct values as needed.
+     * Note: In the future, we may try to optimize this approach
+     * in an attempt to avoid these shifts.
+     */
     protected final void finalizeDssLength() {
         // calculate the total size of the dss and the number of bytes which would
         // require continuation dss headers.  The total length already includes the

Modified: db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/DataSourceTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/DataSourceTest.java?rev=651835&r1=651834&r2=651835&view=diff
==============================================================================
--- db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/DataSourceTest.java
(original)
+++ db/derby/code/branches/10.3/java/testing/org/apache/derbyTesting/functionTests/tests/jdbc4/DataSourceTest.java
Sat Apr 26 08:39:30 2008
@@ -29,6 +29,7 @@
 import org.apache.derbyTesting.functionTests.tests.jdbcapi.AssertEventCatcher;
 import org.apache.derbyTesting.functionTests.util.TestUtil;
 import org.apache.derbyTesting.junit.BaseJDBCTestCase;
+import org.apache.derbyTesting.junit.J2EEDataSource;
 import org.apache.derbyTesting.junit.JDBC;
 import org.apache.derbyTesting.junit.JDBCDataSource;
 import org.apache.derbyTesting.junit.TestConfiguration;
@@ -310,6 +311,130 @@
         // Get a new connection to the database
         conn = getConnection();
         conn.close();
+    }
+    
+    /**
+     * Test that a PooledConnection can be reused and closed
+     * (separately) during the close event raised by the
+     * closing of its logical connection.
+     * DERBY-2142.
+     * @throws SQLException 
+     *
+     */
+    public void testPooledReuseOnClose() throws SQLException
+    {
+    	// PooledConnection from a ConnectionPoolDataSource
+    	ConnectionPoolDataSource cpds =
+    		J2EEDataSource.getConnectionPoolDataSource();
+    	subtestPooledReuseOnClose(cpds.getPooledConnection());
+        subtestPooledCloseOnClose(cpds.getPooledConnection());
+        // DERBY-3401 - removing a callback during a close causes problems.
+        //subtestPooledRemoveListenerOnClose(cpds.getPooledConnection());
+
+    	// PooledConnection from an XDataSource
+    	XADataSource xads = J2EEDataSource.getXADataSource();
+    	subtestPooledReuseOnClose(xads.getXAConnection());
+        subtestPooledCloseOnClose(xads.getXAConnection());
+        // DERBY-3401 - removing a callback during a close causes problems.
+        //subtestPooledRemoveListenerOnClose(xads.getXAConnection());
+    }
+    
+    /**
+     * Tests that a pooled connection can successfully be reused
+     * (a new connection obtained from it) during the processing
+     * of its close event by its listener.
+     * Sections 11.2 & 12.5 of JDBC 4 specification indicate that the
+     * connection can be returned to the pool when the
+     * ConnectionEventListener.connectionClosed() is called.
+     */
+    private void subtestPooledReuseOnClose(final PooledConnection pc) throws SQLException
+    {
+    	final Connection[] newConn = new Connection[1];
+    	pc.addConnectionEventListener(new ConnectionEventListener() {
+
+    		/**
+    		 * Mimic a pool handler that returns the PooledConnection
+    		 * to the pool and then reallocates it to a new logical connection.
+    		 */
+			public void connectionClosed(ConnectionEvent event) {
+				PooledConnection pce = (PooledConnection) event.getSource();
+				assertSame(pc, pce);
+				try {
+					// open a new logical connection and pass
+					// back to the fixture.
+					newConn[0] = pce.getConnection();
+				} catch (SQLException e) {
+                    // Need to catch the exception here because
+                    // we cannot throw a checked exception through
+                    // the api method. Wrap it in a RuntimeException.
+                    throw new RuntimeException(e);
+				}
+			}
+
+			public void connectionErrorOccurred(ConnectionEvent event) {
+			}
+    		
+    	});
+    	
+    	// Open a connection then close it to trigger the
+    	// fetching of a new connection in the callback.
+    	Connection c1 = pc.getConnection();
+    	c1.close();
+    	
+    	// Fetch the connection created in the close callback
+    	Connection c2 = newConn[0];
+    	assertNotNull(c2);
+    	
+    	// Ensure the connection is useable, this hit a NPE before DERBY-2142
+    	// was fixed (for embedded).
+    	c2.createStatement().close();
+    	
+    	pc.close();
+    }
+    
+    /**
+     * Tests that a pooled connection can successfully be closed
+     * during the processing of its close event by its listener.
+     */
+    private void subtestPooledCloseOnClose(final PooledConnection pc) throws SQLException
+    {
+        pc.addConnectionEventListener(new ConnectionEventListener() {
+
+            /**
+             * Mimic a pool handler that closes the PooledConnection
+             * (say it no longer needs it, pool size being reduced)
+             */
+            public void connectionClosed(ConnectionEvent event) {
+                PooledConnection pce = (PooledConnection) event.getSource();
+                assertSame(pc, pce);
+                try {
+                    pce.close();
+                } catch (SQLException e) {
+                    // Need to catch the exception here because
+                    // we cannot throw a checked exception through
+                    // the api method. Wrap it in a RuntimeException.
+                    throw new RuntimeException(e);
+                }
+            }
+
+            public void connectionErrorOccurred(ConnectionEvent event) {
+            }
+            
+        });
+        
+        // Open and close a connection to invoke the logic above
+        // through the callback
+        pc.getConnection().close();
+                
+        // The callback closed the actual pooled connection
+        // so subsequent requests to get a logical connection
+        // should fail.
+        try {
+            pc.getConnection();
+            fail("PooledConnection should be closed");
+        } catch (SQLException sqle) {
+            assertSQLState("08003", sqle);
+        }
     }
     /**
      * Stop the network server



Mime
View raw message