package org.corfudb.runtime.object.transactions;
import com.google.common.reflect.TypeToken;
import org.corfudb.runtime.collections.SMRMap;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Created by dalia on 12/8/16.
*/
public class OptimisticTXConcurrencyTest extends TXConflictScenariosTest {
@Override
public void TXBegin() { OptimisticTXBegin(); }
public void testOpacityOptimistic(boolean isInterleaved) throws Exception {
testOpacity(isInterleaved);
// verfiy that all aborts are justified
for (int task_num = 0; task_num < numTasks; task_num++) {
if (commitStatus.get(task_num) != COMMITVALUE) {
assertThat(sharedCounters.get((task_num + 1) % numTasks).getValue())
.isNotEqualTo(snapStatus.get(task_num));
assertThat(commitStatus.get((task_num + 1) % numTasks))
.isEqualTo(COMMITVALUE);
}
}
}
@Test
public void testOpacityInterleaved() throws Exception {
// invoke the interleaving engine
testOpacityOptimistic(true);
}
@Test
public void testOpacityThreaded() throws Exception {
// invoke the threaded engine
testOpacityOptimistic(false);
}
/**
* If task k aborts, then either task (k-1), or (k+1), or both, must have committed
* (wrapping around for tasks n-1 and 0, respectively).
*/
public void testOptimism(boolean testInterleaved) throws Exception {
testRWConflicts(testInterleaved);
// verfiy that all aborts are justified
for (int task_num = 0; task_num < numTasks; task_num++) {
if (commitStatus.get(task_num) != COMMITVALUE)
assertThat(commitStatus.get((task_num + 1) % numTasks) == COMMITVALUE ||
commitStatus.get((task_num - 1) % numTasks) == COMMITVALUE)
.isTrue();
}
}
@Test
public void testOptimismInterleaved() throws Exception {
testOptimism(true);
}
@Test
public void testOptimismThreaded() throws Exception {
testOptimism(false);
}
@Test
public void testNoWriteConflictSimpleOptimistic() throws Exception {
testNoWriteConflictSimple();
assertThat(commitStatus.get(0) == COMMITVALUE || commitStatus.get(1) == COMMITVALUE)
.isTrue();
}
@Test
public void testAbortWWInterleaved()
throws Exception
{
concurrentAbortTest(true);
// no assertion, just print abort rate
}
@Test
public void testAbortWWThreaded()
throws Exception
{
concurrentAbortTest(false);
// no assertion, just print abort rate
}
@Test
public void checkRollbackNested() throws Exception {
ArrayList<Map> maps = new ArrayList<>();
final int nmaps = 2;
for (int i = 0; i < nmaps; i++)
maps.add( (SMRMap<Integer, String>) instantiateCorfuObject(
new TypeToken<SMRMap<Integer, String>>() {}, "test stream" + i)
);
final int key1 = 1, key2 = 2, key3 = 3;
final String tst1 = "foo", tst2 = "bar";
final int nNests = PARAMETERS.NUM_ITERATIONS_LOW;
// start tx in one thread, establish snapshot time
t(1, () -> {
TXBegin();
maps.get(0).get(key1);
maps.get(1).get(key1);
});
// in another thread, nest nNests transactions writing to different streams
t(2, () -> {
for (int i = 0; i < nNests; i++) {
TXBegin();
maps.get((i%nmaps)).put(key1, (i % nmaps) == 0 ? tst1 : tst2);
maps.get((i%nmaps)).put(key2, (i % nmaps) == 0 ? tst1 : tst2);
maps.get((i%nmaps)).put(key3, (i % nmaps) == 0 ? tst1 : tst2);
}
});
t(1, () -> {
assertThat(maps.get(0).get(key1))
.isEqualTo(null);
assertThat(maps.get(1).get(key1))
.isEqualTo(null);
});
}
}