Return-Path: Delivered-To: apmail-db-derby-commits-archive@www.apache.org Received: (qmail 97175 invoked from network); 12 Jul 2010 11:41:43 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 12 Jul 2010 11:41:43 -0000 Received: (qmail 26418 invoked by uid 500); 12 Jul 2010 11:41:42 -0000 Delivered-To: apmail-db-derby-commits-archive@db.apache.org Received: (qmail 26351 invoked by uid 500); 12 Jul 2010 11:41:41 -0000 Mailing-List: contact derby-commits-help@db.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: "Derby Development" List-Id: Delivered-To: mailing list derby-commits@db.apache.org Received: (qmail 26344 invoked by uid 99); 12 Jul 2010 11:41:40 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 12 Jul 2010 11:41:40 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 12 Jul 2010 11:41:36 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 0F1602388903; Mon, 12 Jul 2010 11:40:43 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r963243 - /db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/J2EEDataSourceTest.java Date: Mon, 12 Jul 2010 11:40:42 -0000 To: derby-commits@db.apache.org From: kristwaa@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100712114043.0F1602388903@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: kristwaa Date: Mon Jul 12 11:40:42 2010 New Revision: 963243 URL: http://svn.apache.org/viewvc?rev=963243&view=rev Log: DERBY-4709: Create test that parse client trace file to detect round-trips for Derby-4653. Alternative test for commit/rollback flow optimization, which parses the DRDA protocol flow log to verify that a commit/rollback flows over the network only when required. The test is very general, it does not test correct commit/rollback behavior for specific database interaction sequences. Patch file: derby-4709-1c-alternative_test.diff Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/J2EEDataSourceTest.java Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/J2EEDataSourceTest.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/J2EEDataSourceTest.java?rev=963243&r1=963242&r2=963243&view=diff ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/J2EEDataSourceTest.java (original) +++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/J2EEDataSourceTest.java Mon Jul 12 11:40:42 2010 @@ -21,7 +21,9 @@ package org.apache.derbyTesting.functionTests.tests.jdbcapi; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; import java.io.Serializable; import java.security.AccessController; import java.sql.CallableStatement; @@ -51,9 +53,11 @@ import javax.transaction.xa.Xid; import junit.framework.Test; import junit.framework.TestSuite; +import org.apache.derby.jdbc.ClientBaseDataSource; import org.apache.derby.jdbc.ClientConnectionPoolDataSource; import org.apache.derby.jdbc.ClientXADataSource; import org.apache.derby.jdbc.EmbeddedSimpleDataSource; +import org.apache.derbyTesting.functionTests.util.PrivilegedFileOpsForTests; import org.apache.derbyTesting.functionTests.util.SecurityCheck; import org.apache.derbyTesting.junit.BaseJDBCTestCase; import org.apache.derbyTesting.junit.CleanDatabaseTestSetup; @@ -62,6 +66,7 @@ import org.apache.derbyTesting.junit.J2E import org.apache.derbyTesting.junit.JDBC; import org.apache.derbyTesting.junit.JDBCClient; import org.apache.derbyTesting.junit.JDBCDataSource; +import org.apache.derbyTesting.junit.SupportFilesSetup; import org.apache.derbyTesting.junit.TestConfiguration; /** @@ -175,6 +180,10 @@ public class J2EEDataSourceTest extends //suite.addTest(new J2EEDataSourceTest( // "testClientMessageTextConnectionAttribute")); suite.addTest(new J2EEDataSourceTest("testConnectionFlowCommit")); + suite.addTest(new J2EEDataSourceTest("testConnectionFlowCommitAlt")); + // Disabled because rollback flow optimization hasn't been implemented. + // See DERBY-4687 + //suite.addTest(new J2EEDataSourceTest("testConnectionFlowRollbackAlt")); return suite; } @@ -213,8 +222,8 @@ public class J2EEDataSourceTest extends suite.addTest(TestConfiguration.clientServerDecorator( baseSuite(":client"))); // Add the tests that only run with client - suite.addTest(TestConfiguration.clientServerDecorator( - getClientSuite())); + suite.addTest(new SupportFilesSetup( + TestConfiguration.clientServerDecorator(getClientSuite()))); // Add the tests that only run with embedded suite.addTest(getEmbeddedSuite("embedded")); // Add the tests relying on getting timeouts. @@ -2126,7 +2135,201 @@ public class J2EEDataSourceTest extends s.close(); } - + + /** + * Alternative test for making sure "redundant" rollbacks, i.e. rollbacks + * invoked when no transaction is in progress, don't result in a rollback + * command being flowed to the server. + * + * @throws IOException if reading/parsing the trace file fails + * @throws SQLException if something goes wrong + */ + public void testConnectionFlowRollbackAlt() + throws IOException, SQLException { + Object[] dataSources = new Object[] { + JDBCDataSource.getDataSource(), + J2EEDataSource.getConnectionPoolDataSource(), + J2EEDataSource.getXADataSource() + }; + for (int i=0; i < dataSources.length; i++) { + Object ds = dataSources[i]; + // Run test sequence without invoking extra rollbacks. + int flowsBase = testConnectionFlowCommitRollback(ds, false, false); + // Run test sequence with extra rollbacks - these should not result + // in a rollback command being flowed to the server. + int flowsExtra = testConnectionFlowCommitRollback(ds, true, false); + assertEquals("Rollback optimization not working for connections " + + "originating from " + ds.getClass().getName(), + flowsBase, flowsExtra); + } + } + + /** + * Alternative test for making sure "redundant" commits, i.e. commits + * invoked when no transaction is in progress, don't result in a commit + * command being flowed to the server. + * + * @throws IOException if reading/parsing the trace file fails + * @throws SQLException if something goes wrong + */ + public void testConnectionFlowCommitAlt() + throws IOException, SQLException { + Object[] dataSources = new Object[] { + JDBCDataSource.getDataSource(), + J2EEDataSource.getConnectionPoolDataSource(), + J2EEDataSource.getXADataSource() + }; + for (int i=0; i < dataSources.length; i++) { + Object ds = dataSources[i]; + // Run test sequence without invoking extra commits. + int flowsBase = testConnectionFlowCommitRollback(ds, false, true); + // Run test sequence with extra commits - these should not result in + // a commit command being flowed to the server. + int flowsExtra = testConnectionFlowCommitRollback(ds, true, true); + assertEquals("Commit optimization not working for connections " + + "originating from " + ds.getClass().getName(), + flowsBase, flowsExtra); + } + } + + /** + * Performs a test sequence accessing the server, then parses the client + * connection trace file to obtain the number of commit or rollback + * commands flowed from the client to the server. + * + * @param ds data source used to obtain a connection to the database + * (must be using the test framework defaults) + * @param invokeExtra if {@code true} extra invocations of either commit or + * rollback are performed (depending on value of {@code isCommit}) + * @param isCommit if {@code true}, commits are invoked, otherwise + * rollbacks are invoked + * @return The number of wire flows detected (depending on value of + * {@code isCommit}). + * @throws IOException if reading/parsing the trace file fails + * @throws SQLException if something goes wrong + */ + private int testConnectionFlowCommitRollback( + Object ds, boolean invokeExtra, boolean isCommit) + throws IOException, SQLException { + final int extraInvokations = invokeExtra ? 25 : 0; + final int rowCount = 10; + final boolean isXA = ds instanceof ClientXADataSource; + final boolean isCP = ds instanceof ClientConnectionPoolDataSource; + // Generate trace file name and define trace behavior. + String dsType = (isXA ? "xa_" : (isCP ? "cp_" : "")); + String tbl = "ds_" + dsType + + (invokeExtra ? "base_" : "extra_") + + (isCommit ? "commit" : "rollback"); + File traceFile = SupportFilesSetup.getReadWrite(tbl + ".trace"); + J2EEDataSource.setBeanProperty(ds, "traceFile", + PrivilegedFileOpsForTests.getAbsolutePath(traceFile)); + J2EEDataSource.setBeanProperty(ds, "traceFileAppend", Boolean.FALSE); + J2EEDataSource.setBeanProperty( ds, "traceLevel", + new Integer(ClientBaseDataSource.TRACE_ALL)); + + // Obtain connection. + PooledConnection physicalCon = null; + Connection con; + if (isXA) { + physicalCon = ((XADataSource)ds).getXAConnection(); + con = physicalCon.getConnection(); + } else if (isCP) { + physicalCon = ((ClientConnectionPoolDataSource)ds). + getPooledConnection(); + con = physicalCon.getConnection(); + } else { + con = ((DataSource)ds).getConnection(); + } + con.setAutoCommit(false); + + // Run test sequence. + // step 0: create table + Statement stmt = con.createStatement(); + stmt.executeUpdate("create table " + tbl + " (id int)"); + con.commit(); // Unconditional commit to persist table + endTranscation(con, isCommit, extraInvokations); + // step 1: insert data + PreparedStatement ps = + con.prepareStatement("insert into " + tbl + " values (?)"); + for (int i=0; i < rowCount; i++) { + ps.setInt(1, i); + ps.executeUpdate(); + endTranscation(con, isCommit, extraInvokations); + } + ps.close(); + // Unconditional commit, should catch "missed" rollbacks above when we + // do a select with another connection at the end. + con.commit(); + // step 2: select data + ResultSet rs = stmt.executeQuery("select count(*) from " + tbl); + rs.next(); + rs.getInt(1); + rs.close(); + endTranscation(con, isCommit, extraInvokations); + // step 3: values clause + rs = stmt.executeQuery("values 7"); + assertTrue(rs.next()); + assertEquals(7, rs.getInt(1)); + rs.close(); + stmt.close(); + endTranscation(con, isCommit, extraInvokations); + con.close(); + if (physicalCon != null) { + physicalCon.close(); + } + + // step 4: table content validation + stmt = createStatement(); + rs = stmt.executeQuery("select count(*) from " + tbl); + rs.next(); + assertEquals("Potential COMMIT/ROLLBACK protocol error", + isCommit ? rowCount : 0, rs.getInt(1)); + + // Parse the trace file for commits or rollbacks. + String token = "SEND BUFFER: " + (isXA ? "SYNCCTL" : + (isCommit ? "RDBCMM" : "RDBRLLBCK")); + int tokenCount = 0; + BufferedReader r = new BufferedReader( + PrivilegedFileOpsForTests.getFileReader(traceFile)); + String line; + while ((line = r.readLine()) != null) { + if (line.startsWith("[derby]") && line.indexOf(token) != -1) { + println((isCommit ? "COMMIT: " : "ROLLBACK: ") + line); + tokenCount++; + } + } + r.close(); + assertTrue("Parsing failed, no COMMITS/ROLLBACKS detected", + tokenCount > 0); + println(ds.getClass().getName() + ", invokeExtra=" + invokeExtra + + ", isCommit=" + isCommit + ", tokenCount=" + tokenCount); + return tokenCount; + } + + /** + * Ends a transaction by invoking at least one commit or rollback. + * + * @param con the connection to work on + * @param isCommit if {@code true} commit is invoked, otherwise rollback + * is invoked + * @param count the number of extra commits or rollbacks to invoke + * @throws SQLException if a commit/rollback fails + */ + private void endTranscation(Connection con, boolean isCommit, int count) + throws SQLException { + if (isCommit) { + con.commit(); + for (int i=0; i < count; i++) { + con.commit(); + } + } else { + con.rollback(); + for (int i=0; i < count; i++) { + con.rollback(); + } + } + } + /** * Check setTransactioIsolation and with four connection in connection pool * for DERBY-4343 case