View Javadoc

    1   /***
    2    *
    3    * Copyright 2004 Protique Ltd
    4    *
    5    * Licensed under the Apache License, Version 2.0 (the "License");
    6    * you may not use this file except in compliance with the License.
    7    * You may obtain a copy of the License at
    8    *
    9    * http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   *
    17   **/
    18  package org.codehaus.activemq.store.bdbn;
    19
    20  import com.sleepycat.bdb.CurrentTransaction;
    21  import com.sleepycat.db.Db;
    22  import com.sleepycat.db.DbEnv;
    23  import com.sleepycat.db.DbException;
    24  import com.sleepycat.db.DbTxn;
    25  import org.apache.commons.logging.Log;
    26  import org.apache.commons.logging.LogFactory;
    27  import org.codehaus.activemq.util.JMSExceptionHelper;
    28
    29  import javax.jms.JMSException;
    30  import java.io.File;
    31  import java.io.FileNotFoundException;
    32  import java.util.LinkedList;
    33
    34  /***
    35   * Some helper factory methods for creating default configured Berkeley DB objects
    36   *
    37   * @version $Revision: 1.1 $
    38   */
    39  public class BDbHelper {
    40      private static final Log log = LogFactory.getLog(BDbHelper.class);
    41      private static ThreadLocal threadLocalTxn = new ThreadLocal();
    42      public static final int TRANSACTION_FLAGS = Db.DB_TXN_SYNC;
    43      private static DbEnv cachedEnvironment;
    44
    45      public static DbEnv createEnvironment(File dir, boolean runRecovery) throws DbException, FileNotFoundException {
    46          DbEnv env = new DbEnv(0);
    47
    48          // Open the Berkeley DB environment in transactional mode.
    49          int envFlags = Db.DB_INIT_TXN | Db.DB_INIT_LOCK | Db.DB_INIT_LOG | Db.DB_INIT_MPOOL |
    50                  Db.DB_CREATE;
    51
    52          if (runRecovery) {
    53              envFlags |= Db.DB_RECOVER;
    54          }
    55          env.open(dir.getPath(), envFlags, 0);
    56          return env;
    57      }
    58
    59      public static Db open(DbEnv environment, String name, boolean isQueue) throws FileNotFoundException, DbException, JMSException {
    60          int flags = Db.DB_CREATE; // | Db.DB_AUTO_COMMIT
    61          Db db = new Db(environment, 0);
    62
    63          if (isQueue) {
    64              db.setFlags(Db.DB_RENUMBER);
    65          }
    66          //  only use Db.DB_RECNUM for list tables as its a performance hog
    67          int type = Db.DB_BTREE;
    68          if (isQueue) {
    69              type = Db.DB_RECNO;
    70          }
    71          String databaseName = null;
    72          DbTxn transaction = createTransaction(environment);
    73          try {
    74              db.open(transaction, name, databaseName, type, flags, 0);
    75              transaction = commitTransaction(transaction);
    76          }
    77          finally {
    78              rollbackTransaction(transaction);
    79          }
    80          return db;
    81      }
    82
    83
    84      /***
    85       * @return the current thread local transaction that is in progress or null if there is no
    86       *         transaction in progress
    87       */
    88      public static DbTxn getTransaction() {
    89          LinkedList list = (LinkedList) threadLocalTxn.get();
    90          if (list != null && !list.isEmpty()) {
    91              return (DbTxn) list.getFirst();
    92          }
    93          return null;
    94      }
    95
    96      /***
    97       * Pops off the current transaction from the stack
    98       */
    99      public static DbTxn popTransaction() {
    100         LinkedList list = (LinkedList) threadLocalTxn.get();
    101         if (list == null || list.isEmpty()) {
    102             log.warn("Attempt to pop transaction when no transaction in progress");
    103             return null;
    104         }
    105         else {
    106             return (DbTxn) list.removeFirst();
    107         }
    108     }
    109
    110     /***
    111      * Sets the current transaction, possibly including nesting
    112      */
    113     public static void pushTransaction(DbTxn transaction) {
    114         LinkedList list = (LinkedList) threadLocalTxn.get();
    115         if (list == null) {
    116             list = new LinkedList();
    117             threadLocalTxn.set(list);
    118         }
    119         list.addLast(transaction);
    120     }
    121
    122     public static int getTransactionCount() {
    123         LinkedList list = (LinkedList) threadLocalTxn.get();
    124         if (list != null) {
    125             return list.size();
    126         }
    127         return 0;
    128     }
    129
    130
    131     public static DbTxn createTransaction(DbEnv environment) throws DbException {
    132         // TODO remove dirty hack!
    133         cachedEnvironment = environment;
    134         CurrentTransaction currentTxn = CurrentTransaction.getInstance(environment);
    135         return currentTxn.beginTxn();
    136         /***
    137          // TODO temporary hack until BDB supports nested transactions
    138          if (getTransactionCount() == 0) {
    139          DbTxn transaction = environment.txnBegin(getTransaction(), TRANSACTION_FLAGS);
    140          pushTransaction(transaction);
    141          return transaction;
    142          }
    143          else {
    144          DbTxn transaction = getTransaction();
    145          pushTransaction(transaction);
    146          return transaction;
    147          }
    148          */
    149     }
    150
    151
    152     /***
    153      * Commit a transaction, throwing a JMSException if a failure occurs to avoid                                                TRA
    154      * rolling back
    155      *
    156      * @param transaction
    157      * @throws javax.jms.JMSException if the transaction could not be committed
    158      */
    159     public static DbTxn commitTransaction(DbTxn transaction) throws JMSException {
    160         try {
    161             CurrentTransaction currentTxn = CurrentTransaction.getInstance(cachedEnvironment);
    162             currentTxn.commitTxn();
    163             return null;
    164         }
    165         catch (DbException e) {
    166             throw JMSExceptionHelper.newJMSException("Failed to commit transaction: " + transaction + " in container: " + e, e);
    167         }
    168
    169         /*
    170         // TODO temporary hack until BDB supports nested transactions
    171         if (getTransactionCount() == 1) {
    172             try {
    173                 transaction.commit(TRANSACTION_FLAGS);
    174                 return null;
    175             }
    176             catch (DbException e) {
    177                 throw JMSExceptionHelper.newJMSException("Failed to commit transaction: " + transaction + " in container: " + e, e);
    178             }
    179             finally {
    180                 popTransaction();
    181             }
    182         }
    183         else {
    184             popTransaction();
    185             return null;
    186         }
    187         */
    188     }
    189
    190     /***
    191      * Rolls back the transaction, catching all exceptions as we only rollback
    192      * if we are about to throw an exception anyways
    193      *
    194      * @param transaction
    195      */
    196     public static void rollbackTransaction(DbTxn transaction) {
    197         if (transaction != null) {
    198             try {
    199                 CurrentTransaction currentTxn = CurrentTransaction.getInstance(cachedEnvironment);
    200                 currentTxn.abortTxn();
    201             }
    202             catch (DbException e) {
    203                 log.warn("Cannot rollback transaction due to: " + e, e);
    204             }
    205         }
    206         /*
    207         // TODO temporary hack until BDB supports nested transactions
    208         if (transaction != null) {
    209             if (getTransactionCount() == 1) {
    210                 try {
    211                     transaction.abort();
    212                 }
    213                 catch (DbException e) {
    214                     log.warn("Cannot rollback transaction due to: " + e, e);
    215                 }
    216                 finally {
    217                     popTransaction();
    218                 }
    219             }
    220             else {
    221                 popTransaction();
    222             }
    223         }
    224         */
    225     }
    226 }