KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > geronimo > transaction > log > HOWLLog


1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. 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.apache.geronimo.transaction.log;
19
20 import java.io.IOException JavaDoc;
21 import java.io.File JavaDoc;
22 import java.util.Collection JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.Map JavaDoc;
27 import javax.transaction.xa.Xid JavaDoc;
28
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31 import org.apache.geronimo.transaction.manager.LogException;
32 import org.apache.geronimo.transaction.manager.Recovery;
33 import org.apache.geronimo.transaction.manager.TransactionBranchInfo;
34 import org.apache.geronimo.transaction.manager.TransactionBranchInfoImpl;
35 import org.apache.geronimo.transaction.manager.TransactionLog;
36 import org.apache.geronimo.transaction.manager.XidFactory;
37 import org.objectweb.howl.log.Configuration;
38 import org.objectweb.howl.log.LogClosedException;
39 import org.objectweb.howl.log.LogConfigurationException;
40 import org.objectweb.howl.log.LogFileOverflowException;
41 import org.objectweb.howl.log.LogRecord;
42 import org.objectweb.howl.log.LogRecordSizeException;
43 import org.objectweb.howl.log.LogRecordType;
44 import org.objectweb.howl.log.ReplayListener;
45 import org.objectweb.howl.log.xa.XACommittingTx;
46 import org.objectweb.howl.log.xa.XALogRecord;
47 import org.objectweb.howl.log.xa.XALogger;
48
49 /**
50  * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
51  */

52 public class HOWLLog implements TransactionLog {
53 // static final byte PREPARE = 1;
54
//these are used as debugging aids only
55
private static final byte COMMIT = 2;
56     private static final byte ROLLBACK = 3;
57
58     static final String JavaDoc[] TYPE_NAMES = {null, "PREPARE", "COMMIT", "ROLLBACK"};
59
60     private static final Log log = LogFactory.getLog(HOWLLog.class);
61
62     private File JavaDoc serverBaseDir;
63     private String JavaDoc logFileDir;
64
65     private final XidFactory xidFactory;
66
67     private final XALogger logger;
68     private final Configuration configuration = new Configuration();
69     private boolean started = false;
70     private HashMap JavaDoc recovered;
71
72     public HOWLLog(String JavaDoc bufferClassName,
73                    int bufferSize,
74                    boolean checksumEnabled,
75                    boolean adler32Checksum,
76                    int flushSleepTimeMilliseconds,
77                    String JavaDoc logFileDir,
78                    String JavaDoc logFileExt,
79                    String JavaDoc logFileName,
80                    int maxBlocksPerFile,
81                    int maxBuffers,
82                    int maxLogFiles,
83                    int minBuffers,
84                    int threadsWaitingForceThreshold,
85                    XidFactory xidFactory,
86                    File JavaDoc serverBaseDir) throws IOException JavaDoc, LogConfigurationException {
87         this.serverBaseDir = serverBaseDir;
88         setBufferClassName(bufferClassName);
89         setBufferSizeKBytes(bufferSize);
90         setChecksumEnabled(checksumEnabled);
91         setAdler32Checksum(adler32Checksum);
92         setFlushSleepTimeMilliseconds(flushSleepTimeMilliseconds);
93         //setLogFileDir(logFileDir);
94
this.logFileDir = logFileDir;
95         setLogFileExt(logFileExt);
96         setLogFileName(logFileName);
97         setMaxBlocksPerFile(maxBlocksPerFile);
98         setMaxBuffers(maxBuffers);
99         setMaxLogFiles(maxLogFiles);
100         setMinBuffers(minBuffers);
101         setThreadsWaitingForceThreshold(threadsWaitingForceThreshold);
102         this.xidFactory = xidFactory;
103         this.logger = new XALogger(configuration);
104     }
105
106     public String JavaDoc getLogFileDir() {
107         return logFileDir;
108     }
109
110     public void setLogFileDir(String JavaDoc logDirName) {
111         File JavaDoc logDir = new File JavaDoc(logDirName);
112         if (!logDir.isAbsolute()) {
113             logDir = new File JavaDoc(serverBaseDir, logDirName);
114         }
115
116         this.logFileDir = logDirName;
117         if (started) {
118             configuration.setLogFileDir(logDir.getAbsolutePath());
119         }
120     }
121
122     public String JavaDoc getLogFileExt() {
123         return configuration.getLogFileExt();
124     }
125
126     public void setLogFileExt(String JavaDoc logFileExt) {
127         configuration.setLogFileExt(logFileExt);
128     }
129
130     public String JavaDoc getLogFileName() {
131         return configuration.getLogFileName();
132     }
133
134     public void setLogFileName(String JavaDoc logFileName) {
135         configuration.setLogFileName(logFileName);
136     }
137
138     public boolean isChecksumEnabled() {
139         return configuration.isChecksumEnabled();
140     }
141
142     public void setChecksumEnabled(boolean checksumOption) {
143         configuration.setChecksumEnabled(checksumOption);
144     }
145
146     public boolean isAdler32ChecksumEnabled() {
147         return configuration.isAdler32ChecksumEnabled();
148     }
149
150     public void setAdler32Checksum(boolean checksumOption) {
151         configuration.setAdler32Checksum(checksumOption);
152     }
153
154     public int getBufferSizeKBytes() {
155         return configuration.getBufferSize();
156     }
157
158     public void setBufferSizeKBytes(int bufferSize) throws LogConfigurationException {
159         configuration.setBufferSize(bufferSize);
160     }
161
162     public String JavaDoc getBufferClassName() {
163         return configuration.getBufferClassName();
164     }
165
166     public void setBufferClassName(String JavaDoc bufferClassName) {
167         configuration.setBufferClassName(bufferClassName);
168     }
169
170     public int getMaxBuffers() {
171         return configuration.getMaxBuffers();
172     }
173
174     public void setMaxBuffers(int maxBuffers) throws LogConfigurationException {
175         configuration.setMaxBuffers(maxBuffers);
176     }
177
178     public int getMinBuffers() {
179         return configuration.getMinBuffers();
180     }
181
182     public void setMinBuffers(int minBuffers) throws LogConfigurationException {
183         configuration.setMinBuffers(minBuffers);
184     }
185
186     public int getFlushSleepTimeMilliseconds() {
187         return configuration.getFlushSleepTime();
188     }
189
190     public void setFlushSleepTimeMilliseconds(int flushSleepTime) {
191         configuration.setFlushSleepTime(flushSleepTime);
192     }
193
194     public int getThreadsWaitingForceThreshold() {
195         return configuration.getThreadsWaitingForceThreshold();
196     }
197
198     public void setThreadsWaitingForceThreshold(int threadsWaitingForceThreshold) {
199         configuration.setThreadsWaitingForceThreshold(threadsWaitingForceThreshold == -1 ? Integer.MAX_VALUE : threadsWaitingForceThreshold);
200     }
201
202     public int getMaxBlocksPerFile() {
203         return configuration.getMaxBlocksPerFile();
204     }
205
206     public void setMaxBlocksPerFile(int maxBlocksPerFile) {
207         configuration.setMaxBlocksPerFile(maxBlocksPerFile == -1 ? Integer.MAX_VALUE : maxBlocksPerFile);
208     }
209
210     public int getMaxLogFiles() {
211         return configuration.getMaxLogFiles();
212     }
213
214     public void setMaxLogFiles(int maxLogFiles) {
215         configuration.setMaxLogFiles(maxLogFiles);
216     }
217
218     public void doStart() throws Exception JavaDoc {
219         started = true;
220         setLogFileDir(logFileDir);
221         log.debug("Initiating transaction manager recovery");
222         recovered = new HashMap JavaDoc();
223
224         logger.open(null);
225
226         ReplayListener replayListener = new GeronimoReplayListener(xidFactory, recovered);
227         logger.replayActiveTx(replayListener);
228
229         log.debug("In doubt transactions recovered from log");
230     }
231
232     public void doStop() throws Exception JavaDoc {
233         started = false;
234         logger.close();
235         recovered = null;
236     }
237
238     public void doFail() {
239     }
240
241     public void begin(Xid JavaDoc xid) throws LogException {
242     }
243
244     public Object JavaDoc prepare(Xid JavaDoc xid, List JavaDoc branches) throws LogException {
245         int branchCount = branches.size();
246         byte[][] data = new byte[3 + 2 * branchCount][];
247         data[0] = intToBytes(xid.getFormatId());
248         data[1] = xid.getGlobalTransactionId();
249         data[2] = xid.getBranchQualifier();
250         int i = 3;
251         for (Iterator JavaDoc iterator = branches.iterator(); iterator.hasNext();) {
252             TransactionBranchInfo transactionBranchInfo = (TransactionBranchInfo) iterator.next();
253             data[i++] = transactionBranchInfo.getBranchXid().getBranchQualifier();
254             data[i++] = transactionBranchInfo.getResourceName().getBytes();
255         }
256         try {
257             XACommittingTx committingTx = logger.putCommit(data);
258             return committingTx;
259         } catch (LogClosedException e) {
260             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
261         } catch (LogRecordSizeException e) {
262             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
263         } catch (LogFileOverflowException e) {
264             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
265         } catch (InterruptedException JavaDoc e) {
266             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
267         } catch (IOException JavaDoc e) {
268             throw new LogException(e);
269         }
270     }
271
272     public void commit(Xid JavaDoc xid, Object JavaDoc logMark) throws LogException {
273         //the data is theoretically unnecessary but is included to help with debugging and because HOWL currently requires it.
274
byte[][] data = new byte[4][];
275         data[0] = new byte[]{COMMIT};
276         data[1] = intToBytes(xid.getFormatId());
277         data[2] = xid.getGlobalTransactionId();
278         data[3] = xid.getBranchQualifier();
279         try {
280             logger.putDone(data, (XACommittingTx) logMark);
281 // logger.putDone(null, (XACommittingTx) logMark);
282
} catch (LogClosedException e) {
283             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
284         } catch (LogRecordSizeException e) {
285             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
286         } catch (LogFileOverflowException e) {
287             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
288         } catch (InterruptedException JavaDoc e) {
289             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
290         } catch (IOException JavaDoc e) {
291             throw new LogException(e);
292         }
293     }
294
295     public void rollback(Xid JavaDoc xid, Object JavaDoc logMark) throws LogException {
296         //the data is theoretically unnecessary but is included to help with debugging and because HOWL currently requires it.
297
byte[][] data = new byte[4][];
298         data[0] = new byte[]{ROLLBACK};
299         data[1] = intToBytes(xid.getFormatId());
300         data[2] = xid.getGlobalTransactionId();
301         data[3] = xid.getBranchQualifier();
302         try {
303             logger.putDone(data, (XACommittingTx) logMark);
304 // logger.putDone(null, (XACommittingTx) logMark);
305
} catch (LogClosedException e) {
306             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
307         } catch (LogRecordSizeException e) {
308             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
309         } catch (LogFileOverflowException e) {
310             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
311         } catch (InterruptedException JavaDoc e) {
312             throw (IllegalStateException JavaDoc) new IllegalStateException JavaDoc().initCause(e);
313         } catch (IOException JavaDoc e) {
314             throw new LogException(e);
315         }
316     }
317
318     public Collection JavaDoc recover(XidFactory xidFactory) throws LogException {
319         log.debug("Initiating transaction manager recovery");
320         Map JavaDoc recovered = new HashMap JavaDoc();
321         ReplayListener replayListener = new GeronimoReplayListener(xidFactory, recovered);
322         logger.replayActiveTx(replayListener);
323         log.debug("In doubt transactions recovered from log");
324         return recovered.values();
325     }
326
327     public String JavaDoc getXMLStats() {
328         return logger.getStats();
329     }
330
331     public int getAverageForceTime() {
332         return 0;//logger.getAverageForceTime();
333
}
334
335     public int getAverageBytesPerForce() {
336         return 0;//logger.getAverageBytesPerForce();
337
}
338
339     private byte[] intToBytes(int formatId) {
340         byte[] buffer = new byte[4];
341         buffer[0] = (byte) (formatId >> 24);
342         buffer[1] = (byte) (formatId >> 16);
343         buffer[2] = (byte) (formatId >> 8);
344         buffer[3] = (byte) (formatId >> 0);
345         return buffer;
346     }
347
348     private int bytesToInt(byte[] buffer) {
349         return ((int) buffer[0]) << 24 + ((int) buffer[1]) << 16 + ((int) buffer[2]) << 8 + ((int) buffer[3]) << 0;
350     }
351
352     private class GeronimoReplayListener implements ReplayListener {
353
354         private final XidFactory xidFactory;
355         private final Map JavaDoc recoveredTx;
356
357         public GeronimoReplayListener(XidFactory xidFactory, Map JavaDoc recoveredTx) {
358             this.xidFactory = xidFactory;
359             this.recoveredTx = recoveredTx;
360         }
361
362         public void onRecord(LogRecord plainlr) {
363             XALogRecord lr = (XALogRecord) plainlr;
364             short recordType = lr.type;
365             XACommittingTx tx = lr.getTx();
366             if (recordType == LogRecordType.XACOMMIT) {
367
368                 byte[][] data = tx.getRecord();
369
370                 assert data[0].length == 4;
371                 int formatId = bytesToInt(data[1]);
372                 byte[] globalId = data[1];
373                 byte[] branchId = data[2];
374                 Xid JavaDoc masterXid = xidFactory.recover(formatId, globalId, branchId);
375
376                 Recovery.XidBranchesPair xidBranchesPair = new Recovery.XidBranchesPair(masterXid, tx);
377                 recoveredTx.put(masterXid, xidBranchesPair);
378                 log.debug("recovered prepare record for master xid: " + masterXid);
379                 for (int i = 3; i < data.length; i += 2) {
380                     byte[] branchBranchId = data[i];
381                     String JavaDoc name = new String JavaDoc(data[i + 1]);
382
383                     Xid JavaDoc branchXid = xidFactory.recover(formatId, globalId, branchBranchId);
384                     TransactionBranchInfoImpl branchInfo = new TransactionBranchInfoImpl(branchXid, name);
385                     xidBranchesPair.addBranch(branchInfo);
386                     log.debug("recovered branch for resource manager, branchId " + name + ", " + branchXid);
387                 }
388             } else {
389                 if(recordType != LogRecordType.END_OF_LOG) { // This value crops up every time the server is started
390
log.warn("Received unexpected log record: " + lr +" ("+recordType+")");
391                 }
392             }
393         }
394
395         public void onError(org.objectweb.howl.log.LogException exception) {
396             log.error("Error during recovery: ", exception);
397         }
398
399         public LogRecord getLogRecord() {
400             //TODO justify this size estimate
401
return new LogRecord(10 * 2 * Xid.MAXBQUALSIZE);
402         }
403
404     }
405 }
406
Popular Tags