djencks 2004/06/19 10:17:13
Modified: modules/transaction project.properties project.xml modules/transaction/src/java/org/apache/geronimo/transaction/manager RecoveryImpl.java XidFactoryImpl.java modules/transaction/src/test/org/apache/geronimo/transaction/log AbstractLogTest.java modules/transaction/src/test/org/apache/geronimo/transaction/manager XATransactionTester.java Added: modules/transaction/src/java/org/apache/geronimo/transaction/log HOWLLog.java modules/transaction/src/test/org/apache/geronimo/transaction/log HOWLLogTest.java modules/transaction/src/test/org/apache/geronimo/transaction/manager AbstractRecoveryTest.java HOWLLogRecoveryTest.java MockLogRecoveryTest.java Log: Transaction logger based on HOWL logger and some basic recovery tests Revision Changes Path 1.4 +2 -4 incubator-geronimo/modules/transaction/project.properties Index: project.properties =================================================================== RCS file: /home/cvs/incubator-geronimo/modules/transaction/project.properties,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- project.properties 27 Apr 2004 00:55:48 -0000 1.3 +++ project.properties 19 Jun 2004 17:17:13 -0000 1.4 @@ -2,6 +2,4 @@ ## $Revision$ $Date$ ## -# the directory containing the geronimo website in CVS - -maven.repo.remote=http://dist.codehaus.org, http://www.ibiblio.org/maven +maven.repo.remote=http://www.apache.org/~djencks/maven, http://www.ibiblio.org/maven 1.15 +6 -6 incubator-geronimo/modules/transaction/project.xml Index: project.xml =================================================================== RCS file: /home/cvs/incubator-geronimo/modules/transaction/project.xml,v retrieving revision 1.14 retrieving revision 1.15 diff -u -r1.14 -r1.15 --- project.xml 6 May 2004 04:00:51 -0000 1.14 +++ project.xml 19 Jun 2004 17:17:13 -0000 1.15 @@ -77,19 +77,19 @@ </dependency> <!--this is an experimental version compiled by David Jencks--> - <!--dependency> + <dependency> <groupId>howl</groupId> <artifactId>howl-logger</artifactId> - <version>SNAPSHOT</version> + <version>GERONIMO-PRIVATE-0.1</version> <url>http://www.objectweb.org</url> - </dependency--> + </dependency> - <!--dependency> + <dependency> <groupId>pyrasun</groupId> <artifactId>PyrasunLog</artifactId> <version>0.2_Alpha</version> <url>http://www.krisnmike.com/mike</url> - </dependency--> + </dependency> <dependency> <groupId>tranql</groupId> 1.1 incubator-geronimo/modules/transaction/src/java/org/apache/geronimo/transaction/log/HOWLLog.java Index: HOWLLog.java =================================================================== /** * * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.geronimo.transaction.log; import java.io.IOException; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.transaction.xa.Xid; import org.apache.geronimo.gbean.GBeanLifecycle; import org.apache.geronimo.gbean.WaitingException; import org.apache.geronimo.gbean.GBeanInfoFactory; import org.apache.geronimo.gbean.GBeanInfo; import org.apache.geronimo.transaction.manager.LogException; import org.apache.geronimo.transaction.manager.TransactionBranchInfo; import org.apache.geronimo.transaction.manager.TransactionBranchInfoImpl; import org.apache.geronimo.transaction.manager.TransactionLog; import org.apache.geronimo.transaction.manager.XidFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.objectweb.howl.log.LogClosedException; import org.objectweb.howl.log.LogConfigurationException; import org.objectweb.howl.log.LogFileOverflowException; import org.objectweb.howl.log.LogRecord; import org.objectweb.howl.log.LogRecordSizeException; import org.objectweb.howl.log.Logger; import org.objectweb.howl.log.ReplayListener; import org.objectweb.howl.log.LogRecordType; import org.objectweb.howl.log.Configuration; /** * * * @version $Revision: 1.1 $ $Date: 2004/06/19 17:17:13 $ * * */ public class HOWLLog implements TransactionLog, GBeanLifecycle { static final byte PREPARE = 1; static final byte COMMIT = 2; static final byte ROLLBACK = 3; static final String[] TYPE_NAMES = {null, "PREPARE", "COMMIT", "ROLLBACK"}; private static final Log log = LogFactory.getLog(HOWLLog.class); private final Logger logger; private final Configuration configuration = new Configuration(); public HOWLLog( String bufferClassName, int bufferSize, boolean checksumEnabled, int flushSleepTime, String logFileDir, String logFileExt, String logFileName, int maxBlocksPerFile, int maxBuffers, int maxLogFiles, int minBuffers, int threadsWaitingForceThreshold ) throws IOException { setBufferClassName(bufferClassName); setBufferSizeKBytes(bufferSize); setChecksumEnabled(checksumEnabled); setFlushSleepTime(flushSleepTime); setLogFileDir(logFileDir); setLogFileExt(logFileExt); setLogFileName(logFileName); setMaxBlocksPerFile(maxBlocksPerFile); setMaxBuffers(maxBuffers); setMaxLogFiles(maxLogFiles); setMinBuffers(minBuffers); setThreadsWaitingForceThreshold(threadsWaitingForceThreshold); this.logger = new Logger(configuration); } public String getLogFileDir() { return configuration.getLogFileDir(); } public void setLogFileDir(String logDir) { configuration.setLogFileDir(logDir); } public String getLogFileExt() { return configuration.getLogFileExt(); } public void setLogFileExt(String logFileExt) { configuration.setLogFileExt(logFileExt); } public String getLogFileName() { return configuration.getLogFileName(); } public void setLogFileName(String logFileName) { configuration.setLogFileName(logFileName); } public boolean isChecksumEnabled() { return configuration.isChecksumEnabled(); } public void setChecksumEnabled(boolean checksumOption) { configuration.setChecksumEnabled(checksumOption); } public int getBufferSizeKBytes() { return configuration.getBufferSize(); } public void setBufferSizeKBytes(int bufferSize) { configuration.setBufferSize(bufferSize); } public String getBufferClassName() { return configuration.getBufferClassName(); } public void setBufferClassName(String bufferClassName) { configuration.setBufferClassName(bufferClassName); } public int getMaxBuffers() { return configuration.getMaxBuffers(); } public void setMaxBuffers(int maxBuffers) { configuration.setMaxBuffers(maxBuffers); } public int getMinBuffers() { return configuration.getMinBuffers(); } public void setMinBuffers(int minBuffers) { configuration.setMinBuffers(minBuffers); } public int getFlushSleepTime() { return configuration.getFlushSleepTime(); } public void setFlushSleepTime(int flushSleepTime) { configuration.setFlushSleepTime(flushSleepTime); } public int getThreadsWaitingForceThreshold() { return configuration.getThreadsWaitingForceThreshold(); } public void setThreadsWaitingForceThreshold(int threadsWaitingForceThreshold) { configuration.setThreadsWaitingForceThreshold(threadsWaitingForceThreshold); } public int getMaxBlocksPerFile() { return configuration.getMaxBlocksPerFile(); } public void setMaxBlocksPerFile(int maxBlocksPerFile) { configuration.setMaxBlocksPerFile(maxBlocksPerFile); } public int getMaxLogFiles() { return configuration.getMaxLogFiles(); } public void setMaxLogFiles(int maxLogFiles) { configuration.setMaxLogFiles(maxLogFiles); } public void doStart() throws WaitingException, Exception { logger.open(); } public void doStop() throws WaitingException, Exception { logger.close(); } public void doFail() { } public void begin(Xid xid) throws LogException { } public void prepare(Xid xid, List branches) throws LogException { int branchCount = branches.size(); byte[][] data = new byte[4 + 2 * branchCount][]; data[0] = new byte[]{PREPARE}; data[1] = intToBytes(xid.getFormatId()); data[2] = xid.getGlobalTransactionId(); data[3] = xid.getBranchQualifier(); int i = 4; for (Iterator iterator = branches.iterator(); iterator.hasNext();) { TransactionBranchInfo transactionBranchInfo = (TransactionBranchInfo) iterator.next(); data[i++] = transactionBranchInfo.getBranchXid().getBranchQualifier(); data[i++] = transactionBranchInfo.getResourceName().getBytes(); } try { logger.put(data, true); } catch (LogClosedException e) { throw (IllegalStateException) new IllegalStateException().initCause(e); } catch (LogRecordSizeException e) { throw (IllegalStateException) new IllegalStateException().initCause(e); } catch (LogFileOverflowException e) { throw (IllegalStateException) new IllegalStateException().initCause(e); } catch (InterruptedException e) { throw (IllegalStateException) new IllegalStateException().initCause(e); } catch (IOException e) { throw new LogException(e); } } public void commit(Xid xid) throws LogException { byte[][] data = new byte[4][]; data[0] = new byte[]{COMMIT}; data[1] = intToBytes(xid.getFormatId()); data[2] = xid.getGlobalTransactionId(); data[3] = xid.getBranchQualifier(); try { logger.put(data, false); } catch (LogClosedException e) { throw (IllegalStateException) new IllegalStateException().initCause(e); } catch (LogRecordSizeException e) { throw (IllegalStateException) new IllegalStateException().initCause(e); } catch (LogFileOverflowException e) { throw (IllegalStateException) new IllegalStateException().initCause(e); } catch (InterruptedException e) { throw (IllegalStateException) new IllegalStateException().initCause(e); } catch (IOException e) { throw new LogException(e); } } public void rollback(Xid xid) throws LogException { byte[][] data = new byte[4][]; data[0] = new byte[]{ROLLBACK}; data[1] = intToBytes(xid.getFormatId()); data[2] = xid.getGlobalTransactionId(); data[3] = xid.getBranchQualifier(); try { logger.put(data, false); } catch (LogClosedException e) { throw (IllegalStateException) new IllegalStateException().initCause(e); } catch (LogRecordSizeException e) { throw (IllegalStateException) new IllegalStateException().initCause(e); } catch (LogFileOverflowException e) { throw (IllegalStateException) new IllegalStateException().initCause(e); } catch (InterruptedException e) { throw (IllegalStateException) new IllegalStateException().initCause(e); } catch (IOException e) { throw new LogException(e); } } public Map recover(XidFactory xidFactory) throws LogException { log.info("Initiating transaction manager recovery"); Map recovered = new HashMap(); ReplayListener replayListener = new GeronimoReplayListener(xidFactory, recovered, log); try { logger.replay(replayListener); } catch (LogConfigurationException e) { throw new LogException(e); } return recovered; } public String getXMLStats() { return logger.getStats(); } public int getAverageForceTime() { return 0;//logger.getAverageForceTime(); } public int getAverageBytesPerForce() { return 0;//logger.getAverageBytesPerForce(); } private byte[] intToBytes(int formatId) { byte[] buffer = new byte[4]; buffer[0] = (byte) (formatId >> 24); buffer[1] = (byte) (formatId >> 16); buffer[2] = (byte) (formatId >> 8); buffer[3] = (byte) (formatId >> 0); return buffer; } private static class GeronimoReplayListener implements ReplayListener { private final XidFactory xidFactory; private final Map recoveredTx; private final Log log; public GeronimoReplayListener(XidFactory xidFactory, Map recoveredTx, Log log) { this.xidFactory = xidFactory; this.recoveredTx = recoveredTx; this.log = log; } public void onRecord(LogRecord lr) { short recordType = lr.type; if (recordType != LogRecordType.USER) { if (recordType != LogRecordType.END_OF_LOG) { log.warn("Received unexpected log record: " + lr); } return; } ByteBuffer raw = lr.dataBuffer; if (raw.remaining() == 0) { log.warn("Received empty log record of user type!"); return; } //type (PREPARE etc) short size = raw.getShort(); assert size == 1; byte type = raw.get(); //format id integer size = raw.getShort(); assert size == 4; int formatId = raw.getInt(); //global id int globalIdLength = raw.getShort(); byte[] globalId = new byte[globalIdLength]; raw.get(globalId); //branch qualifier for master xid int branchIdLength = raw.getShort(); byte[] branchId = new byte[branchIdLength]; raw.get(branchId); Xid masterXid = xidFactory.recover(formatId, globalId, branchId); if (type == PREPARE) { Set branches = new HashSet(); recoveredTx.put(masterXid, branches); log.info("recovered prepare record for master xid: " + masterXid); while (raw.hasRemaining()) { int branchBranchIdLength = raw.getShort(); byte[] branchBranchId = new byte[branchBranchIdLength]; raw.get(branchBranchId); Xid branchXid = xidFactory.recover(formatId, globalId, branchBranchId); int nameLength = raw.getShort(); byte[] nameBytes = new byte[nameLength]; raw.get(nameBytes); String name = new String(nameBytes); TransactionBranchInfoImpl branchInfo = new TransactionBranchInfoImpl(branchXid, name); branches.add(branchInfo); log.info("recovered branch for resource manager, branchId " + name + ", " + branchXid); } } else if (type == COMMIT || type == ROLLBACK) { Object o = recoveredTx.remove(masterXid); log.info("Recovered " + TYPE_NAMES[type] + " for xid: " + masterXid + " and branches: " + o); } else { log.error("Unknown recovery record received, type byte: " + type + ", buffer: " + raw); } } public void onError(org.objectweb.howl.log.LogException exception) { log.error("Error during recovery: ", exception); } public LogRecord getLogRecord() { //TODO justify this size estimate return new LogRecord(10 * 2 * Xid.MAXBQUALSIZE); } } public static final GBeanInfo GBEAN_INFO; static { GBeanInfoFactory infoFactory = new GBeanInfoFactory(HOWLLog.class); infoFactory.addAttribute("bufferClassName", String.class, true); infoFactory.addAttribute("bufferSizeKBytes", Integer.TYPE, true); infoFactory.addAttribute("checksumEnabled", Boolean.TYPE, true); infoFactory.addAttribute("flushSleepTime", Integer.TYPE, true); infoFactory.addAttribute("logFileDir", String.class, true); infoFactory.addAttribute("logFileExt", String.class, true); infoFactory.addAttribute("logFileName", String.class, true); infoFactory.addAttribute("maxBlocksPerFile", Integer.TYPE, true); infoFactory.addAttribute("maxBuffers", Integer.TYPE, true); infoFactory.addAttribute("maxLogFiles", Integer.TYPE, true); infoFactory.addAttribute("minBuffers", Integer.TYPE, true); infoFactory.addAttribute("threadsWaitingForceThreshold", Integer.TYPE, true); infoFactory.setConstructor(new String[] { "bufferClassName", "bufferSizeKBytes", "checksumEnabled", "flushSleepTime", "logFileDir", "logFileExt", "logFileName", "maxBlocksPerFile", "maxBuffers", "maxLogFiles", "minBuffers", "threadsWaitingForceThreshold"}); GBEAN_INFO = infoFactory.getBeanInfo(); } public static GBeanInfo getGBeanInfo() { return GBEAN_INFO; } } 1.2 +3 -1 incubator-geronimo/modules/transaction/src/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java Index: RecoveryImpl.java =================================================================== RCS file: /home/cvs/incubator-geronimo/modules/transaction/src/java/org/apache/geronimo/transaction/manager/RecoveryImpl.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- RecoveryImpl.java 11 Jun 2004 19:20:55 -0000 1.1 +++ RecoveryImpl.java 19 Jun 2004 17:17:13 -0000 1.2 @@ -70,6 +70,7 @@ Map.Entry entry = (Map.Entry) iterator.next(); Xid xid = (Xid) entry.getKey(); if (xidFactory.matchesGlobalId(xid.getGlobalTransactionId())) { + Object o = entry.getValue(); XidBranchesPair xidBranchesPair = new XidBranchesPair(xid, (Set) entry.getValue()); ourXids.put(new ByteArrayWrapper(xid.getGlobalTransactionId()), xidBranchesPair); for (Iterator branches = xidBranchesPair.branches.iterator(); branches.hasNext();) { @@ -81,6 +82,7 @@ transactionsForName.add(xidBranchesPair); } } else { + Object o = entry.getValue(); TransactionImpl externalTx = new ExternalTransaction(xid, txLog, (Set) entry.getValue()); externalXids.put(xid, externalTx); externalGlobalIdMap.put(xid.getGlobalTransactionId(), externalTx); 1.4 +5 -5 incubator-geronimo/modules/transaction/src/java/org/apache/geronimo/transaction/manager/XidFactoryImpl.java Index: XidFactoryImpl.java =================================================================== RCS file: /home/cvs/incubator-geronimo/modules/transaction/src/java/org/apache/geronimo/transaction/manager/XidFactoryImpl.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- XidFactoryImpl.java 8 Jun 2004 17:33:43 -0000 1.3 +++ XidFactoryImpl.java 19 Jun 2004 17:17:13 -0000 1.4 @@ -19,9 +19,9 @@ import java.net.InetAddress; import java.net.UnknownHostException; + import javax.transaction.xa.Xid; -import org.apache.geronimo.transaction.log.XidImpl2; import org.apache.geronimo.gbean.GBeanInfo; import org.apache.geronimo.gbean.GBeanInfoFactory; @@ -72,7 +72,7 @@ globalId[5] = (byte) (id >>> 40); globalId[6] = (byte) (id >>> 48); globalId[7] = (byte) (id >>> 56); - return new XidImpl2(globalId); + return new XidImpl(globalId); } public Xid createBranch(Xid globalId, int branch) { @@ -81,7 +81,7 @@ branchId[1] = (byte) (branch >>> 8); branchId[2] = (byte) (branch >>> 16); branchId[3] = (byte) (branch >>> 24); - return new XidImpl2(globalId, branchId); + return new XidImpl(globalId, branchId); } public boolean matchesGlobalId(byte[] globalTransactionId) { @@ -109,7 +109,7 @@ } public Xid recover(int formatId, byte[] globalTransactionid, byte[] branchQualifier) { - return new XidImpl2(formatId, globalTransactionid, branchQualifier); + return new XidImpl(formatId, globalTransactionid, branchQualifier); } public static final GBeanInfo GBEAN_INFO; 1.4 +2 -2 incubator-geronimo/modules/transaction/src/test/org/apache/geronimo/transaction/log/AbstractLogTest.java Index: AbstractLogTest.java =================================================================== RCS file: /home/cvs/incubator-geronimo/modules/transaction/src/test/org/apache/geronimo/transaction/log/AbstractLogTest.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- AbstractLogTest.java 11 Jun 2004 19:20:55 -0000 1.3 +++ AbstractLogTest.java 19 Jun 2004 17:17:13 -0000 1.4 @@ -50,7 +50,7 @@ public void testDummy() throws Exception {} - public void xtestTransactionLog() throws Exception { + public void testTransactionLog() throws Exception { File resultFileXML = new File(getResultFileName() + ".xml"); resultsXML = new FileWriter(resultFileXML); resultsXML.write("<log-test>\n"); 1.1 incubator-geronimo/modules/transaction/src/test/org/apache/geronimo/transaction/log/HOWLLogTest.java Index: HOWLLogTest.java =================================================================== /** * * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.geronimo.transaction.log; import java.io.IOException; import javax.transaction.xa.Xid; import junit.framework.TestCase; import org.apache.geronimo.transaction.manager.TransactionLog; import org.objectweb.howl.log.LogClosedException; import org.objectweb.howl.log.LogFileOverflowException; import org.objectweb.howl.log.Logger; /** * * * @version $Revision: 1.1 $ $Date: 2004/06/19 17:17:13 $ * * */ public class HOWLLogTest extends AbstractLogTest { protected String getResultFileName() { return "howllog"; } protected void closeTransactionLog(TransactionLog transactionLog) throws Exception { ((HOWLLog) transactionLog).doStop(); } protected TransactionLog createTransactionLog() throws Exception { HOWLLog howlLog = new HOWLLog( "org.objectweb.howl.log.BlockLogBuffer", // "bufferClassName", 4, // "bufferSizeKBytes", true, // "checksumEnabled", 20, // "flushSleepTime", "target", // "logFileDir", "log", // "logFileExt", "howl_test_", // "logFileName", 200, // "maxBlocksPerFile", 10, // "maxBuffers", 2, // "maxLogFiles", 2, // "minBuffers", 10// "threadsWaitingForceThreshold"}); ); howlLog.doStart(); return howlLog; } } 1.7 +2 -2 incubator-geronimo/modules/transaction/src/test/org/apache/geronimo/transaction/manager/XATransactionTester.java Index: XATransactionTester.java =================================================================== RCS file: /home/cvs/incubator-geronimo/modules/transaction/src/test/org/apache/geronimo/transaction/manager/XATransactionTester.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- XATransactionTester.java 11 Jun 2004 19:20:55 -0000 1.6 +++ XATransactionTester.java 19 Jun 2004 17:17:13 -0000 1.7 @@ -95,7 +95,7 @@ */ private XADataSource getDataSource(String[] args) throws Exception { // oracle.jdbc.xa.client.OracleXADataSource ds = new oracle.jdbc.xa.client.OracleXADataSource(); -// ds.setURL("jdbc:oracle:thin:@localhost:1521:ABU"); +// ds.setConnectionURL("jdbc:oracle:thin:@localhost:1521:ABU"); // return ds; return null; } 1.1 incubator-geronimo/modules/transaction/src/test/org/apache/geronimo/transaction/manager/AbstractRecoveryTest.java Index: AbstractRecoveryTest.java =================================================================== /** * * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.geronimo.transaction.manager; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import junit.framework.TestCase; /** * This is just a unit test for recovery, depending on proper behavior of the log(s) it uses. * * @version $Revision: 1.1 $ $Date: 2004/06/19 17:17:13 $ * * */ public abstract class AbstractRecoveryTest extends TestCase { protected TransactionLog txLog; private final XidFactory xidFactory = new XidFactoryImpl(); private static final String RM1 = "rm1"; private static final String RM2 = "rm2"; private static final String RM3 = "rm3"; private static final int XID_COUNT = 3; private int branchCounter; public void testDummy() throws Exception {} public void test2ResOnlineAfterRecoveryStart() throws Exception { Xid[] xids = getXidArray(XID_COUNT); MockXAResource xares1 = new MockXAResource(RM1, xids); MockXAResource xares2 = new MockXAResource(RM2, xids); MockTransactionInfo[] txInfos = makeTxInfos(xids); addBranch(txInfos, xares1); addBranch(txInfos, xares2); prepareLog(txLog, txInfos); prepareForReplay(); Recovery recovery = new RecoveryImpl(txLog, xidFactory); recovery.recoverLog(); assertTrue(!recovery.hasRecoveryErrors()); assertTrue(recovery.getExternalXids().isEmpty()); assertTrue(!recovery.localRecoveryComplete()); recovery.recoverResourceManager(xares1); assertTrue(!recovery.localRecoveryComplete()); assertEquals(XID_COUNT, xares1.committed.size()); recovery.recoverResourceManager(xares2); assertEquals(XID_COUNT, xares2.committed.size()); assertTrue(recovery.localRecoveryComplete()); } public void test3ResOnlineAfterRecoveryStart() throws Exception { Xid[] xids12 = getXidArray(XID_COUNT); List xids12List = Arrays.asList(xids12); Xid[] xids13 = getXidArray(XID_COUNT); List xids13List = Arrays.asList(xids13); Xid[] xids23 = getXidArray(XID_COUNT); List xids23List = Arrays.asList(xids23); ArrayList tmp = new ArrayList(); tmp.addAll(xids12List); tmp.addAll(xids13List); Xid[] xids1 = (Xid[]) tmp.toArray(new Xid[6]); tmp.clear(); tmp.addAll(xids12List); tmp.addAll(xids23List); Xid[] xids2 = (Xid[]) tmp.toArray(new Xid[6]); tmp.clear(); tmp.addAll(xids13List); tmp.addAll(xids23List); Xid[] xids3 = (Xid[]) tmp.toArray(new Xid[6]); MockXAResource xares1 = new MockXAResource(RM1, xids1); MockXAResource xares2 = new MockXAResource(RM2, xids2); MockXAResource xares3 = new MockXAResource(RM3, xids3); MockTransactionInfo[] txInfos12 = makeTxInfos(xids12); addBranch(txInfos12, xares1); addBranch(txInfos12, xares2); prepareLog(txLog, txInfos12); MockTransactionInfo[] txInfos13 = makeTxInfos(xids13); addBranch(txInfos13, xares1); addBranch(txInfos13, xares3); prepareLog(txLog, txInfos13); MockTransactionInfo[] txInfos23 = makeTxInfos(xids23); addBranch(txInfos23, xares2); addBranch(txInfos23, xares3); prepareLog(txLog, txInfos23); prepareForReplay(); Recovery recovery = new RecoveryImpl(txLog, xidFactory); recovery.recoverLog(); assertTrue(!recovery.hasRecoveryErrors()); assertTrue(recovery.getExternalXids().isEmpty()); assertEquals(XID_COUNT * 3, recovery.localUnrecoveredCount()); recovery.recoverResourceManager(xares1); assertEquals(XID_COUNT * 3, recovery.localUnrecoveredCount()); assertEquals(XID_COUNT * 2, xares1.committed.size()); recovery.recoverResourceManager(xares2); assertEquals(XID_COUNT * 2, recovery.localUnrecoveredCount()); assertEquals(XID_COUNT * 2, xares2.committed.size()); recovery.recoverResourceManager(xares3); assertEquals(0, recovery.localUnrecoveredCount()); assertEquals(XID_COUNT * 2, xares3.committed.size()); } protected abstract void prepareForReplay() throws Exception; private void prepareLog(TransactionLog txLog, MockTransactionInfo[] txInfos) throws LogException { for (int i = 0; i < txInfos.length; i++) { MockTransactionInfo txInfo = txInfos[i]; txLog.prepare(txInfo.globalXid, txInfo.branches); } } private Xid[] getXidArray(int i) { Xid[] xids = new Xid[i]; for (int j = 0; j < xids.length; j++) { xids[j] = xidFactory.createXid(); } return xids; } private void addBranch(MockTransactionInfo[] txInfos, MockXAResource xaRes) { for (int i = 0; i < txInfos.length; i++) { MockTransactionInfo txInfo = txInfos[i]; Xid globalXid = txInfo.globalXid; Xid branchXid = xidFactory.createBranch(globalXid, branchCounter++); txInfo.branches.add(new MockTransactionBranchInfo(xaRes.getName(), branchXid)); } } private MockTransactionInfo[] makeTxInfos(Xid[] xids) { MockTransactionInfo[] txInfos = new MockTransactionInfo[xids.length]; for (int i = 0; i < xids.length; i++) { Xid xid = xids[i]; txInfos[i] = new MockTransactionInfo(xid, new ArrayList()); } return txInfos; } private static class MockXAResource implements NamedXAResource { private final String name; private final Xid[] xids; private final List committed = new ArrayList(); private final List rolledBack = new ArrayList(); public MockXAResource(String name, Xid[] xids) { this.name = name; this.xids = xids; } public String getName() { return name; } public void commit(Xid xid, boolean onePhase) throws XAException { committed.add(xid); } public void end(Xid xid, int flags) throws XAException { } public void forget(Xid xid) throws XAException { } public int getTransactionTimeout() throws XAException { return 0; } public boolean isSameRM(XAResource xaResource) throws XAException { return false; } public int prepare(Xid xid) throws XAException { return 0; } public Xid[] recover(int flag) throws XAException { return xids; } public void rollback(Xid xid) throws XAException { rolledBack.add(xid); } public boolean setTransactionTimeout(int seconds) throws XAException { return false; } public void start(Xid xid, int flags) throws XAException { } public List getCommitted() { return committed; } public List getRolledBack() { return rolledBack; } } private static class MockTransactionInfo { private Xid globalXid; private List branches; public MockTransactionInfo(Xid globalXid, List branches) { this.globalXid = globalXid; this.branches = branches; } } private static class MockTransactionBranchInfo implements TransactionBranchInfo { private final String name; private final Xid branchXid; public MockTransactionBranchInfo(String name, Xid branchXid) { this.name = name; this.branchXid = branchXid; } public String getResourceName() { return name; } public Xid getBranchXid() { return branchXid; } } } 1.1 incubator-geronimo/modules/transaction/src/test/org/apache/geronimo/transaction/manager/HOWLLogRecoveryTest.java Index: HOWLLogRecoveryTest.java =================================================================== /** * * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.geronimo.transaction.manager; import java.io.File; import org.apache.geronimo.transaction.log.HOWLLog; import junit.framework.Test; import junit.framework.TestSuite; import junit.extensions.TestSetup; /** * * * @version $Revision: 1.1 $ $Date: 2004/06/19 17:17:13 $ * * */ public class HOWLLogRecoveryTest extends AbstractRecoveryTest { public void test2Again() throws Exception { test2ResOnlineAfterRecoveryStart(); } public void test3Again() throws Exception { test3ResOnlineAfterRecoveryStart(); } protected void setUp() throws Exception { HOWLLog howlLog = new HOWLLog( "org.objectweb.howl.log.BlockLogBuffer", // "bufferClassName", 4, // "bufferSizeKBytes", true, // "checksumEnabled", 20, // "flushSleepTime", "target", // "logFileDir", "log", // "logFileExt", "howl_test_", // "logFileName", 200, // "maxBlocksPerFile", 10, // "maxBuffers", 2, // "maxLogFiles", 2, // "minBuffers", 10// "threadsWaitingForceThreshold"}); ); howlLog.doStart(); txLog = howlLog; } protected void tearDown() throws Exception { ((HOWLLog)txLog).doStop(); txLog = null; } protected void prepareForReplay() throws Exception { tearDown(); setUp(); } public static Test suite() { return new TestSetup(new TestSuite(HOWLLogRecoveryTest.class)) { protected void setUp() throws Exception { File logFile = new File("target/howl_1.log"); if (logFile.exists()) { logFile.delete(); } logFile = new File("target/howl_2.log"); if (logFile.exists()) { logFile.delete(); } } }; } } 1.1 incubator-geronimo/modules/transaction/src/test/org/apache/geronimo/transaction/manager/MockLogRecoveryTest.java Index: MockLogRecoveryTest.java =================================================================== /** * * Copyright 2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.geronimo.transaction.manager; /** * * * @version $Revision: 1.1 $ $Date: 2004/06/19 17:17:13 $ * * */ public class MockLogRecoveryTest extends AbstractRecoveryTest { protected void setUp() throws Exception { txLog = new MockLog(); } protected void tearDown() throws Exception { txLog = null; } protected void prepareForReplay() throws Exception { } }