/* * Copyright 2013 LinkedIn, Inc * * 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 voldemort.coordinator; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.util.List; import java.util.Properties; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; import voldemort.ServerTestUtils; import voldemort.client.ClientConfig; import voldemort.client.SocketStoreClientFactory; import voldemort.cluster.Cluster; import voldemort.rest.coordinator.DynamicTimeoutStoreClient; import voldemort.server.VoldemortServer; import voldemort.store.CompositeGetVoldemortRequest; import voldemort.store.CompositePutVoldemortRequest; import voldemort.store.InsufficientOperationalNodesException; import voldemort.store.socket.SocketStoreFactory; import voldemort.store.socket.clientrequest.ClientRequestExecutorPool; import voldemort.utils.ByteArray; import voldemort.versioning.Versioned; import voldemort.xml.ClusterMapper; /** * Class to test the Fat Client wrapper */ public class DynamicTimeoutStoreClientTest { private VoldemortServer[] servers; private Cluster cluster; public static String socketUrl = ""; private static final String STORE_NAME = "slow-store-test"; private static final String STORES_XML = "test/common/voldemort/config/single-slow-store.xml"; private static final String SLOW_STORE_DELAY = "500"; private final SocketStoreFactory socketStoreFactory = new ClientRequestExecutorPool(2, 10000, 100000, 32 * 1024); private DynamicTimeoutStoreClient<ByteArray, byte[]> dynamicTimeoutClient = null; /** * Setup a one node Voldemort cluster with a 'slow' store * (SlowStorageEngine) with a delay of 500 ms for get and put. * * @throws java.lang.Exception */ @Before public void setUp() throws Exception { int numServers = 1; servers = new VoldemortServer[numServers]; int partitionMap[][] = { { 0, 2, 4, 6, 1, 3, 5, 7 } }; Properties props = new Properties(); props.setProperty("storage.configs", "voldemort.store.bdb.BdbStorageConfiguration,voldemort.store.slow.SlowStorageConfiguration"); props.setProperty("testing.slow.queueing.get.ms", SLOW_STORE_DELAY); props.setProperty("testing.slow.queueing.put.ms", SLOW_STORE_DELAY); cluster = ServerTestUtils.startVoldemortCluster(numServers, servers, partitionMap, socketStoreFactory, true, // useNio null, STORES_XML, props); socketUrl = servers[0].getIdentityNode().getSocketUrl().toString(); String bootstrapUrl = socketUrl; ClientConfig clientConfig = new ClientConfig().setBootstrapUrls(bootstrapUrl) .setEnableCompressionLayer(false) .setEnableSerializationLayer(false) .enableDefaultClient(true) .setEnableLazy(false); String storesXml = FileUtils.readFileToString(new File(STORES_XML), "UTF-8"); ClusterMapper mapper = new ClusterMapper(); this.dynamicTimeoutClient = new DynamicTimeoutStoreClient<ByteArray, byte[]>(STORE_NAME, new SocketStoreClientFactory(clientConfig), 1, storesXml, mapper.writeCluster(cluster)); } /** * @throws java.lang.Exception */ @After public void tearDown() throws Exception { if(this.socketStoreFactory != null) { this.socketStoreFactory.close(); } } /** * Test the dynamic per call timeout. We do a regular put with the default * configured timeout. We then do a put with a dynamic timeout of 200 ms * which is less than the delay at the server side. After this we do a get * with a dynamic timeout of 1500 ms which should succeed and return the * value from the first put. */ @Test public void test() { long incorrectTimeout = 200; long correctTimeout = 1500; String key = "a"; String value = "First"; String newValue = "Second"; try { this.dynamicTimeoutClient.put(new ByteArray(key.getBytes()), value.getBytes()); } catch(Exception e) { fail("Error in regular put."); } long startTime = System.currentTimeMillis(); try { this.dynamicTimeoutClient.putWithCustomTimeout(new CompositePutVoldemortRequest<ByteArray, byte[]>(new ByteArray(key.getBytes()), newValue.getBytes(), incorrectTimeout)); fail("Should not reach this point. The small (incorrect) timeout did not work."); } catch(InsufficientOperationalNodesException ion) { System.out.println("This failed as Expected."); } try { List<Versioned<byte[]>> versionedValues = this.dynamicTimeoutClient.getWithCustomTimeout(new CompositeGetVoldemortRequest<ByteArray, byte[]>(new ByteArray(key.getBytes()), correctTimeout, true)); // We only expect one value in the response since resolve conflicts // is set to true assertTrue(versionedValues.size() == 1); Versioned<byte[]> versionedValue = versionedValues.get(0); long endTime = System.currentTimeMillis(); System.out.println("Total time taken = " + (endTime - startTime)); String response = new String(versionedValue.getValue()); if(!response.equals(value)) { fail("The returned value does not match. Expected: " + value + " but Received: " + response); } } catch(Exception e) { e.printStackTrace(); fail("The dynamic per call timeout did not work !"); } } }