Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

CurrentTransaction.java

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 2000-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: CurrentTransaction.java,v 12.3 2005/08/01 20:25:17 mark Exp $
00008  */
00009 
00010 package com.sleepycat.collections;
00011 
00012 import java.util.ArrayList;
00013 import java.util.List;
00014 import java.util.WeakHashMap;
00015 
00016 import com.sleepycat.compat.DbCompat;
00017 import com.sleepycat.db.Cursor;
00018 import com.sleepycat.db.CursorConfig;
00019 import com.sleepycat.db.Database;
00020 import com.sleepycat.db.DatabaseException;
00021 import com.sleepycat.db.Environment;
00022 import com.sleepycat.db.EnvironmentConfig;
00023 import com.sleepycat.db.LockMode;
00024 import com.sleepycat.db.Transaction;
00025 import com.sleepycat.db.TransactionConfig;
00026 import com.sleepycat.util.RuntimeExceptionWrapper;
00027 
00037 public class CurrentTransaction {
00038 
00039     /* For internal use, this class doubles as an Environment wrapper. */
00040 
00041     private static WeakHashMap envMap = new WeakHashMap();
00042 
00043     private LockMode writeLockMode;
00044     private boolean cdbMode;
00045     private boolean txnMode;
00046     private Environment env;
00047     private ThreadLocal localTrans = new ThreadLocal();
00048     private ThreadLocal localCdbCursors;
00049 
00060     public static CurrentTransaction getInstance(Environment env) {
00061 
00062         CurrentTransaction currentTxn = getInstanceInternal(env);
00063         return currentTxn.isTxnMode() ? currentTxn : null;
00064     }
00065 
00072     static CurrentTransaction getInstanceInternal(Environment env) {
00073         synchronized (envMap) {
00074             CurrentTransaction myEnv = (CurrentTransaction) envMap.get(env);
00075             if (myEnv == null) {
00076                 myEnv = new CurrentTransaction(env);
00077                 envMap.put(env, myEnv);
00078             }
00079             return myEnv;
00080         }
00081     }
00082 
00083     private CurrentTransaction(Environment env) {
00084         this.env = env;
00085         try {
00086             EnvironmentConfig config = env.getConfig();
00087             txnMode = config.getTransactional();
00088             if (txnMode || DbCompat.getInitializeLocking(config)) {
00089                 writeLockMode = LockMode.RMW;
00090             } else {
00091                 writeLockMode = LockMode.DEFAULT;
00092             }
00093             cdbMode = DbCompat.getInitializeCDB(config);
00094             if (cdbMode) {
00095                 localCdbCursors = new ThreadLocal();
00096             }
00097         } catch (DatabaseException e) {
00098             throw new RuntimeExceptionWrapper(e);
00099         }
00100     }
00101 
00105     final boolean isTxnMode() {
00106 
00107         return txnMode;
00108     }
00109 
00113     final boolean isCdbMode() {
00114 
00115         return cdbMode;
00116     }
00117 
00124     final LockMode getWriteLockMode() {
00125 
00126         return writeLockMode;
00127     }
00128 
00132     public final Environment getEnvironment() {
00133 
00134         return env;
00135     }
00136 
00141     public final Transaction getTransaction() {
00142 
00143         Trans trans = (Trans) localTrans.get();
00144         return (trans != null) ? trans.txn : null;
00145     }
00146 
00152     boolean isAutoCommitAllowed()
00153         throws DatabaseException {
00154 
00155         return getTransaction() == null &&
00156                DbCompat.getThreadTransaction(env) == null;
00157     }
00158 
00176     public final Transaction beginTransaction(TransactionConfig config)
00177         throws DatabaseException {
00178 
00179         Trans trans = (Trans) localTrans.get();
00180         if (trans != null) {
00181             if (trans.txn != null) {
00182                 if (!DbCompat.NESTED_TRANSACTIONS) {
00183                     throw new IllegalStateException(
00184                             "Nested transactions are not supported");
00185                 }
00186                 Transaction parentTxn = trans.txn;
00187                 trans = new Trans(trans, config);
00188                 trans.txn = env.beginTransaction(parentTxn, config);
00189                 localTrans.set(trans);
00190             } else {
00191                 trans.txn = env.beginTransaction(null, config);
00192                 trans.config = config;
00193             }
00194         } else {
00195             trans = new Trans(null, config);
00196             trans.txn = env.beginTransaction(null, config);
00197             localTrans.set(trans);
00198         }
00199         return trans.txn;
00200     }
00201 
00217     public final Transaction commitTransaction()
00218         throws DatabaseException, IllegalStateException {
00219 
00220         Trans trans = (Trans) localTrans.get();
00221         if (trans != null && trans.txn != null) {
00222             Transaction parent = closeTxn(trans);
00223             trans.txn.commit();
00224             return parent;
00225         } else {
00226             throw new IllegalStateException("No transaction is active");
00227         }
00228     }
00229 
00245     public final Transaction abortTransaction()
00246         throws DatabaseException, IllegalStateException {
00247 
00248         Trans trans = (Trans) localTrans.get();
00249         if (trans != null && trans.txn != null) {
00250             Transaction parent = closeTxn(trans);
00251             trans.txn.abort();
00252             return parent;
00253         } else {
00254             throw new IllegalStateException("No transaction is active");
00255         }
00256     }
00257 
00262     final boolean isReadUncommitted() {
00263 
00264         Trans trans = (Trans) localTrans.get();
00265         if (trans != null && trans.config != null) {
00266             return trans.config.getReadUncommitted();
00267         } else {
00268             return false;
00269         }
00270     }
00271 
00272     private Transaction closeTxn(Trans trans) {
00273 
00274         localTrans.set(trans.parent);
00275         return (trans.parent != null) ? trans.parent.txn : null;
00276     }
00277 
00278     private static class Trans {
00279 
00280         private Trans parent;
00281         private Transaction txn;
00282         private TransactionConfig config;
00283 
00284         private Trans(Trans parent, TransactionConfig config) {
00285 
00286             this.parent = parent;
00287             this.config = config;
00288         }
00289     }
00290 
00295     Cursor openCursor(Database db, CursorConfig cursorConfig,
00296                       boolean writeCursor, Transaction txn)
00297         throws DatabaseException {
00298 
00299         if (cdbMode) {
00300             CdbCursors cdbCursors = null;
00301             WeakHashMap cdbCursorsMap = (WeakHashMap) localCdbCursors.get();
00302             if (cdbCursorsMap == null) {
00303                 cdbCursorsMap = new WeakHashMap();
00304                 localCdbCursors.set(cdbCursorsMap);
00305             } else {
00306                 cdbCursors = (CdbCursors) cdbCursorsMap.get(db);
00307             }
00308             if (cdbCursors == null) {
00309                 cdbCursors = new CdbCursors();
00310                 cdbCursorsMap.put(db, cdbCursors);
00311             }
00312 
00313             /*
00314              * In CDB mode the cursorConfig specified by the user is ignored
00315              * and only the writeCursor parameter is honored.  This is the only
00316              * meaningful cursor attribute for CDB, and here we count on
00317              * writeCursor flag being set correctly by the caller.
00318              */
00319             List cursors;
00320             CursorConfig cdbConfig;
00321             if (writeCursor) {
00322                 if (cdbCursors.readCursors.size() > 0) {
00323                     
00324                     /*
00325                      * Although CDB allows opening a write cursor when a read
00326                      * cursor is open, a self-deadlock will occur if a write is
00327                      * attempted for a record that is read-locked; we should
00328                      * avoid self-deadlocks at all costs
00329                      */
00330                     throw new IllegalStateException(
00331                       "cannot open CDB write cursor when read cursor is open");
00332                 }
00333                 cursors = cdbCursors.writeCursors;
00334                 cdbConfig = new CursorConfig();
00335                 DbCompat.setWriteCursor(cdbConfig, true);
00336             } else {
00337                 cursors = cdbCursors.readCursors;
00338                 cdbConfig = null;
00339             }
00340             Cursor cursor;
00341             if (cursors.size() > 0) {
00342                 Cursor other = ((Cursor) cursors.get(0));
00343                 cursor = other.dup(false);
00344             } else {
00345                 cursor = db.openCursor(null, cdbConfig);
00346             }
00347             cursors.add(cursor);
00348             return cursor;
00349         } else {
00350             return db.openCursor(txn, cursorConfig);
00351         }
00352     }
00353 
00366     Cursor dupCursor(Cursor cursor, boolean writeCursor, boolean samePosition)
00367         throws DatabaseException {
00368 
00369         if (cdbMode) {
00370             WeakHashMap cdbCursorsMap = (WeakHashMap) localCdbCursors.get();
00371             if (cdbCursorsMap != null) {
00372                 Database db = cursor.getDatabase();
00373                 CdbCursors cdbCursors = (CdbCursors) cdbCursorsMap.get(db);
00374                 if (cdbCursors != null) {
00375                     List cursors = writeCursor ? cdbCursors.writeCursors
00376                                                : cdbCursors.readCursors;
00377                     if (cursors.contains(cursor)) {
00378                         Cursor newCursor = cursor.dup(samePosition);
00379                         cursors.add(newCursor);
00380                         return newCursor;
00381                     }
00382                 }
00383             }
00384             throw new IllegalStateException("cursor to dup not tracked");
00385         } else {
00386             return cursor.dup(samePosition);
00387         }
00388     }
00389 
00397     void closeCursor(Cursor cursor)
00398         throws DatabaseException {
00399 
00400         if (cursor == null) {
00401             return;
00402         }
00403         if (cdbMode) {
00404             WeakHashMap cdbCursorsMap = (WeakHashMap) localCdbCursors.get();
00405             if (cdbCursorsMap != null) {
00406                 Database db = cursor.getDatabase();
00407                 CdbCursors cdbCursors = (CdbCursors) cdbCursorsMap.get(db);
00408                 if (cdbCursors != null) {
00409                     if (cdbCursors.readCursors.remove(cursor) ||
00410                         cdbCursors.writeCursors.remove(cursor)) {
00411                         cursor.close();
00412                         return;
00413                     }
00414                 }
00415             }
00416             throw new IllegalStateException(
00417               "closing CDB cursor that was not known to be open");
00418         } else {
00419             cursor.close();
00420         }
00421     }
00422 
00427     boolean isCDBCursorOpen(Database db)
00428         throws DatabaseException {
00429 
00430         if (cdbMode) {
00431             WeakHashMap cdbCursorsMap = (WeakHashMap) localCdbCursors.get();
00432             if (cdbCursorsMap != null) {
00433                 CdbCursors cdbCursors = (CdbCursors) cdbCursorsMap.get(db);
00434 
00435                 if (cdbCursors != null &&
00436                     (cdbCursors.readCursors.size() > 0 ||
00437                      cdbCursors.writeCursors.size() > 0)) {
00438                     return true;
00439                 }
00440             }
00441         }
00442         return false;
00443     }
00444 
00445     static final class CdbCursors {
00446 
00447         List writeCursors = new ArrayList();
00448         List readCursors = new ArrayList();
00449     }
00450 }

Generated on Sun Dec 25 12:14:31 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2