public void testConditionUpdateConcurrency() throws Exception {
// This test uses MutationCondition's to let multiple threads concurrently increment a counter field
// in the same record.
// Create record with counter field initially set to 0
Record record = repository.newRecord();
record.setId(repository.getIdGenerator().newRecordId());
record.setRecordType(recordType2.getName());
record.setField(fieldType4.getName(), new Integer(0));
repository.createOrUpdate(record);
final RecordId recordId = record.getId();
// Run concurrent threads to increment the counter field
int threads = 5;
int count = 200;
ThreadPoolExecutor executor = new ThreadPoolExecutor(threads, threads, 10, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(count));
List<Future> futures = new ArrayList<Future>();
for (int i = 0; i < count; i++) {
futures.add(executor.submit(new Callable<Void>() {
@Override
public Void call() throws Exception {
int iteration = 0;
while (true) {
try {
iteration++;
Record record = repository.read(recordId);
int oldValue = (Integer) record.getField(fieldType4.getName());
record.setField(fieldType4.getName(), new Integer(oldValue + 1));
MutationCondition cond = new MutationCondition(fieldType4.getName(), oldValue, false);
record = repository.update(record, Lists.newArrayList(cond));
if (record.getResponseStatus() == ResponseStatus.CONFLICT) {
if (iteration > 20) {
System.out.println("cas failed, will retry, iteration " + iteration);
}
Thread.sleep((int) (Math.random() * 50));
} else if (record.getResponseStatus() == ResponseStatus.UPDATED) {
// success
return null;
} else {
fail("unexpected response status = " + record.getResponseStatus());
}
} catch (ConcurrentRecordUpdateException e) {
if (iteration > 20) {
System.out.println("concurrent update, will retry, iteration " + iteration);
}
Thread.sleep((int) (Math.random() * 50));
}
}
}
}));
}
for (Future future : futures) {
future.get();
}
executor.shutdown();
// verify the value of the counter field is as expected
record = repository.read(record.getId());
assertEquals(count, record.getField(fieldType4.getName()));
}