Tweak Map-based repository for performance (serialization of a StepExecution is expensive and unnecessary)
This commit is contained in:
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user