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 }