Added:
branches/branch_5_0/connector-j/src/com/mysql/jdbc/jdbc2/optional/SuspendableXAConnection.java
Modified:
branches/branch_5_0/connector-j/CHANGES
branches/branch_5_0/connector-j/src/com/mysql/jdbc/ConnectionProperties.java
branches/branch_5_0/connector-j/src/com/mysql/jdbc/jdbc2/optional/MysqlXADataSource.java
branches/branch_5_0/connector-j/src/testsuite/BaseTestCase.java
branches/branch_5_0/connector-j/src/testsuite/simple/XATest.java
Log:
Added connection/datasource property "pinGlobalTxToPhysicalConnection"
(defaults to "false"). When set to "true", when using XAConnections, the
driver ensures that operations on a given XID are always routed to the
same physical connection. This allows the XAConnection to support
"XA START ... JOIN" after "XA END" has been called, and is also a
workaround for transaction managers that don't maintain thread affinity
for a global transaction (most either always maintain thread affinity,
or have it as a configuration option).
Modified: branches/branch_5_0/connector-j/CHANGES
===================================================================
--- branches/branch_5_0/connector-j/CHANGES 2006-06-27 00:01:37 UTC (rev 5439)
+++ branches/branch_5_0/connector-j/CHANGES 2006-06-27 17:00:53 UTC (rev 5440)
@@ -20,7 +20,19 @@
- Fixed BUG#20242 - MysqlValidConnectionChecker for JBoss doesn't
work with MySQLXADataSources.
-
+
+ - Better caching of character set converters (per-connection)
+ to remove a bottleneck for multibyte character sets.
+
+ - Added connection/datasource property "pinGlobalTxToPhysicalConnection"
+ (defaults to "false"). When set to "true", when using XAConnections, the
+ driver ensures that operations on a given XID are always routed to the
+ same physical connection. This allows the XAConnection to support
+ "XA START ... JOIN" after "XA END" has been called, and is also a
+ workaround for transaction managers that don't maintain thread affinity
+ for a global transaction (most either always maintain thread affinity,
+ or have it as a configuration option).
+
12-23-05 - Version 5.0.0-beta
- XADataSource implemented (ported from 3.2 branch which won't be
Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/ConnectionProperties.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/ConnectionProperties.java 2006-06-27 00:01:37 UTC (rev 5439)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/ConnectionProperties.java 2006-06-27 17:00:53 UTC (rev 5440)
@@ -1037,6 +1037,12 @@
"pedantic", false, "Follow the JDBC spec to the letter.", "3.0.0",
MISC_CATEGORY, Integer.MIN_VALUE);
+ private BooleanConnectionProperty pinGlobalTxToPhysicalConnection = new BooleanConnectionProperty(
+ "pinGlobalTxToPhysicalConnection", false, "When using XAConnections, should the driver ensure that "
+ + " operations on a given XID are always routed to the same physical connection? This allows the XAConnection"
+ + " to support \"XA START ... JOIN\" after \"XA END\" has been called",
+ "5.0.1", MISC_CATEGORY, Integer.MIN_VALUE);
+
private IntegerConnectionProperty preparedStatementCacheSize = new IntegerConnectionProperty(
"prepStmtCacheSize", 25, 0, Integer.MAX_VALUE,
"If prepared statement caching is enabled, "
@@ -3553,55 +3559,55 @@
*
* @return Returns the useUnbufferedInput.
*/
- protected boolean useUnbufferedInput() {
+ public boolean useUnbufferedInput() {
return this.useUnbufferedInput.getValueAsBoolean();
}
- protected boolean getUseCursorFetch() {
+ public boolean getUseCursorFetch() {
return this.useCursorFetch.getValueAsBoolean();
}
- protected void setUseCursorFetch(boolean flag) {
+ public void setUseCursorFetch(boolean flag) {
this.useCursorFetch.setValue(flag);
}
- protected boolean getOverrideSupportsIntegrityEnhancementFacility() {
+ public boolean getOverrideSupportsIntegrityEnhancementFacility() {
return this.overrideSupportsIntegrityEnhancementFacility.getValueAsBoolean();
}
- protected void setOverrideSupportsIntegrityEnhancementFacility(boolean flag) {
+ public void setOverrideSupportsIntegrityEnhancementFacility(boolean flag) {
this.overrideSupportsIntegrityEnhancementFacility.setValue(flag);
}
- protected boolean getNoTimezoneConversionForTimeType() {
+ public boolean getNoTimezoneConversionForTimeType() {
return this.noTimezoneConversionForTimeType.getValueAsBoolean();
}
- protected void setNoTimezoneConversionForTimeType(boolean flag) {
+ public void setNoTimezoneConversionForTimeType(boolean flag) {
this.noTimezoneConversionForTimeType.setValue(flag);
}
- protected boolean getUseJDBCCompliantTimezoneShift() {
+ public boolean getUseJDBCCompliantTimezoneShift() {
return this.useJDBCCompliantTimezoneShift.getValueAsBoolean();
}
- protected void setUseJDBCCompliantTimezoneShift(boolean flag) {
+ public void setUseJDBCCompliantTimezoneShift(boolean flag) {
this.useJDBCCompliantTimezoneShift.setValue(flag);
}
- protected boolean getAutoClosePStmtStreams() {
+ public boolean getAutoClosePStmtStreams() {
return this.autoClosePStmtStreams.getValueAsBoolean();
}
- protected void setAutoClosePStmtStreams(boolean flag) {
+ public void setAutoClosePStmtStreams(boolean flag) {
this.autoClosePStmtStreams.setValue(flag);
}
- protected boolean getProcessEscapeCodesForPrepStmts() {
+ public boolean getProcessEscapeCodesForPrepStmts() {
return this.processEscapeCodesForPrepStmts.getValueAsBoolean();
}
- protected void setProcessEscapeCodesForPrepStmts(boolean flag) {
+ public void setProcessEscapeCodesForPrepStmts(boolean flag) {
this.processEscapeCodesForPrepStmts.setValue(flag);
}
@@ -3613,30 +3619,55 @@
this.useGmtMillisForDatetimes.setValue(flag);
}
- protected boolean getDumpMetadataOnColumnNotFound() {
+ public boolean getDumpMetadataOnColumnNotFound() {
return this.dumpMetadataOnColumnNotFound.getValueAsBoolean();
}
- protected void setDumpMetadataOnColumnNotFound(boolean flag) {
+ public void setDumpMetadataOnColumnNotFound(boolean flag) {
this.dumpMetadataOnColumnNotFound.setValue(flag);
}
- protected String getResourceId() {
+ public String getResourceId() {
return this.resourceId.getValueAsString();
}
- protected void setResourceId(String resourceId) {
+ public void setResourceId(String resourceId) {
this.resourceId.setValue(resourceId);
}
- protected boolean getRewriteBatchedStatements() {
+ public boolean getRewriteBatchedStatements() {
return this.rewriteBatchedStatements.getValueAsBoolean();
}
- protected void setRewriteBatchedStatements(boolean flag) {
+ public void setRewriteBatchedStatements(boolean flag) {
this.rewriteBatchedStatements.setValue(flag);
}
+ public boolean getJdbcCompliantTruncationForReads() {
+ return this.jdbcCompliantTruncationForReads;
+ }
+
+ public void setJdbcCompliantTruncationForReads(
+ boolean jdbcCompliantTruncationForReads) {
+ this.jdbcCompliantTruncationForReads = jdbcCompliantTruncationForReads;
+ }
+
+ public boolean getUseJvmCharsetConverters() {
+ return this.useJvmCharsetConverters.getValueAsBoolean();
+ }
+
+ public void setUseJvmCharsetConverters(boolean flag) {
+ this.useJvmCharsetConverters.setValue(flag);
+ }
+
+ public boolean getPinGlobalTxToPhysicalConnection() {
+ return this.pinGlobalTxToPhysicalConnection.getValueAsBoolean();
+ }
+
+ public void setPinGlobalTxToPhysicalConnection(boolean flag) {
+ this.pinGlobalTxToPhysicalConnection.setValue(flag);
+ }
+
/*
* "Aliases" which match the property names to make using
* from datasources easier.
@@ -3690,20 +3721,5 @@
return getPreparedStatementCacheSqlLimit();
}
- protected boolean getJdbcCompliantTruncationForReads() {
- return this.jdbcCompliantTruncationForReads;
- }
- protected void setJdbcCompliantTruncationForReads(
- boolean jdbcCompliantTruncationForReads) {
- this.jdbcCompliantTruncationForReads = jdbcCompliantTruncationForReads;
- }
-
- protected boolean getUseJvmCharsetConverters() {
- return this.useJvmCharsetConverters.getValueAsBoolean();
- }
-
- protected void setUseJvmCharsetConverters(boolean flag) {
- this.useJvmCharsetConverters.setValue(flag);
- }
}
Modified: branches/branch_5_0/connector-j/src/com/mysql/jdbc/jdbc2/optional/MysqlXADataSource.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/jdbc2/optional/MysqlXADataSource.java 2006-06-27 00:01:37 UTC (rev 5439)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/jdbc2/optional/MysqlXADataSource.java 2006-06-27 17:00:53 UTC (rev 5440)
@@ -65,6 +65,11 @@
*/
private XAConnection wrapConnection(Connection conn) throws SQLException {
+ if (getPinGlobalTxToPhysicalConnection() ||
+ ((com.mysql.jdbc.Connection)conn).getPinGlobalTxToPhysicalConnection()) {
+ return new SuspendableXAConnection((com.mysql.jdbc.Connection) conn);
+ }
+
return new MysqlXAConnection((com.mysql.jdbc.Connection) conn);
}
}
\ No newline at end of file
Added: branches/branch_5_0/connector-j/src/com/mysql/jdbc/jdbc2/optional/SuspendableXAConnection.java
===================================================================
--- branches/branch_5_0/connector-j/src/com/mysql/jdbc/jdbc2/optional/SuspendableXAConnection.java 2006-06-27 00:01:37 UTC (rev 5439)
+++ branches/branch_5_0/connector-j/src/com/mysql/jdbc/jdbc2/optional/SuspendableXAConnection.java 2006-06-27 17:00:53 UTC (rev 5440)
@@ -0,0 +1,153 @@
+package com.mysql.jdbc.jdbc2.optional;
+
+
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.sql.XAConnection;
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+import com.mysql.jdbc.Connection;
+
+public class SuspendableXAConnection extends MysqlPooledConnection implements
+XAConnection, XAResource {
+
+ public SuspendableXAConnection(Connection connection) {
+ super(connection);
+ this.underlyingConnection = connection;
+ }
+
+ private static final Map XIDS_TO_PHYSICAL_CONNECTIONS =
+ new HashMap();
+
+ private Xid currentXid;
+
+ private XAConnection currentXAConnection;
+ private XAResource currentXAResource;
+
+ private Connection underlyingConnection;
+
+ private static synchronized XAConnection findConnectionForXid(Connection connectionToWrap, Xid xid)
+ throws SQLException {
+ // TODO: check for same GTRID, but different BQUALs...MySQL doesn't allow this yet
+
+ // Note, we don't need to check for XIDs here, because MySQL itself will complain
+ // with a XAER_NOTA if need be.
+
+ XAConnection conn = (XAConnection)XIDS_TO_PHYSICAL_CONNECTIONS.get(xid);
+
+ if (conn == null) {
+ conn = new MysqlXAConnection(connectionToWrap);
+ }
+
+ return conn;
+ }
+
+ private static synchronized void removeXAConnectionMapping(Xid xid) {
+ XIDS_TO_PHYSICAL_CONNECTIONS.remove(xid);
+ }
+
+ private synchronized void switchToXid(Xid xid) throws XAException {
+ if (xid == null) {
+ throw new XAException();
+ }
+
+ try {
+ if (!xid.equals(this.currentXid)) {
+ XAConnection toSwitchTo = findConnectionForXid(this.underlyingConnection, xid);
+ this.currentXAConnection = toSwitchTo;
+ this.currentXid = xid;
+ this.currentXAResource = toSwitchTo.getXAResource();
+ }
+ } catch (SQLException sqlEx) {
+ throw new XAException();
+ }
+ }
+
+ public XAResource getXAResource() throws SQLException {
+ return this;
+ }
+
+ public void commit(Xid xid, boolean arg1) throws XAException {
+ switchToXid(xid);
+ this.currentXAResource.commit(xid, arg1);
+ removeXAConnectionMapping(xid);
+ }
+
+ public void end(Xid xid, int arg1) throws XAException {
+ switchToXid(xid);
+ this.currentXAResource.end(xid, arg1);
+ }
+
+ public void forget(Xid xid) throws XAException {
+ switchToXid(xid);
+ this.currentXAResource.forget(xid);
+ // remove?
+ removeXAConnectionMapping(xid);
+ }
+
+ public int getTransactionTimeout() throws XAException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public boolean isSameRM(XAResource xaRes) throws XAException {
+ return xaRes == this;
+ }
+
+ public int prepare(Xid xid) throws XAException {
+ switchToXid(xid);
+ return this.currentXAResource.prepare(xid);
+ }
+
+ public Xid[] recover(int flag) throws XAException {
+ return MysqlXAConnection.recover(this.underlyingConnection, flag);
+ }
+
+ public void rollback(Xid xid) throws XAException {
+ switchToXid(xid);
+ this.currentXAResource.rollback(xid);
+ removeXAConnectionMapping(xid);
+ }
+
+ public boolean setTransactionTimeout(int arg0) throws XAException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void start(Xid xid, int arg1) throws XAException {
+ switchToXid(xid);
+
+ if (arg1 != XAResource.TMJOIN) {
+ this.currentXAResource.start(xid, arg1);
+
+ return;
+ }
+
+ //
+ // Emulate join, by using resume on the same physical connection
+ //
+
+ this.currentXAResource.start(xid, XAResource.TMRESUME);
+ }
+
+ public synchronized java.sql.Connection getConnection() throws SQLException {
+ if (this.currentXAConnection == null) {
+ return getConnection(false, true);
+ }
+
+ return this.currentXAConnection.getConnection();
+ }
+
+ public void close() throws SQLException {
+ if (this.currentXAConnection == null) {
+ super.close();
+ } else {
+ removeXAConnectionMapping(this.currentXid);
+ this.currentXAConnection.close();
+ }
+ }
+}
Modified: branches/branch_5_0/connector-j/src/testsuite/BaseTestCase.java
===================================================================
--- branches/branch_5_0/connector-j/src/testsuite/BaseTestCase.java 2006-06-27 00:01:37 UTC (rev 5439)
+++ branches/branch_5_0/connector-j/src/testsuite/BaseTestCase.java 2006-06-27 17:00:53 UTC (rev 5440)
@@ -37,6 +37,7 @@
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.Properties;
import com.mysql.jdbc.NonRegisteringDriver;
@@ -546,4 +547,10 @@
}
}
}
+
+ protected boolean isRunningOnJRockit() {
+ String vmVendor = System.getProperty("java.vm.vendor");
+
+ return (vmVendor != null && vmVendor.toUpperCase(Locale.US).startsWith("BEA"));
+ }
}
Modified: branches/branch_5_0/connector-j/src/testsuite/simple/XATest.java
===================================================================
--- branches/branch_5_0/connector-j/src/testsuite/simple/XATest.java 2006-06-27 00:01:37 UTC (rev 5439)
+++ branches/branch_5_0/connector-j/src/testsuite/simple/XATest.java 2006-06-27 17:00:53 UTC (rev 5440)
@@ -337,7 +337,77 @@
}
}
}
+
+ public void testSuspendableTx() throws Exception {
+ if (!versionMeetsMinimum(5, 0) || isRunningOnJdk131()) {
+ return;
+ }
+
+ Connection conn1 = null;
+ MysqlXADataSource suspXaDs = new MysqlXADataSource();
+ suspXaDs.setUrl(BaseTestCase.dbUrl);
+ suspXaDs.setPinGlobalTxToPhysicalConnection(true);
+ suspXaDs.setRollbackOnPooledClose(true);
+
+ XAConnection xaConn1 = null;
+
+ Xid xid = createXid();
+
+ try {
+ /*
+ -- works using RESUME
+ xa start 0x123,0x456;
+ select * from foo;
+ xa end 0x123,0x456;
+ xa start 0x123,0x456 resume;
+ select * from foo;
+ xa end 0x123,0x456;
+ xa commit 0x123,0x456 one phase;
+ */
+
+ xaConn1 = suspXaDs.getXAConnection();
+ XAResource xaRes1 = xaConn1.getXAResource();
+ conn1 = xaConn1.getConnection();
+ xaRes1.start(xid, XAResource.TMNOFLAGS);
+ conn1.createStatement().executeQuery("SELECT 1");
+ xaRes1.end(xid, XAResource.TMSUCCESS);
+ xaRes1.start(xid, XAResource.TMRESUME);
+ conn1.createStatement().executeQuery("SELECT 1");
+ xaRes1.end(xid, XAResource.TMSUCCESS);
+ xaRes1.commit(xid, true);
+
+ xaConn1.close();
+
+ /*
+
+ -- fails using JOIN
+ xa start 0x123,0x456;
+ select * from foo;
+ xa end 0x123,0x456;
+ xa start 0x123,0x456 join;
+ select * from foo;
+ xa end 0x123,0x456;
+ xa commit 0x123,0x456 one phase;
+ */
+
+ xaConn1 = suspXaDs.getXAConnection();
+ xaRes1 = xaConn1.getXAResource();
+ conn1 = xaConn1.getConnection();
+ xaRes1.start(xid, XAResource.TMNOFLAGS);
+ conn1.createStatement().executeQuery("SELECT 1");
+ xaRes1.end(xid, XAResource.TMSUCCESS);
+ xaRes1.start(xid, XAResource.TMJOIN);
+ conn1.createStatement().executeQuery("SELECT 1");
+ xaRes1.end(xid, XAResource.TMSUCCESS);
+ xaRes1.commit(xid, true);
+ } finally {
+ if (xaConn1 != null) {
+ xaConn1.close();
+ }
+ }
+ }
+
private Xid createXid() throws IOException {
ByteArrayOutputStream gtridOut = new ByteArrayOutputStream();
DataOutputStream dataOut = new DataOutputStream(gtridOut);
| Thread |
|---|
| • Connector/J commit: r5440 - in branches/branch_5_0/connector-j: . src/com/mysql/jdbc src/com/mysql/jdbc/jdbc2/optional src/testsuite src/testsuite/sim... | mmatthews | 27 Jun |