1 17 18 package org.apache.geronimo.transaction.log; 19 20 import java.io.IOException ; 21 import java.io.File ; 22 import java.util.Collection ; 23 import java.util.HashMap ; 24 import java.util.Iterator ; 25 import java.util.List ; 26 import java.util.Map ; 27 import javax.transaction.xa.Xid ; 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 52 public class HOWLLog implements TransactionLog { 53 private static final byte COMMIT = 2; 56 private static final byte ROLLBACK = 3; 57 58 static final String [] TYPE_NAMES = {null, "PREPARE", "COMMIT", "ROLLBACK"}; 59 60 private static final Log log = LogFactory.getLog(HOWLLog.class); 61 62 private File serverBaseDir; 63 private String 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 recovered; 71 72 public HOWLLog(String bufferClassName, 73 int bufferSize, 74 boolean checksumEnabled, 75 boolean adler32Checksum, 76 int flushSleepTimeMilliseconds, 77 String logFileDir, 78 String logFileExt, 79 String logFileName, 80 int maxBlocksPerFile, 81 int maxBuffers, 82 int maxLogFiles, 83 int minBuffers, 84 int threadsWaitingForceThreshold, 85 XidFactory xidFactory, 86 File serverBaseDir) throws IOException , LogConfigurationException { 87 this.serverBaseDir = serverBaseDir; 88 setBufferClassName(bufferClassName); 89 setBufferSizeKBytes(bufferSize); 90 setChecksumEnabled(checksumEnabled); 91 setAdler32Checksum(adler32Checksum); 92 setFlushSleepTimeMilliseconds(flushSleepTimeMilliseconds); 93 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 getLogFileDir() { 107 return logFileDir; 108 } 109 110 public void setLogFileDir(String logDirName) { 111 File logDir = new File (logDirName); 112 if (!logDir.isAbsolute()) { 113 logDir = new File (serverBaseDir, logDirName); 114 } 115 116 this.logFileDir = logDirName; 117 if (started) { 118 configuration.setLogFileDir(logDir.getAbsolutePath()); 119 } 120 } 121 122 public String getLogFileExt() { 123 return configuration.getLogFileExt(); 124 } 125 126 public void setLogFileExt(String logFileExt) { 127 configuration.setLogFileExt(logFileExt); 128 } 129 130 public String getLogFileName() { 131 return configuration.getLogFileName(); 132 } 133 134 public void setLogFileName(String 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 getBufferClassName() { 163 return configuration.getBufferClassName(); 164 } 165 166 public void setBufferClassName(String 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 { 219 started = true; 220 setLogFileDir(logFileDir); 221 log.debug("Initiating transaction manager recovery"); 222 recovered = new HashMap (); 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 { 233 started = false; 234 logger.close(); 235 recovered = null; 236 } 237 238 public void doFail() { 239 } 240 241 public void begin(Xid xid) throws LogException { 242 } 243 244 public Object prepare(Xid xid, List 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 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 ) new IllegalStateException ().initCause(e); 261 } catch (LogRecordSizeException e) { 262 throw (IllegalStateException ) new IllegalStateException ().initCause(e); 263 } catch (LogFileOverflowException e) { 264 throw (IllegalStateException ) new IllegalStateException ().initCause(e); 265 } catch (InterruptedException e) { 266 throw (IllegalStateException ) new IllegalStateException ().initCause(e); 267 } catch (IOException e) { 268 throw new LogException(e); 269 } 270 } 271 272 public void commit(Xid xid, Object logMark) throws LogException { 273 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 } catch (LogClosedException e) { 283 throw (IllegalStateException ) new IllegalStateException ().initCause(e); 284 } catch (LogRecordSizeException e) { 285 throw (IllegalStateException ) new IllegalStateException ().initCause(e); 286 } catch (LogFileOverflowException e) { 287 throw (IllegalStateException ) new IllegalStateException ().initCause(e); 288 } catch (InterruptedException e) { 289 throw (IllegalStateException ) new IllegalStateException ().initCause(e); 290 } catch (IOException e) { 291 throw new LogException(e); 292 } 293 } 294 295 public void rollback(Xid xid, Object logMark) throws LogException { 296 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 } catch (LogClosedException e) { 306 throw (IllegalStateException ) new IllegalStateException ().initCause(e); 307 } catch (LogRecordSizeException e) { 308 throw (IllegalStateException ) new IllegalStateException ().initCause(e); 309 } catch (LogFileOverflowException e) { 310 throw (IllegalStateException ) new IllegalStateException ().initCause(e); 311 } catch (InterruptedException e) { 312 throw (IllegalStateException ) new IllegalStateException ().initCause(e); 313 } catch (IOException e) { 314 throw new LogException(e); 315 } 316 } 317 318 public Collection recover(XidFactory xidFactory) throws LogException { 319 log.debug("Initiating transaction manager recovery"); 320 Map recovered = new HashMap (); 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 getXMLStats() { 328 return logger.getStats(); 329 } 330 331 public int getAverageForceTime() { 332 return 0; } 334 335 public int getAverageBytesPerForce() { 336 return 0; } 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 recoveredTx; 356 357 public GeronimoReplayListener(XidFactory xidFactory, Map 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 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 name = new String (data[i + 1]); 382 383 Xid 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) { 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 return new LogRecord(10 * 2 * Xid.MAXBQUALSIZE); 402 } 403 404 } 405 } 406 | Popular Tags |