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
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;
61 Db db = new Db(environment, 0);
62
63 if (isQueue) {
64 db.setFlags(Db.DB_RENUMBER);
65 }
66
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
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225 }
226 }