Tweak Map-based repository for performance (serialization of a StepExecution is expensive and unnecessary)

This commit is contained in:
dsyer
2010-04-07 11:05:46 +00:00
parent d04a904eaf
commit 8782405974
5 changed files with 29 additions and 31 deletions

View File

@@ -15,7 +15,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
@@ -29,18 +28,14 @@ import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.Assert;
/**
* Tests for {@link FaultTolerantStepFactoryBean}.
*/
@ContextConfiguration(locations = "/simple-job-launcher-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class MapRepositoryFaultTolerantStepFactoryBeanRollbackTests {
private static final int MAX_COUNT = 1000;
@@ -61,24 +56,20 @@ public class MapRepositoryFaultTolerantStepFactoryBeanRollbackTests {
private JobRepository repository;
@Autowired
private PlatformTransactionManager transactionManager;
private PlatformTransactionManager transactionManager = new ResourcelessTransactionManager();
@SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
repository = new MapJobRepositoryFactoryBean().getJobRepository();
reader = new SkipReaderStub();
writer = new SkipWriterStub();
processor = new SkipProcessorStub();
factory = new FaultTolerantStepFactoryBean<String, String>();
factory.setBeanName("stepName");
factory.setTransactionManager(transactionManager);
factory.setJobRepository(repository);
factory.setBeanName("stepName");
factory.setCommitInterval(3);
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(3);
@@ -113,7 +104,7 @@ public class MapRepositoryFaultTolerantStepFactoryBeanRollbackTests {
if (i%100==0) {
logger.info("Starting step: "+i);
repository = new MapJobRepositoryFactoryBean().getJobRepository();
repository = new MapJobRepositoryFactoryBean(transactionManager).getJobRepository();
factory.setJobRepository(repository);
jobExecution = repository.createJobExecution("vanillaJob", new JobParameters());
}

View File

@@ -13,7 +13,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
@@ -27,18 +26,14 @@ import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.Assert;
/**
* Tests for {@link FaultTolerantStepFactoryBean}.
*/
@ContextConfiguration(locations = "/simple-job-launcher-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class MapRepositoryFaultTolerantStepFactoryBeanTests {
private static final int MAX_COUNT = 1000;
@@ -59,14 +54,11 @@ public class MapRepositoryFaultTolerantStepFactoryBeanTests {
private JobRepository repository;
@Autowired
private PlatformTransactionManager transactionManager;
private PlatformTransactionManager transactionManager = new ResourcelessTransactionManager();
@Before
public void setUp() throws Exception {
repository = new MapJobRepositoryFactoryBean().getJobRepository();
reader = new SkipReaderStub();
writer = new SkipWriterStub();
processor = new SkipProcessorStub();
@@ -75,7 +67,6 @@ public class MapRepositoryFaultTolerantStepFactoryBeanTests {
factory.setBeanName("stepName");
factory.setTransactionManager(transactionManager);
factory.setJobRepository(repository);
factory.setCommitInterval(3);
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setCorePoolSize(3);
@@ -107,7 +98,7 @@ public class MapRepositoryFaultTolerantStepFactoryBeanTests {
if (i%100==0) {
logger.info("Starting step: "+i);
repository = new MapJobRepositoryFactoryBean().getJobRepository();
repository = new MapJobRepositoryFactoryBean(transactionManager).getJobRepository();
factory.setJobRepository(repository);
jobExecution = repository.createJobExecution("vanillaJob", new JobParameters());
}

View File

@@ -51,11 +51,16 @@ public class SplitJobMapRepositoryIntegrationTests {
JobLauncher jobLauncher = null;
Job job = null;
ClassPathXmlApplicationContext context = null;
for (int i = 0; i < MAX_COUNT; i++) {
if (i % 100 == 0) {
if (context!=null) {
context.close();
}
logger.info("Starting job: " + i);
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(getClass().getSimpleName()
context = new ClassPathXmlApplicationContext(getClass().getSimpleName()
+ "-context.xml", getClass());
jobLauncher = (JobLauncher) context.getBean("jobLauncher", JobLauncher.class);
job = (Job) context.getBean("job", Job.class);

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.batch.core.repository.dao;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -29,6 +30,7 @@ import org.springframework.batch.core.StepExecution;
import org.springframework.batch.support.SerializationUtils;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
/**
* In-memory implementation of {@link StepExecutionDao}.
@@ -49,6 +51,16 @@ public class MapStepExecutionDao implements StepExecutionDao {
private static StepExecution copy(StepExecution original) {
return (StepExecution) SerializationUtils.deserialize(SerializationUtils.serialize(original));
}
private static void copy(final StepExecution sourceExecution, final StepExecution targetExecution) {
// Cheaper than full serialization is a reflective field copy, which is fine for volatile storage
ReflectionUtils.doWithFields(StepExecution.class, new ReflectionUtils.FieldCallback() {
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
field.setAccessible(true);
field.set(targetExecution, field.get(sourceExecution));
}
});
}
public void saveStepExecution(StepExecution stepExecution) {
@@ -77,7 +89,7 @@ public class MapStepExecutionDao implements StepExecutionDao {
Map<Long, StepExecution> executions = executionsByJobExecutionId.get(stepExecution.getJobExecutionId());
Assert.notNull(executions, "step executions for given job execution are expected to be already saved");
StepExecution persistedExecution = executionsByStepExecutionId.get(stepExecution.getId());
final StepExecution persistedExecution = executionsByStepExecutionId.get(stepExecution.getId());
Assert.notNull(persistedExecution, "step execution is expected to be already saved");
synchronized (stepExecution) {
@@ -88,9 +100,8 @@ public class MapStepExecutionDao implements StepExecutionDao {
}
stepExecution.incrementVersion();
StepExecution copy = copy(stepExecution);
executions.put(stepExecution.getId(), copy);
executionsByStepExecutionId.put(stepExecution.getId(), copy);
copy(stepExecution, persistedExecution);
executions.put(stepExecution.getId(), persistedExecution);
}
}

View File

@@ -74,7 +74,7 @@ public class TransactionAwareProxyFactory<T> {
private TransactionAwareProxyFactory(T target, boolean appendOnly) {
super();
this.target = begin(target);
this.target = target;
this.appendOnly = appendOnly;
}