/* * Copyright 2016 higherfrequencytrading.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package net.openhft.chronicle.engine; import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.core.OS; import net.openhft.chronicle.core.io.Closeable; import net.openhft.chronicle.core.onoes.ExceptionKey; import net.openhft.chronicle.core.pool.ClassAliasPool; import net.openhft.chronicle.engine.api.EngineReplication; import net.openhft.chronicle.engine.api.map.KeyValueStore; import net.openhft.chronicle.engine.api.map.MapView; import net.openhft.chronicle.engine.api.tree.AssetTree; import net.openhft.chronicle.engine.fs.ChronicleMapGroupFS; import net.openhft.chronicle.engine.fs.FilePerKeyGroupFS; import net.openhft.chronicle.engine.map.CMap2EngineReplicator; import net.openhft.chronicle.engine.map.ChronicleMapKeyValueStore; import net.openhft.chronicle.engine.map.VanillaMapView; import net.openhft.chronicle.engine.server.ServerEndpoint; import net.openhft.chronicle.engine.tree.VanillaAssetTree; import net.openhft.chronicle.network.TCPRegistry; import net.openhft.chronicle.wire.WireType; import net.openhft.chronicle.wire.YamlLogging; import org.jetbrains.annotations.NotNull; import org.junit.*; import org.junit.rules.TestName; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; import java.util.Collection; import java.util.Map; import java.util.concurrent.ConcurrentMap; import static org.junit.Assert.assertNotNull; /** * Created by Rob Austin */ @Ignore("fails in teamcity") @RunWith(value = Parameterized.class) public class Replication3WayIntIntTest extends ThreadMonitoringTest { public static final WireType WIRE_TYPE = WireType.TEXT; public static final int NUMBER_OF_TIMES = 10; static { //System.setProperty("ReplicationHandler3", "true"); } public ServerEndpoint serverEndpoint1; public ServerEndpoint serverEndpoint2; @NotNull @Rule public TestName testName = new TestName(); public String name; private ServerEndpoint serverEndpoint3; private AssetTree tree1; private AssetTree tree2; private AssetTree tree3; private Map<ExceptionKey, Integer> exceptions; public Replication3WayIntIntTest() { } @Parameterized.Parameters public static Collection<Object[]> data() { @NotNull Object[][] objects = new Object[NUMBER_OF_TIMES][]; Arrays.fill(objects, new Object[]{}); return Arrays.asList(objects); } @NotNull public static String resourcesDir() { String path = ChronicleMapKeyValueStoreTest.class.getProtectionDomain().getCodeSource().getLocation().getPath(); if (path == null) return "."; return new File(path).getParentFile().getParentFile() + "/src/test/resources"; } @Before public void before() throws IOException { exceptions = Jvm.recordExceptions(); YamlLogging.setAll(false); ClassAliasPool.CLASS_ALIASES.addAlias(ChronicleMapGroupFS.class); ClassAliasPool.CLASS_ALIASES.addAlias(FilePerKeyGroupFS.class); //Delete any files from the last run TCPRegistry.createServerSocketChannelFor( "host.port1", "host.port2", "host.port3"); @NotNull WireType writeType = WireType.TEXT; tree1 = create(1, writeType, "clusterThree"); tree2 = create(2, writeType, "clusterThree"); tree3 = create(3, writeType, "clusterThree"); serverEndpoint1 = new ServerEndpoint("host.port1", tree1); serverEndpoint2 = new ServerEndpoint("host.port2", tree2); serverEndpoint3 = new ServerEndpoint("host.port3", tree3); name = testName.getMethodName(); Files.deleteIfExists(Paths.get(OS.TARGET, name)); } public void preAfter() { Closeable.closeQuietly(serverEndpoint1); Closeable.closeQuietly(serverEndpoint2); Closeable.closeQuietly(serverEndpoint3); Closeable.closeQuietly(tree1); Closeable.closeQuietly(tree2); Closeable.closeQuietly(tree3); if (!exceptions.isEmpty()) { Jvm.dumpException(exceptions); // TODO FIX Assert.fail(); } } @NotNull private AssetTree create(final int hostId, WireType writeType, final String clusterTwo) { @NotNull AssetTree tree = new VanillaAssetTree((byte) hostId) .forTesting() .withConfig(resourcesDir() + "/3way", OS.TARGET + "/" + hostId); tree.root().addWrappingRule(MapView.class, "map directly to KeyValueStore", VanillaMapView::new, KeyValueStore.class); tree.root().addLeafRule(EngineReplication.class, "Engine replication holder", CMap2EngineReplicator::new); tree.root().addLeafRule(KeyValueStore.class, "KVS is Chronicle Map", (context, asset) -> new ChronicleMapKeyValueStore(context.wireType(writeType).cluster(clusterTwo), asset)); return tree; } @Test public void testAllDataGetsReplicated() { name = "testAllDataGetsReplicated"; @NotNull final ConcurrentMap<Integer, Integer> map1 = tree1.acquireMap(name, Integer.class, Integer .class); assertNotNull(map1); @NotNull final ConcurrentMap<Integer, Integer> map2 = tree2.acquireMap(name, Integer.class, Integer .class); assertNotNull(map2); @NotNull final ConcurrentMap<Integer, Integer> map3 = tree3.acquireMap(name, Integer.class, Integer .class); assertNotNull(map3); for (int i = 0; i < 70; i++) { map1.put(i, i); } assertFullRange(70, map1); Jvm.pause(1); assertFullRange(70, map2); put(map2, 70); assertFullRange(71, map1, map2); assertFullRange(71, map3); assertAllContain(70, map1, map2, map3); put(map1, 71); assertAllContain(71, map1, map2, map3); put(map2, 72); assertAllContain(72, map1, map2, map3); put(map3, 73); assertAllContain(73, map1, map2, map3); // you have to wait for it to become fully replicated int epectedSize = 74; for (int i = 0; i < 100; i++) { if (map1.size() == epectedSize && map2.size() == epectedSize && map3.size() == epectedSize) { break; } Jvm.pause(100); } if (map1.size() != map2.size()) System.out.println("map1=" + map1 + "\nmap2=" + map2); Assert.assertEquals(map1.size(), map2.size()); Assert.assertEquals(map2.size(), map3.size()); } private void put(@NotNull Map<Integer, Integer> map, int toPut) { map.put(toPut, toPut); } @SafeVarargs private final void assertAllContain(int key, @NotNull Map<Integer, Integer>... maps) { Outer: for (int x = 0; x < 100; x++) { for (@NotNull Map<Integer, Integer> map : maps) { if (!map.containsKey(key)) { Jvm.pause(100); continue Outer; } assert true; return; } } System.out.println("key=" + key + ",maps=" + Arrays.toString(maps)); assert false; } @SafeVarargs private final void assertFullRange(int upperBoundExclusive, @NotNull Map<Integer, Integer>... maps) { Outer: for (int x = 0; x < 100; x++) { for (@NotNull Map<Integer, Integer> map : maps) { for (int i = 0; i < upperBoundExclusive; i++) { if (!map.containsKey(i)) { Jvm.pause(100); continue Outer; } assert true; return; } } } assert false; } }