From 0a78be150e162aad34c19f233dc2f4ca71f61135 Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Sat, 4 Nov 2006 17:44:21 +0000 Subject: Support transaction isolation level of "none". --- .../java/com/amazon/carbonado/IsolationLevel.java | 6 +++++ .../carbonado/repo/indexed/ManagedIndex.java | 16 +++++-------- .../amazon/carbonado/repo/jdbc/JDBCRepository.java | 21 +++++++++++++---- .../carbonado/repo/jdbc/JDBCTransaction.java | 27 ++++++++++++++-------- .../repo/sleepycat/BDBTransactionManager.java | 6 +++++ .../amazon/carbonado/spi/TransactionManager.java | 4 ++++ 6 files changed, 56 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/amazon/carbonado/IsolationLevel.java b/src/main/java/com/amazon/carbonado/IsolationLevel.java index 7571205..fc8c747 100644 --- a/src/main/java/com/amazon/carbonado/IsolationLevel.java +++ b/src/main/java/com/amazon/carbonado/IsolationLevel.java @@ -47,6 +47,12 @@ package com.amazon.carbonado; */ public enum IsolationLevel { + /** + * Indicates that no actual transaction is in progress. If this level is + * specified when entering a transaction, it uses auto-commit mode. + */ + NONE, + /** * Indicates that dirty reads, non-repeatable reads and phantom reads can * occur. This level allows modifications by one transaction to be read by diff --git a/src/main/java/com/amazon/carbonado/repo/indexed/ManagedIndex.java b/src/main/java/com/amazon/carbonado/repo/indexed/ManagedIndex.java index 80ad172..bb17067 100644 --- a/src/main/java/com/amazon/carbonado/repo/indexed/ManagedIndex.java +++ b/src/main/java/com/amazon/carbonado/repo/indexed/ManagedIndex.java @@ -296,14 +296,10 @@ class ManagedIndex implements IndexEntryAccessor { void populateIndex(Repository repo, Storage masterStorage) throws RepositoryException { MergeSortBuffer buffer; Comparator c; - Transaction txn; - - if (repo.getTransactionIsolationLevel() == null) { - txn = null; - } else { - txn = repo.enterTopTransaction(IsolationLevel.READ_COMMITTED); - } + // Enter top transaction with isolation level of none to make sure + // preload operation does not run in a long nested transaction. + Transaction txn = repo.enterTopTransaction(IsolationLevel.NONE); try { Cursor cursor = masterStorage.query().fetch(); if (!cursor.hasNext()) { @@ -335,10 +331,10 @@ class ManagedIndex implements IndexEntryAccessor { while (cursor.hasNext()) { buffer.add(makeIndexEntry(cursor.next())); } + + // No need to commit transaction because no changes should have been made. } finally { - if (txn != null) { - txn.exit(); - } + txn.exit(); } buffer.sort(); diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCRepository.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCRepository.java index 3a6ec68..f9c6d25 100644 --- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCRepository.java +++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCRepository.java @@ -79,7 +79,9 @@ public class JDBCRepository static IsolationLevel mapIsolationLevelFromJdbc(int jdbcLevel) { switch (jdbcLevel) { - case Connection.TRANSACTION_READ_UNCOMMITTED: default: + case Connection.TRANSACTION_NONE: default: + return IsolationLevel.NONE; + case Connection.TRANSACTION_READ_UNCOMMITTED: return IsolationLevel.READ_UNCOMMITTED; case Connection.TRANSACTION_READ_COMMITTED: return IsolationLevel.READ_COMMITTED; @@ -92,7 +94,9 @@ public class JDBCRepository static int mapIsolationLevelToJdbc(IsolationLevel level) { switch (level) { - case READ_UNCOMMITTED: default: + case NONE: default: + return Connection.TRANSACTION_NONE; + case READ_UNCOMMITTED: return Connection.TRANSACTION_READ_UNCOMMITTED; case READ_COMMITTED: return Connection.TRANSACTION_READ_COMMITTED; @@ -513,9 +517,14 @@ public class JDBCRepository // Get connection outside synchronized section since it may block. Connection con = mDataSource.getConnection(); - con.setAutoCommit(false); - if (level != mDefaultIsolationLevel) { - con.setTransactionIsolation(mapIsolationLevelToJdbc(level)); + + if (level == IsolationLevel.NONE) { + con.setAutoCommit(true); + } else { + con.setAutoCommit(false); + if (level != mDefaultIsolationLevel) { + con.setTransactionIsolation(mapIsolationLevelToJdbc(level)); + } } synchronized (mAllTxnMgrs) { @@ -609,6 +618,8 @@ public class JDBCRepository } switch (desiredLevel) { + case NONE: + return IsolationLevel.NONE; case READ_UNCOMMITTED: return mReadUncommittedLevel; case READ_COMMITTED: diff --git a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCTransaction.java b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCTransaction.java index d92228d..832745b 100644 --- a/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCTransaction.java +++ b/src/main/java/com/amazon/carbonado/repo/jdbc/JDBCTransaction.java @@ -34,10 +34,12 @@ import com.amazon.carbonado.IsolationLevel; * @author Brian S O'Neill */ class JDBCTransaction { + // Use this magic value to indicate that the isolation level need not be + // changed when the transaction ends. This is a little optimization to + // avoid a round trip call to the remote database. + private static final int LEVEL_NOT_CHANGED = -1; + private final Connection mConnection; - // Use TRANSACTION_NONE as a magic value to indicate that the isolation - // level need not be changed when the transaction ends. This is a little - // optimization to avoid a round trip call to the remote database. private final int mOriginalLevel; private Savepoint mSavepoint; @@ -46,7 +48,7 @@ class JDBCTransaction { JDBCTransaction(Connection con) { mConnection = con; // Don't change level upon abort. - mOriginalLevel = Connection.TRANSACTION_NONE; + mOriginalLevel = LEVEL_NOT_CHANGED; } /** @@ -57,16 +59,19 @@ class JDBCTransaction { if (level == null) { // Don't change level upon abort. - mOriginalLevel = Connection.TRANSACTION_NONE; + mOriginalLevel = LEVEL_NOT_CHANGED; } else { int newLevel = JDBCRepository.mapIsolationLevelToJdbc(level); int originalLevel = mConnection.getTransactionIsolation(); if (newLevel == originalLevel) { // Don't change level upon abort. - mOriginalLevel = Connection.TRANSACTION_NONE; + mOriginalLevel = LEVEL_NOT_CHANGED; } else { - // Don't change level upon abort. + // Do change level upon abort. mOriginalLevel = originalLevel; + if (originalLevel == Connection.TRANSACTION_NONE) { + mConnection.setAutoCommit(false); + } mConnection.setTransactionIsolation(newLevel); } } @@ -105,8 +110,12 @@ class JDBCTransaction { return mConnection; } else { mConnection.rollback(mSavepoint); - if (mOriginalLevel != Connection.TRANSACTION_NONE) { - mConnection.setTransactionIsolation(mOriginalLevel); + if (mOriginalLevel != LEVEL_NOT_CHANGED) { + if (mOriginalLevel == Connection.TRANSACTION_NONE) { + mConnection.setAutoCommit(true); + } else { + mConnection.setTransactionIsolation(mOriginalLevel); + } } mSavepoint = null; return null; diff --git a/src/main/java/com/amazon/carbonado/repo/sleepycat/BDBTransactionManager.java b/src/main/java/com/amazon/carbonado/repo/sleepycat/BDBTransactionManager.java index 4c6105f..53ca5e4 100644 --- a/src/main/java/com/amazon/carbonado/repo/sleepycat/BDBTransactionManager.java +++ b/src/main/java/com/amazon/carbonado/repo/sleepycat/BDBTransactionManager.java @@ -49,6 +49,9 @@ class BDBTransactionManager extends TransactionManager { } protected Txn createTxn(Txn parent, IsolationLevel level) throws Exception { + if (level == IsolationLevel.NONE) { + return null; + } return repository().txn_begin(parent, level); } @@ -56,6 +59,9 @@ class BDBTransactionManager extends TransactionManager { protected Txn createTxn(Txn parent, IsolationLevel level, int timeout, TimeUnit unit) throws Exception { + if (level == IsolationLevel.NONE) { + return null; + } if (timeout == 0) { return repository().txn_begin_nowait(parent, level); } else { diff --git a/src/main/java/com/amazon/carbonado/spi/TransactionManager.java b/src/main/java/com/amazon/carbonado/spi/TransactionManager.java index 144b411..e8cc637 100644 --- a/src/main/java/com/amazon/carbonado/spi/TransactionManager.java +++ b/src/main/java/com/amazon/carbonado/spi/TransactionManager.java @@ -304,6 +304,8 @@ public abstract class TransactionManager { * * @param parent optional parent transaction * @param level required isolation level + * @return new transaction, parent transaction, or possibly null if required + * isolation level is none */ protected abstract Txn createTxn(Txn parent, IsolationLevel level) throws Exception; @@ -320,6 +322,8 @@ public abstract class TransactionManager { * @param level required isolation level * @param timeout desired timeout for lock acquisition, never negative * @param unit timeout unit, never null + * @return new transaction, parent transaction, or possibly null if required + * isolation level is none */ protected Txn createTxn(Txn parent, IsolationLevel level, int timeout, TimeUnit unit) -- cgit v1.2.3