/*
* #%L
* Wisdom-Framework
* %%
* Copyright (C) 2013 - 2014 Wisdom Framework
* %%
* 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.
* #L%
*/
package org.wisdom.framework.transaction.impl;
import org.apache.geronimo.transaction.log.XidImpl2;
import org.apache.geronimo.transaction.manager.TransactionLog;
import org.apache.geronimo.transaction.manager.XidFactory;
import org.junit.Before;
import org.junit.Test;
import javax.transaction.xa.Xid;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Collections;
import java.util.List;
public class HowlLogTest {
private static final File basedir = new File(System.getProperty("basedir", System.getProperty("user.dir")));
private static final String LOG_FILE_NAME = "howl_test";
protected void closeTransactionLog(TransactionLog transactionLog) throws Exception {
((HowlLog) transactionLog).stop();
}
protected TransactionLog createTransactionLog() throws Exception {
XidFactory xidFactory = new XidFactoryImpl("hi".getBytes());
HowlLog howlLog = new HowlLog(
"org.objectweb.howl.log.BlockLogBuffer", // "bufferClassName",
4, // "bufferSizeKBytes",
true, // "checksumEnabled",
true,
20, // "flushSleepTime",
"txlog", // "logFileDir",
"log", // "logFileExt",
LOG_FILE_NAME, // "logFileName",
200, // "maxBlocksPerFile",
10, // "maxBuffers",
2, // "maxLogFiles",
2, // "minBuffers",
10,// "threadsWaitingForceThreshold"});
true,
xidFactory, new File(basedir, "target")
);
howlLog.start();
return howlLog;
}
@Before
public void setUp() throws Exception {
File logFile = new File(basedir, "target/" + LOG_FILE_NAME + "_1.log");
if (logFile.exists()) {
logFile.delete();
}
logFile = new File(basedir, "target/" + LOG_FILE_NAME + "_2.log");
if (logFile.exists()) {
logFile.delete();
}
}
private Object startBarrier = new Object();
private Object stopBarrier = new Object();
private int startedThreads = 0;
private int stoppedThreads = 0;
long totalDuration = 0;
private Xid xid;
private List names;
final Object mutex = new Object();
long totalXidCount = 0;
private Writer resultsXML;
private Writer resultsCSV;
@Test
public void testTransactionLog() throws Exception {
File resultFileXML = new File("target/howllog" + ".xml");
resultsXML = new FileWriter(resultFileXML);
resultsXML.write("<log-test>\n");
File resultFileCSV = new File("target/howllog" + ".csv");
resultsCSV = new FileWriter(resultFileCSV);
resultsCSV.write("workerCount,xidCount,TotalXids,missingXids,DurationMilliseconds,XidsPerSecond,AverageForceTime,AverageBytesPerForce,AverageLatency\n");
int xidCount = Integer.getInteger("xa.log.test.xid.count", 50).intValue();
int minWorkerCount = Integer.getInteger("xa.log.test.worker.count.min", 20).intValue();
int maxWorkerCount = Integer.getInteger("xa.log.test.worker.count.max", 40).intValue();
int workerCountStep = Integer.getInteger("xa.log.test.worker.count.step", 20).intValue();
int repCount = Integer.getInteger("xa.log.test.repetition.count", 1).intValue();
long maxTime = Long.getLong("xa.log.test.max.time.seconds", 30).longValue() * 1000;
int overtime = 0;
try {
for (int workers = minWorkerCount; workers <= maxWorkerCount; workers += workerCountStep) {
for (int reps = 0; reps < repCount; reps++) {
if (testTransactionLog(workers, xidCount) > maxTime) {
overtime++;
if (overtime > 1) {
return;
}
}
resultsCSV.flush();
resultsXML.flush();
}
}
} finally {
resultsXML.write("</log-test>\n");
resultsXML.flush();
resultsXML.close();
resultsCSV.flush();
resultsCSV.close();
}
}
public long testTransactionLog(int workers, int xidCount) throws Exception {
TransactionLog transactionLog = createTransactionLog();
xid = new XidImpl2(new byte[Xid.MAXGTRIDSIZE]);
names = Collections.EMPTY_LIST;
long startTime = journalTest(transactionLog, workers, xidCount);
long stopTime = System.currentTimeMillis();
printSpeedReport(transactionLog, startTime, stopTime, workers, xidCount);
closeTransactionLog(transactionLog);
return stopTime - startTime;
}
private long journalTest(final TransactionLog logger, final int workers, final int xidCount)
throws Exception {
totalXidCount = 0;
startedThreads = 0;
stoppedThreads = 0;
totalDuration = 0;
for (int i = 0; i < workers; i++) {
new Thread() {
public void run() {
long localXidCount = 0;
boolean exception = false;
long localDuration = 0;
try {
synchronized (startBarrier) {
++startedThreads;
startBarrier.notifyAll();
while (startedThreads < (workers + 1)) startBarrier.wait();
}
long localStartTime = System.currentTimeMillis();
for (int i = 0; i < xidCount; i++) {
// journalize COMMITTING record
Object logMark = logger.prepare(xid, names);
//localXidCount++;
// journalize FORGET record
logger.commit(xid, logMark);
localXidCount++;
}
localDuration = System.currentTimeMillis() - localStartTime;
} catch (Exception e) {
System.err.println(Thread.currentThread().getName());
e.printStackTrace(System.err);
exception = true;
} finally {
synchronized (mutex) {
totalXidCount += localXidCount;
totalDuration += localDuration;
}
synchronized (stopBarrier) {
++stoppedThreads;
stopBarrier.notifyAll();
}
}
}
}
.start();
}
// Wait for all the workers to be ready..
long startTime = 0;
synchronized (startBarrier) {
while (startedThreads < workers) startBarrier.wait();
++startedThreads;
startBarrier.notifyAll();
startTime = System.currentTimeMillis();
}
// Wait for all the workers to finish.
synchronized (stopBarrier) {
while (stoppedThreads < workers) stopBarrier.wait();
}
return startTime;
}
void printSpeedReport(TransactionLog logger, long startTime, long stopTime, int workers, int xidCount) throws IOException {
long mc = ((long) xidCount) * workers;
long duration = (stopTime - startTime);
long xidsPerSecond = (totalXidCount * 1000 / (duration));
int averageForceTime = logger.getAverageForceTime();
int averageBytesPerForce = logger.getAverageBytesPerForce();
long averageLatency = totalDuration / totalXidCount;
resultsXML.write("<run><workers>" + workers + "</workers><xids-per-thread>" + xidCount + "</xids-per-thread><expected-total-xids>" + mc + "</expected-total-xids><missing-xids>" + (mc - totalXidCount) + "</missing-xids><totalDuration-milliseconds>" + duration + "</totalDuration-milliseconds><xids-per-second>" + xidsPerSecond + "</xids-per-second></run>\n");
resultsXML.write(logger.getXMLStats() + "\n");
resultsCSV.write("" + workers + "," + xidCount + "," + mc + "," + (mc - totalXidCount) + "," + duration + "," + xidsPerSecond + "," + averageForceTime + "," + averageBytesPerForce + "," + averageLatency + "\n");
}
}