From 0a78be150e162aad34c19f233dc2f4ca71f61135 Mon Sep 17 00:00:00 2001
From: "Brian S. O'Neill" <bronee@gmail.com>
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(-)

(limited to 'src/main/java/com')

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<S extends Storable> implements IndexEntryAccessor<S> {
     void populateIndex(Repository repo, Storage<S> 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<S> cursor = masterStorage.query().fetch();
             if (!cursor.hasNext()) {
@@ -335,10 +331,10 @@ class ManagedIndex<S extends Storable> implements IndexEntryAccessor<S> {
             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<Txn> extends TransactionManager<Txn> {
     }
 
     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<Txn> extends TransactionManager<Txn> {
     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<Txn> {
      *
      * @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<Txn> {
      * @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