package voldemort.store.routed; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import voldemort.ClusterTestUtils; import voldemort.ServerTestUtils; import voldemort.TestUtils; import voldemort.client.ClientConfig; import voldemort.client.SocketStoreClientFactory; import voldemort.cluster.Cluster; import voldemort.server.VoldemortConfig; import voldemort.server.VoldemortServer; import voldemort.store.InsufficientOperationalNodesException; import voldemort.store.InsufficientZoneResponsesException; import voldemort.store.Store; import voldemort.store.StoreDefinition; import voldemort.store.socket.SocketStoreFactory; import voldemort.store.socket.clientrequest.ClientRequestExecutorPool; import voldemort.utils.ByteArray; import voldemort.versioning.Versioned; /** * This test verifies the zone count write policy in PipelineRoutedStore * */ @RunWith(Parameterized.class) public class ZoneCountWriteTest { private Store<String, String, byte[]> client; private Map<Integer, VoldemortServer> vservers = new HashMap<Integer, VoldemortServer>(); private Cluster cluster; private StoreDefinition storeDef = null; private List<StoreDefinition> storeDefs; private ClientConfig clientConfig; Set<Integer> stoppedServersForRemoteZoneNodeFail; Set<Integer> stoppedServersForInsufficientZone; public ZoneCountWriteTest(Cluster cluster, List<StoreDefinition> storeDefs, ClientConfig clientConfig, Set<Integer> stoppedServersForRemoteZoneNodeFail, Set<Integer> stoppedServersForInsufficientZone) { this.cluster = cluster; this.storeDefs = storeDefs; this.clientConfig = clientConfig; this.stoppedServersForRemoteZoneNodeFail = stoppedServersForRemoteZoneNodeFail; this.stoppedServersForInsufficientZone = stoppedServersForInsufficientZone; } @Parameterized.Parameters public static Collection<Object[]> configs() { Cluster z1z3z5cluster = ClusterTestUtils.getZ1Z3Z5ClusterWithNonContiguousNodeIds(); List<StoreDefinition> z1z3z5StoreDefs = ClusterTestUtils.getZ1Z3Z5322StoreDefs("memory"); ClientConfig clientConfig = new ClientConfig(); clientConfig.setClientZoneId(3); clientConfig.setBootstrapUrls(z1z3z5cluster.getNodeById(3).getSocketUrl().toString()); clientConfig.getZoneAffinity().setEnableGetOpZoneAffinity(true); Set<Integer> stoppedServersForRemoteZoneNodeFail = new HashSet<Integer>(Arrays.asList(4, 5, 9, 10, 11, 15, 16)); Set<Integer> stoppedServersForInsufficientZone = new HashSet<Integer>(Arrays.asList(5, 9, 10, 11, 15, 16, 17)); Cluster zzzCluster = ClusterTestUtils.getZZZCluster(); List<StoreDefinition> zzzStoreDefs = ClusterTestUtils.getZZZ322StoreDefs("memory"); ClientConfig zzzClientConfig = new ClientConfig(); zzzClientConfig.setClientZoneId(0); zzzClientConfig.setBootstrapUrls(zzzCluster.getNodeById(0).getSocketUrl().toString()); zzzClientConfig.getZoneAffinity().setEnableGetOpZoneAffinity(true); Set<Integer> zzzstoppedServersForRemoteZoneNodeFail = new HashSet<Integer>(Arrays.asList(1, 2, 3, 4, 5, 6, 7)); Set<Integer> zzzstoppedServersForInsufficientZone = new HashSet<Integer>(Arrays.asList(2, 3, 4, 5, 6, 7, 8)); return Arrays.asList(new Object[][] { { z1z3z5cluster, z1z3z5StoreDefs, clientConfig, stoppedServersForRemoteZoneNodeFail, stoppedServersForInsufficientZone }, { zzzCluster, zzzStoreDefs, zzzClientConfig, zzzstoppedServersForRemoteZoneNodeFail, zzzstoppedServersForInsufficientZone } }); } @Before public void setup() throws IOException { storeDef = storeDefs.get(0); Integer zoneCountWrite = 1; // override storeDef = new StoreDefinition(storeDef.getName(), storeDef.getType(), storeDef.getDescription(), storeDef.getKeySerializer(), storeDef.getValueSerializer(), storeDef.getTransformsSerializer(), storeDef.getRoutingPolicy(), storeDef.getRoutingStrategyType(), storeDef.getReplicationFactor(), storeDef.getPreferredReads(), storeDef.getRequiredReads(), storeDef.getPreferredWrites(), storeDef.getRequiredWrites(), storeDef.getViewTargetStoreName(), storeDef.getValueTransformation(), storeDef.getZoneReplicationFactor(), storeDef.getZoneCountReads(), zoneCountWrite, storeDef.getRetentionDays(), storeDef.getRetentionScanThrottleRate(), storeDef.getRetentionFrequencyDays(), storeDef.getSerializerFactory(), storeDef.getHintedHandoffStrategyType(), storeDef.getHintPrefListSize(), storeDef.getOwners(), storeDef.getMemoryFootprintMB()); storeDefs.set(0, storeDef); SocketStoreClientFactory socketStoreClientFactory = new SocketStoreClientFactory(clientConfig); for(Integer nodeId: cluster.getNodeIds()) { SocketStoreFactory socketStoreFactory = new ClientRequestExecutorPool(2, 10000, 100000, 1024); VoldemortConfig config = ServerTestUtils.createServerConfigWithDefs(true, nodeId, TestUtils.createTempDir() .getAbsolutePath(), cluster, storeDefs, new Properties()); VoldemortServer vs = ServerTestUtils.startVoldemortServer(socketStoreFactory, config, cluster); vservers.put(nodeId, vs); } client = socketStoreClientFactory.getRawStore(storeDef.getName(), null); } @After public void tearDown() throws IOException { for(VoldemortServer vs: this.vservers.values()) { ServerTestUtils.stopVoldemortServer(vs); } } @Test public void testFastPath() { try { client.put("AB", new Versioned<String>("CD"), null); try { Thread.sleep(100); } catch(InterruptedException e) { e.printStackTrace(); } for(Integer nodeId: vservers.keySet()) { VoldemortServer vs = vservers.get(nodeId); Store<ByteArray, byte[], byte[]> store = vs.getStoreRepository() .getLocalStore(storeDef.getName()); byte[] real = store.get(new ByteArray("AB".getBytes()), null).get(0).getValue(); assertTrue(Arrays.equals(real, "CD".getBytes())); } } catch(InsufficientOperationalNodesException e) { fail("Failed with exception: " + e); } } @Test public void testRemoteZoneNodeFail() { try { for(Integer nodeId: stoppedServersForRemoteZoneNodeFail) { vservers.get(nodeId).stop(); } client.put("AB", new Versioned<String>("CD"), null); try { Thread.sleep(100); } catch(InterruptedException e) {} for(Integer nodeId: vservers.keySet()) { // skip stopped ones if(stoppedServersForRemoteZoneNodeFail.contains(nodeId)) { continue; } VoldemortServer vs = vservers.get(nodeId); Store<ByteArray, byte[], byte[]> store = vs.getStoreRepository() .getLocalStore(storeDef.getName()); byte[] real = store.get(new ByteArray("AB".getBytes()), null).get(0).getValue(); assertTrue(Arrays.equals(real, "CD".getBytes())); } } catch(InsufficientOperationalNodesException e) { fail("Failed with exception: " + e); e.printStackTrace(); } } @Test public void testRemoteZoneNodeFailInsufficientZone() { for(Integer nodeId: stoppedServersForInsufficientZone) { vservers.get(nodeId).stop(); } try { client.put("AB", new Versioned<String>("CD"), null); fail("Didn't throw exception"); } catch(InsufficientZoneResponsesException e) {} } }