Make all connections READ COMMITTED isolation level instead of setting it everytime we get the db connection causing useless round trips

This commit is contained in:
Alex Huang 2011-07-23 14:58:32 -07:00
parent 868373c280
commit 69d928b3d1

View File

@ -78,7 +78,7 @@ public class Transaction {
public static final short CLOUD_DB = 0; public static final short CLOUD_DB = 0;
public static final short USAGE_DB = 1; public static final short USAGE_DB = 1;
public static final short CONNECTED_DB = -1; public static final short CONNECTED_DB = -1;
private static AtomicLong s_id = new AtomicLong(); private static AtomicLong s_id = new AtomicLong();
private static final TransactionMBeanImpl s_mbean = new TransactionMBeanImpl(); private static final TransactionMBeanImpl s_mbean = new TransactionMBeanImpl();
static { static {
@ -91,7 +91,7 @@ public class Transaction {
private final LinkedList<StackElement> _stack; private final LinkedList<StackElement> _stack;
private long _id; private long _id;
private final LinkedList<Pair<String, Long>> _lockTimes = new LinkedList<Pair<String, Long>>(); private final LinkedList<Pair<String, Long>> _lockTimes = new LinkedList<Pair<String, Long>>();
private String _name; private String _name;
@ -101,17 +101,17 @@ public class Transaction {
private long _txnTime; private long _txnTime;
private Statement _stmt; private Statement _stmt;
private String _creator; private String _creator;
private Transaction _prev = null; private Transaction _prev = null;
public static Transaction currentTxn() { public static Transaction currentTxn() {
Transaction txn = tls.get(); Transaction txn = tls.get();
assert txn != null : "No Transaction on stack. Did you mark the method with @DB?"; assert txn != null : "No Transaction on stack. Did you mark the method with @DB?";
assert checkAnnotation(3, txn) : "Did you even read the guide to use Transaction...IOW...other people's code? Try method can't be private. What about @DB? hmmm... could that be it? " + txn; assert checkAnnotation(3, txn) : "Did you even read the guide to use Transaction...IOW...other people's code? Try method can't be private. What about @DB? hmmm... could that be it? " + txn;
return txn; return txn;
} }
public static Transaction open(final short databaseId) { public static Transaction open(final short databaseId) {
String name = buildName(); String name = buildName();
if (name == null) { if (name == null) {
@ -130,17 +130,17 @@ public class Transaction {
_conn = conn; _conn = conn;
_dbId = CONNECTED_DB; _dbId = CONNECTED_DB;
} }
public void transitToAutoManagedConnection(short dbId) { public void transitToAutoManagedConnection(short dbId) {
// assert(_stack.size() <= 1) : "Can't change to auto managed connection unless your stack is empty"; // assert(_stack.size() <= 1) : "Can't change to auto managed connection unless your stack is empty";
_dbId = dbId; _dbId = dbId;
_conn = null; _conn = null;
} }
public static Transaction open(final String name) { public static Transaction open(final String name) {
return open(name, CLOUD_DB, false); return open(name, CLOUD_DB, false);
} }
public static Transaction open(final String name, final short databaseId, final boolean forceDbChange) { public static Transaction open(final String name, final short databaseId, final boolean forceDbChange) {
Transaction txn = tls.get(); Transaction txn = tls.get();
boolean isNew = false; boolean isNew = false;
@ -169,46 +169,46 @@ public class Transaction {
} }
return txn; return txn;
} }
protected StackElement peekInStack(Object obj) { protected StackElement peekInStack(Object obj) {
final Iterator<StackElement> it = _stack.iterator(); final Iterator<StackElement> it = _stack.iterator();
while (it.hasNext()) { while (it.hasNext()) {
StackElement next = it.next(); StackElement next = it.next();
if (next.type == obj) { if (next.type == obj) {
return next; return next;
} }
} }
return null; return null;
} }
public void registerLock(String sql) { public void registerLock(String sql) {
if (_txn && s_lockLogger.isDebugEnabled()) { if (_txn && s_lockLogger.isDebugEnabled()) {
Pair<String, Long> time = new Pair<String, Long>(sql, System.currentTimeMillis()); Pair<String, Long> time = new Pair<String, Long>(sql, System.currentTimeMillis());
_lockTimes.add(time); _lockTimes.add(time);
} }
} }
public boolean dbTxnStarted() { public boolean dbTxnStarted() {
return _txn; return _txn;
} }
public static Connection getStandaloneConnectionWithException() throws SQLException { public static Connection getStandaloneConnectionWithException() throws SQLException {
Connection conn = s_ds.getConnection(); Connection conn = s_ds.getConnection();
if (s_connLogger.isTraceEnabled()) { if (s_connLogger.isTraceEnabled()) {
s_connLogger.trace("Retrieving a standalone connection: dbconn" + System.identityHashCode(conn)); s_connLogger.trace("Retrieving a standalone connection: dbconn" + System.identityHashCode(conn));
} }
return conn; return conn;
} }
public static Connection getStandaloneConnection() { public static Connection getStandaloneConnection() {
try { try {
return getStandaloneConnectionWithException(); return getStandaloneConnectionWithException();
} catch (SQLException e) { } catch (SQLException e) {
s_logger.error("Unexpected exception: ", e); s_logger.error("Unexpected exception: ", e);
return null; return null;
} }
} }
public static Connection getStandaloneUsageConnection() { public static Connection getStandaloneUsageConnection() {
try { try {
Connection conn = s_usageDS.getConnection(); Connection conn = s_usageDS.getConnection();
@ -221,11 +221,11 @@ public class Transaction {
return null; return null;
} }
} }
protected void attach(TransactionAttachment value) { protected void attach(TransactionAttachment value) {
_stack.push(new StackElement(ATTACHMENT, value)); _stack.push(new StackElement(ATTACHMENT, value));
} }
protected TransactionAttachment detach(String name) { protected TransactionAttachment detach(String name) {
Iterator<StackElement> it = _stack.descendingIterator(); Iterator<StackElement> it = _stack.descendingIterator();
while (it.hasNext()) { while (it.hasNext()) {
@ -241,20 +241,20 @@ public class Transaction {
assert false : "Are you sure you attached this: " + name; assert false : "Are you sure you attached this: " + name;
return null; return null;
} }
public static void attachToTxn(TransactionAttachment value) { public static void attachToTxn(TransactionAttachment value) {
Transaction txn = tls.get(); Transaction txn = tls.get();
assert txn != null && txn.peekInStack(CURRENT_TXN) != null: "Come on....how can we attach something to the transaction if you haven't started it?"; assert txn != null && txn.peekInStack(CURRENT_TXN) != null: "Come on....how can we attach something to the transaction if you haven't started it?";
txn.attach(value); txn.attach(value);
} }
public static TransactionAttachment detachFromTxn(String name) { public static TransactionAttachment detachFromTxn(String name) {
Transaction txn = tls.get(); Transaction txn = tls.get();
assert txn != null : "No Transaction in TLS"; assert txn != null : "No Transaction in TLS";
return txn.detach(name); return txn.detach(name);
} }
protected static boolean checkAnnotation(int stack, Transaction txn) { protected static boolean checkAnnotation(int stack, Transaction txn) {
final StackTraceElement[] stacks = Thread.currentThread().getStackTrace(); final StackTraceElement[] stacks = Thread.currentThread().getStackTrace();
StackElement se = txn.peekInStack(CURRENT_TXN); StackElement se = txn.peekInStack(CURRENT_TXN);
@ -283,7 +283,7 @@ public class Transaction {
i++; i++;
continue; continue;
} }
str.append("-").append(stacks[i].getClassName().substring(stacks[i].getClassName().lastIndexOf(".") + 1)).append(".").append(stacks[i].getMethodName()).append(":").append(stacks[i].getLineNumber()); str.append("-").append(stacks[i].getClassName().substring(stacks[i].getClassName().lastIndexOf(".") + 1)).append(".").append(stacks[i].getMethodName()).append(":").append(stacks[i].getLineNumber());
j++; j++;
i++; i++;
@ -303,11 +303,11 @@ public class Transaction {
_id = s_id.incrementAndGet(); _id = s_id.incrementAndGet();
_creator = Thread.currentThread().getName(); _creator = Thread.currentThread().getName();
} }
public String getCreator() { public String getCreator() {
return _creator; return _creator;
} }
public long getId() { public long getId() {
return _id; return _id;
} }
@ -342,7 +342,7 @@ public class Transaction {
if (lockMaster == null) { if (lockMaster == null) {
throw new CloudRuntimeException("There's no support for locking yet"); throw new CloudRuntimeException("There's no support for locking yet");
} }
return lockMaster.acquire(name, timeoutSeconds); return lockMaster.acquire(name, timeoutSeconds);
} }
public boolean release(final String name) { public boolean release(final String name) {
@ -350,7 +350,7 @@ public class Transaction {
if (lockMaster == null) { if (lockMaster == null) {
throw new CloudRuntimeException("There's no support for locking yet"); throw new CloudRuntimeException("There's no support for locking yet");
} }
return lockMaster.release(name); return lockMaster.release(name);
} }
public void start() { public void start() {
@ -364,7 +364,7 @@ public class Transaction {
s_logger.trace("txn: has already been started."); s_logger.trace("txn: has already been started.");
return; return;
} }
_txn = true; _txn = true;
_txnTime = System.currentTimeMillis(); _txnTime = System.currentTimeMillis();
@ -378,28 +378,28 @@ public class Transaction {
} }
} }
} }
protected void closePreviousStatement() { protected void closePreviousStatement() {
if (_stmt != null) { if (_stmt != null) {
try { try {
if (s_stmtLogger.isTraceEnabled()) { if (s_stmtLogger.isTraceEnabled()) {
s_stmtLogger.trace("Closing: " + _stmt); s_stmtLogger.trace("Closing: " + _stmt);
} }
try { try {
ResultSet rs = _stmt.getResultSet(); ResultSet rs = _stmt.getResultSet();
if (rs != null && _stmt.getResultSetHoldability() != ResultSet.HOLD_CURSORS_OVER_COMMIT) { if (rs != null && _stmt.getResultSetHoldability() != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
rs.close(); rs.close();
} }
} catch(SQLException e) { } catch(SQLException e) {
s_stmtLogger.trace("Unable to close resultset"); s_stmtLogger.trace("Unable to close resultset");
} }
_stmt.close(); _stmt.close();
} catch (final SQLException e) { } catch (final SQLException e) {
s_stmtLogger.trace("Unable to close statement: " + _stmt); s_stmtLogger.trace("Unable to close statement: " + _stmt);
} finally { } finally {
_stmt = null; _stmt = null;
} }
} }
} }
/** /**
@ -413,17 +413,17 @@ public class Transaction {
* @see java.sql.Connection * @see java.sql.Connection
*/ */
public PreparedStatement prepareAutoCloseStatement(final String sql) throws SQLException { public PreparedStatement prepareAutoCloseStatement(final String sql) throws SQLException {
PreparedStatement stmt = prepareStatement(sql); PreparedStatement stmt = prepareStatement(sql);
closePreviousStatement(); closePreviousStatement();
_stmt = stmt; _stmt = stmt;
return stmt; return stmt;
} }
public PreparedStatement prepareStatement(final String sql) throws SQLException { public PreparedStatement prepareStatement(final String sql) throws SQLException {
final Connection conn = getConnection(); final Connection conn = getConnection();
final PreparedStatement pstmt = conn.prepareStatement(sql); final PreparedStatement pstmt = conn.prepareStatement(sql);
if (s_stmtLogger.isTraceEnabled()) { if (s_stmtLogger.isTraceEnabled()) {
s_stmtLogger.trace("Preparing: " + sql); s_stmtLogger.trace("Preparing: " + sql);
} }
return pstmt; return pstmt;
} }
@ -443,7 +443,7 @@ public class Transaction {
final Connection conn = getConnection(); final Connection conn = getConnection();
final PreparedStatement pstmt = conn.prepareStatement(sql, autoGeneratedKeys); final PreparedStatement pstmt = conn.prepareStatement(sql, autoGeneratedKeys);
if (s_stmtLogger.isTraceEnabled()) { if (s_stmtLogger.isTraceEnabled()) {
s_stmtLogger.trace("Preparing: " + sql); s_stmtLogger.trace("Preparing: " + sql);
} }
closePreviousStatement(); closePreviousStatement();
_stmt = pstmt; _stmt = pstmt;
@ -465,13 +465,13 @@ public class Transaction {
final Connection conn = getConnection(); final Connection conn = getConnection();
final PreparedStatement pstmt = conn.prepareStatement(sql, columnNames); final PreparedStatement pstmt = conn.prepareStatement(sql, columnNames);
if (s_stmtLogger.isTraceEnabled()) { if (s_stmtLogger.isTraceEnabled()) {
s_stmtLogger.trace("Preparing: " + sql); s_stmtLogger.trace("Preparing: " + sql);
} }
closePreviousStatement(); closePreviousStatement();
_stmt = pstmt; _stmt = pstmt;
return pstmt; return pstmt;
} }
/** /**
* Prepares an auto close statement. The statement is closed automatically if it is * Prepares an auto close statement. The statement is closed automatically if it is
* retrieved with this method. * retrieved with this method.
@ -486,7 +486,7 @@ public class Transaction {
final Connection conn = getConnection(); final Connection conn = getConnection();
final PreparedStatement pstmt = conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); final PreparedStatement pstmt = conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
if (s_stmtLogger.isTraceEnabled()) { if (s_stmtLogger.isTraceEnabled()) {
s_stmtLogger.trace("Preparing: " + sql); s_stmtLogger.trace("Preparing: " + sql);
} }
closePreviousStatement(); closePreviousStatement();
_stmt = pstmt; _stmt = pstmt;
@ -508,32 +508,31 @@ public class Transaction {
if (_conn == null) { if (_conn == null) {
switch (_dbId) { switch (_dbId) {
case CLOUD_DB: case CLOUD_DB:
if(s_ds != null) { if(s_ds != null) {
_conn = s_ds.getConnection(); _conn = s_ds.getConnection();
} else { } else {
s_logger.warn("A static-initialized variable becomes null, process is dying?"); s_logger.warn("A static-initialized variable becomes null, process is dying?");
throw new CloudRuntimeException("Database is not initialized, process is dying?"); throw new CloudRuntimeException("Database is not initialized, process is dying?");
} }
break; break;
case USAGE_DB: case USAGE_DB:
if(s_usageDS != null) { if(s_usageDS != null) {
_conn = s_usageDS.getConnection(); _conn = s_usageDS.getConnection();
} else { } else {
s_logger.warn("A static-initialized variable becomes null, process is dying?"); s_logger.warn("A static-initialized variable becomes null, process is dying?");
throw new CloudRuntimeException("Database is not initialized, process is dying?"); throw new CloudRuntimeException("Database is not initialized, process is dying?");
} }
break; break;
default: default:
throw new CloudRuntimeException("No database selected for the transaction"); throw new CloudRuntimeException("No database selected for the transaction");
} }
_conn.setAutoCommit(!_txn); _conn.setAutoCommit(!_txn);
// //
// MySQL default transaction isolation level is REPEATABLE READ, // MySQL default transaction isolation level is REPEATABLE READ,
// to reduce chances of DB deadlock, we will use READ COMMITED isolation level instead // to reduce chances of DB deadlock, we will use READ COMMITED isolation level instead
// see http://dev.mysql.com/doc/refman/5.0/en/innodb-deadlocks.html // see http://dev.mysql.com/doc/refman/5.0/en/innodb-deadlocks.html
// //
_conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
_stack.push(new StackElement(CREATE_CONN, null)); _stack.push(new StackElement(CREATE_CONN, null));
if (s_connLogger.isTraceEnabled()) { if (s_connLogger.isTraceEnabled()) {
s_connLogger.trace("Creating a DB connection with " + (_txn ? " txn: " : " no txn: ") + " for " + _dbId + ": dbconn" + System.identityHashCode(_conn) + ". Stack: " + buildName()); s_connLogger.trace("Creating a DB connection with " + (_txn ? " txn: " : " no txn: ") + " for " + _dbId + ": dbconn" + System.identityHashCode(_conn) + ". Stack: " + buildName());
@ -580,8 +579,8 @@ public class Transaction {
} }
public void cleanup() { public void cleanup() {
closePreviousStatement(); closePreviousStatement();
removeUpTo(null, null); removeUpTo(null, null);
if (_txn) { if (_txn) {
rollbackTransaction(); rollbackTransaction();
@ -590,7 +589,7 @@ public class Transaction {
_name = null; _name = null;
closeConnection(); closeConnection();
_stack.clear(); _stack.clear();
Merovingian2 lockMaster = Merovingian2.getLockMaster(); Merovingian2 lockMaster = Merovingian2.getLockMaster();
if (lockMaster != null) { if (lockMaster != null) {
@ -600,19 +599,19 @@ public class Transaction {
public void close() { public void close() {
removeUpTo(CURRENT_TXN, null); removeUpTo(CURRENT_TXN, null);
if (_stack.size() == 0) { if (_stack.size() == 0) {
s_logger.trace("Transaction is done"); s_logger.trace("Transaction is done");
cleanup(); cleanup();
} }
if(this._dbId == CONNECTED_DB) { if(this._dbId == CONNECTED_DB) {
tls.set(_prev); tls.set(_prev);
_prev = null; _prev = null;
s_mbean.removeTransaction(this); s_mbean.removeTransaction(this);
} }
} }
/** /**
* close() is used by endTxn to close the connection. This method only * close() is used by endTxn to close the connection. This method only
* closes the connection if the name is the same as what's stored. * closes the connection if the name is the same as what's stored.
@ -644,16 +643,16 @@ public class Transaction {
} }
protected boolean hasTxnInStack() { protected boolean hasTxnInStack() {
return peekInStack(START_TXN) != null; return peekInStack(START_TXN) != null;
} }
protected void clearLockTimes() { protected void clearLockTimes() {
if (s_lockLogger.isDebugEnabled()) { if (s_lockLogger.isDebugEnabled()) {
for (Pair<String, Long> time : _lockTimes) { for (Pair<String, Long> time : _lockTimes) {
s_lockLogger.trace("SQL " + time.first() + " took " + (System.currentTimeMillis() - time.second())); s_lockLogger.trace("SQL " + time.first() + " took " + (System.currentTimeMillis() - time.second()));
} }
_lockTimes.clear(); _lockTimes.clear();
} }
} }
public boolean commit() { public boolean commit() {
@ -694,8 +693,8 @@ public class Transaction {
} }
protected void closeConnection() { protected void closeConnection() {
closePreviousStatement(); closePreviousStatement();
if (_conn == null) { if (_conn == null) {
return; return;
} }
@ -712,7 +711,7 @@ public class Transaction {
if(this._dbId != CONNECTED_DB) { if(this._dbId != CONNECTED_DB) {
_conn.close(); _conn.close();
} }
_conn = null; _conn = null;
} catch (final SQLException e) { } catch (final SQLException e) {
s_logger.warn("Unable to close connection", e); s_logger.warn("Unable to close connection", e);
@ -726,12 +725,12 @@ public class Transaction {
StackElement item = it.next(); StackElement item = it.next();
it.remove(); it.remove();
try { try {
if (item.type == type && (ref == null || item.ref == ref)) { if (item.type == type && (ref == null || item.ref == ref)) {
break; break;
} }
if (item.type == CURRENT_TXN) { if (item.type == CURRENT_TXN) {
if (s_logger.isTraceEnabled()) { if (s_logger.isTraceEnabled()) {
s_logger.trace("Releasing the current txn: " + (item.ref != null ? item.ref : "")); s_logger.trace("Releasing the current txn: " + (item.ref != null ? item.ref : ""));
@ -755,37 +754,37 @@ public class Transaction {
s_stmtLogger.trace("Closing: " + ref); s_stmtLogger.trace("Closing: " + ref);
} }
Statement stmt = (Statement)ref; Statement stmt = (Statement)ref;
try { try {
ResultSet rs = stmt.getResultSet(); ResultSet rs = stmt.getResultSet();
if (rs != null) { if (rs != null) {
rs.close(); rs.close();
} }
} catch(SQLException e) { } catch(SQLException e) {
s_stmtLogger.trace("Unable to close resultset"); s_stmtLogger.trace("Unable to close resultset");
} }
stmt.close(); stmt.close();
} catch (final SQLException e) { } catch (final SQLException e) {
s_stmtLogger.trace("Unable to close statement: " + item); s_stmtLogger.trace("Unable to close statement: " + item);
} }
} else if (item.type == ATTACHMENT) { } else if (item.type == ATTACHMENT) {
TransactionAttachment att = (TransactionAttachment)item.ref; TransactionAttachment att = (TransactionAttachment)item.ref;
if (s_logger.isTraceEnabled()) { if (s_logger.isTraceEnabled()) {
s_logger.trace("Cleaning up " + att.getName()); s_logger.trace("Cleaning up " + att.getName());
} }
att.cleanup(); att.cleanup();
} }
} catch(Exception e) { } catch(Exception e) {
s_logger.error("Unable to clean up " + item, e); s_logger.error("Unable to clean up " + item, e);
} }
} }
if (rollback) { if (rollback) {
rollback(); rollback();
} }
} }
protected void rollbackTransaction() { protected void rollbackTransaction() {
closePreviousStatement(); closePreviousStatement();
if (!_txn) { if (!_txn) {
if (s_logger.isTraceEnabled()) { if (s_logger.isTraceEnabled()) {
s_logger.trace("Rollback called for " + _name + " when there's no transaction: " + buildName()); s_logger.trace("Rollback called for " + _name + " when there's no transaction: " + buildName());
@ -807,7 +806,7 @@ public class Transaction {
s_logger.warn("Unable to rollback", e); s_logger.warn("Unable to rollback", e);
} }
} }
protected void rollbackSavepoint(Savepoint sp) { protected void rollbackSavepoint(Savepoint sp) {
try { try {
if (_conn != null) { if (_conn != null) {
@ -816,7 +815,7 @@ public class Transaction {
} catch (SQLException e) { } catch (SQLException e) {
s_logger.warn("Unable to rollback to savepoint " + sp); s_logger.warn("Unable to rollback to savepoint " + sp);
} }
if (!hasTxnInStack()) { if (!hasTxnInStack()) {
_txn = false; _txn = false;
closeConnection(); closeConnection();
@ -836,7 +835,7 @@ public class Transaction {
} }
} }
} }
rollbackTransaction(); rollbackTransaction();
} }
@ -867,13 +866,13 @@ public class Transaction {
if (_conn != null) { if (_conn != null) {
_conn.releaseSavepoint(sp); _conn.releaseSavepoint(sp);
} }
if (!hasTxnInStack()) { if (!hasTxnInStack()) {
_txn = false; _txn = false;
closeConnection(); closeConnection();
} }
} }
protected boolean hasSavepointInStack(Savepoint sp) { protected boolean hasSavepointInStack(Savepoint sp) {
Iterator<StackElement> it = _stack.iterator(); Iterator<StackElement> it = _stack.iterator();
while (it.hasNext()) { while (it.hasNext()) {
@ -884,14 +883,14 @@ public class Transaction {
} }
return false; return false;
} }
protected void removeTxn(Savepoint sp) { protected void removeTxn(Savepoint sp) {
assert hasSavepointInStack(sp) : "Removing a save point that's not in the stack"; assert hasSavepointInStack(sp) : "Removing a save point that's not in the stack";
if (!hasSavepointInStack(sp)) { if (!hasSavepointInStack(sp)) {
return; return;
} }
Iterator<StackElement> it = _stack.iterator(); Iterator<StackElement> it = _stack.iterator();
while (it.hasNext()) { while (it.hasNext()) {
StackElement se = it.next(); StackElement se = it.next();
@ -906,26 +905,26 @@ public class Transaction {
public void rollback(final Savepoint sp) { public void rollback(final Savepoint sp) {
removeTxn(sp); removeTxn(sp);
rollbackSavepoint(sp); rollbackSavepoint(sp);
} }
public Connection getCurrentConnection() { public Connection getCurrentConnection() {
return _conn; return _conn;
} }
public List<StackElement> getStack() { public List<StackElement> getStack() {
return _stack; return _stack;
} }
protected Transaction() { protected Transaction() {
_name = null; _name = null;
_conn = null; _conn = null;
_stack = null; _stack = null;
_txn = false; _txn = false;
_dbId = -1; _dbId = -1;
} }
@Override @Override
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
if (!(_conn == null && (_stack == null || _stack.size() == 0))) { if (!(_conn == null && (_stack == null || _stack.size() == 0))) {
@ -934,22 +933,22 @@ public class Transaction {
cleanup(); cleanup();
} }
} }
protected class StackElement { protected class StackElement {
public String type; public String type;
public Object ref; public Object ref;
public StackElement (String type, Object ref) { public StackElement (String type, Object ref) {
this.type = type; this.type = type;
this.ref = ref; this.ref = ref;
} }
@Override @Override
public String toString() { public String toString() {
return type + "-" + ref; return type + "-" + ref;
} }
} }
private static DataSource s_ds; private static DataSource s_ds;
private static DataSource s_usageDS; private static DataSource s_usageDS;
static { static {
@ -969,6 +968,21 @@ public class Transaction {
final String cloudDbName = dbProps.getProperty("db.cloud.name"); final String cloudDbName = dbProps.getProperty("db.cloud.name");
final boolean cloudAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.cloud.autoReconnect")); final boolean cloudAutoReconnect = Boolean.parseBoolean(dbProps.getProperty("db.cloud.autoReconnect"));
final String cloudValidationQuery = dbProps.getProperty("db.cloud.validationQuery"); final String cloudValidationQuery = dbProps.getProperty("db.cloud.validationQuery");
final String cloudIsolationLevel = dbProps.getProperty("db.cloud.isolation.level");
int isolationLevel = Connection.TRANSACTION_READ_COMMITTED;
if (cloudIsolationLevel == null) {
isolationLevel = Connection.TRANSACTION_READ_COMMITTED;
} else if (cloudIsolationLevel.equalsIgnoreCase("readcommitted")) {
isolationLevel = Connection.TRANSACTION_READ_COMMITTED;
} else if (cloudIsolationLevel.equalsIgnoreCase("repeatableread")) {
isolationLevel = Connection.TRANSACTION_REPEATABLE_READ;
} else if (cloudIsolationLevel.equalsIgnoreCase("serializable")) {
isolationLevel = Connection.TRANSACTION_SERIALIZABLE;
} else if (cloudIsolationLevel.equalsIgnoreCase("readuncommitted")) {
isolationLevel = Connection.TRANSACTION_READ_UNCOMMITTED;
} else {
s_logger.warn("Unknown isolation level " + cloudIsolationLevel + ". Using read uncommitted");
}
final boolean cloudTestOnBorrow = Boolean.parseBoolean(dbProps.getProperty("db.cloud.testOnBorrow")); final boolean cloudTestOnBorrow = Boolean.parseBoolean(dbProps.getProperty("db.cloud.testOnBorrow"));
final boolean cloudTestWhileIdle = Boolean.parseBoolean(dbProps.getProperty("db.cloud.testWhileIdle")); final boolean cloudTestWhileIdle = Boolean.parseBoolean(dbProps.getProperty("db.cloud.testWhileIdle"));
final long cloudTimeBtwEvictionRunsMillis = Long.parseLong(dbProps.getProperty("db.cloud.timeBetweenEvictionRunsMillis")); final long cloudTimeBtwEvictionRunsMillis = Long.parseLong(dbProps.getProperty("db.cloud.timeBetweenEvictionRunsMillis"));
@ -985,7 +999,7 @@ public class Transaction {
"?autoReconnect="+cloudAutoReconnect + (url != null ? "&" + url : ""), cloudUsername, cloudPassword); "?autoReconnect="+cloudAutoReconnect + (url != null ? "&" + url : ""), cloudUsername, cloudPassword);
final KeyedObjectPoolFactory poolableObjFactory = (cloudPoolPreparedStatements ? new StackKeyedObjectPoolFactory() : null); final KeyedObjectPoolFactory poolableObjFactory = (cloudPoolPreparedStatements ? new StackKeyedObjectPoolFactory() : null);
final PoolableConnectionFactory cloudPoolableConnectionFactory = new PoolableConnectionFactory(cloudConnectionFactory, cloudConnectionPool, poolableObjFactory, final PoolableConnectionFactory cloudPoolableConnectionFactory = new PoolableConnectionFactory(cloudConnectionFactory, cloudConnectionPool, poolableObjFactory,
cloudValidationQuery, false, false); cloudValidationQuery, false, false, isolationLevel);
s_ds = new PoolingDataSource(cloudPoolableConnectionFactory.getPool()); s_ds = new PoolingDataSource(cloudPoolableConnectionFactory.getPool());
// configure the usage db // configure the usage db