package org.corfudb.runtime.collections; import lombok.Getter; import org.corfudb.runtime.CorfuRuntime; import org.corfudb.runtime.object.transactions.AbstractTransactionsTest; import org.junit.Before; import org.junit.Test; import java.util.Map; import java.util.Set; import java.util.concurrent.CountDownLatch; import static org.assertj.core.api.Assertions.assertThat; /** * Created by dmalkhi on 3/20/17. */ public class SMRMapEntrySetTest extends AbstractTransactionsTest { @Override public void TXBegin() { OptimisticTXBegin(); } @Getter final String defaultConfigurationString = getDefaultEndpoint(); public CorfuRuntime r; @Before public void setRuntime() throws Exception { r = getDefaultRuntime().connect(); } @Test public void manipulateSets() throws Exception { Map<Long, Long> testMap = instantiateCorfuObject(SMRMap.class, "mapsettest"); // populate the map for (long i = 0; i < (long) PARAMETERS.NUM_ITERATIONS_LOW; i++) testMap.put(i, i); assertThat(testMap.get(0L)) .isEqualTo(0L); assertThat(testMap.size()) .isEqualTo(PARAMETERS.NUM_ITERATIONS_LOW); // get a snapshot of the keys Set<Long> keys = testMap.keySet(); assertThat(keys.size()) .isEqualTo(PARAMETERS.NUM_ITERATIONS_LOW); assertThat(keys.contains(0L)) .isTrue(); // manipulate the map, verify that keys set is unmodified, // the original map is modified testMap.remove(0L); assertThat(keys.size()) .isEqualTo(PARAMETERS.NUM_ITERATIONS_LOW); assertThat(keys.contains(0L)) .isTrue(); assertThat(testMap.containsKey(0L)) .isFalse(); assertThat(testMap.size()) .isEqualTo(PARAMETERS.NUM_ITERATIONS_LOW-1); } @Test public void manipulateSetsConcurrent() throws Exception { Map<Long, Long> testMap = instantiateCorfuObject(SMRMap.class, "mapsettest"); CountDownLatch l1 = new CountDownLatch(1); CountDownLatch l2 = new CountDownLatch(1); CountDownLatch l3 = new CountDownLatch(1); CountDownLatch l4 = new CountDownLatch(1); // first thread: create and manipulate map scheduleConcurrently(t -> { // signal start to second thread l1.countDown(); // populate the map for (long i = 0; i < (long) PARAMETERS.NUM_ITERATIONS_LOW; i++) testMap.put(i, i); assertThat(testMap.get(0L)) .isEqualTo(0L); assertThat(testMap.size()) .isEqualTo(PARAMETERS.NUM_ITERATIONS_LOW); // wait for second thread to advance l2.await(); // manipulate the map, verify that keys set is unmodified, // the original map is modified testMap.remove(0L); assertThat(testMap.containsKey(0L)) .isFalse(); assertThat(testMap.size()) .isEqualTo(PARAMETERS.NUM_ITERATIONS_LOW - 1); // allow third thread to proceed l3.countDown(); }); // 2nd thread: get an immutable copy of the keys in the // at an arbitrary snapshot scheduleConcurrently(t -> { l1.await(); // get a snapshot of the keys; // we don't know at which point the snapshot will be, // relative to the other thread Set<Long> keys = testMap.keySet(); int snapshotSize = keys.size(); if (snapshotSize > 0) assertThat(keys.contains(0L)) .isTrue(); // signal that one snapshot was taken already l2.countDown(); // verify that the immutable snapshot remains immutable while (l3.getCount() > 0) { assertThat(keys.size()) .isEqualTo(snapshotSize); if (snapshotSize > 0) assertThat(keys.contains(0L)) .isTrue(); } l3.await(); assertThat(keys.size()) .isEqualTo(snapshotSize); if (snapshotSize > 0) assertThat(keys.contains(0L)) .isTrue(); } ); scheduleConcurrently(t -> { l3.await(); // get a snapshot of the keys; Set<Long> keys = testMap.keySet(); assertThat(keys.size()) .isEqualTo(PARAMETERS.NUM_ITERATIONS_LOW-1); assertThat(keys.contains(0L)) .isFalse(); }); executeScheduled(PARAMETERS.CONCURRENCY_SOME, PARAMETERS.TIMEOUT_SHORT); } }