/*
* Copyright 2012 C24 Technologies
*
* 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 biz.c24.io.spring.batch.reader.performance.util;
import org.springframework.batch.item.ItemReader;
import biz.c24.io.api.data.ComplexDataObject;
import biz.c24.io.spring.batch.reader.C24ItemReader;
/**
* Abstract test harness to call read on a C24ItemReader until the underlying Reader is exhausted.
*
* @author Andrew Elmore
*
*/
public abstract class ItemReaderJobRunner {
private long runTime;
private long recordsProcessed;
private int numThreads;
public ItemReaderJobRunner(int numThreads) {
this.numThreads = numThreads;
}
/**
* Override this to create the C24ItemReader to be exercised during the test
* @return The C24ItemReader to be exercised during the test.
*/
protected abstract C24ItemReader<ComplexDataObject> createReader();
/**
* Executes the test.
* Fires up the specified number of threads to invoke read on the C24ItemReader until there
* is no more data to read.
* Tracks the number of items read and the cumulative processing time.
*/
public void runJob() {
ItemReaderJobRunner.Worker<ComplexDataObject>[] workers = new ItemReaderJobRunner.Worker[numThreads];
C24ItemReader<ComplexDataObject> reader = createReader();
for(int i=0; i < workers.length; i++) {
workers[i] = new ItemReaderJobRunner.Worker<ComplexDataObject>();
workers[i].setReader(reader);
workers[i].start();
}
recordsProcessed = 0;
long startTime = System.nanoTime();
for(int i=0; i < workers.length; i++) {
try {
workers[i].join(200000);
recordsProcessed += workers[i].getCount();
if(workers[i].getException() != null) {
throw new RuntimeException(workers[i].getException());
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted waiting on thread");
}
if(workers[i].isAlive()) {
throw new RuntimeException("Timed out waiting for thread to complete its work");
}
}
runTime = System.nanoTime() - startTime;
reader.cleanup();
}
public long getRecordsProcessed() {
return this.recordsProcessed;
}
public long getRunTime() {
return this.runTime;
}
private static class Worker<T extends ComplexDataObject> implements Runnable {
private ItemReader<T> reader;
private Exception ex = null;
private long count = 0;
private Thread thread = new Thread(this);
public Worker() {}
public void setReader(ItemReader<T> itemReader) {
this.reader = itemReader;
}
public void start() {
thread.start();
}
public void join(long timeoutMs) throws InterruptedException {
thread.join(timeoutMs);
}
public boolean isAlive() {
return thread.isAlive();
}
public long getCount() {
return count;
}
public void run() {
count = 0;
ex = null;
try {
while(reader.read() != null) {
count++;
}
} catch (Exception e) {
ex = e;
throw new RuntimeException(e);
}
}
public Exception getException() {
return ex;
}
}
}