/*
* Copyright 2008-2009 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.store.invalidmetadata;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.Map.Entry;
import junit.framework.TestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import voldemort.ServerTestUtils;
import voldemort.TestUtils;
import voldemort.VoldemortException;
import voldemort.cluster.Cluster;
import voldemort.cluster.Node;
import voldemort.routing.RoutingStrategy;
import voldemort.server.VoldemortConfig;
import voldemort.server.VoldemortServer;
import voldemort.store.Store;
import voldemort.utils.ByteArray;
import voldemort.utils.ByteUtils;
import voldemort.versioning.VectorClock;
import voldemort.versioning.Versioned;
/**
* InvalidMetadata can cause trouble for server side routing by not allowing
* requests from random partitions on a server.
*
*/
@RunWith(Parameterized.class)
public class ServerSideRoutingTest extends TestCase {
private static int TEST_VALUES_SIZE = 1000;
private static String testStoreName = "test-replication-memory";
private static String storesXmlfile = "test/common/voldemort/config/stores.xml";
private final boolean useNio;
private final boolean enableMetadataChecking;
private VoldemortServer servers[];
public ServerSideRoutingTest(boolean useNio, boolean enableMetadataChecking) {
this.useNio = useNio;
this.enableMetadataChecking = enableMetadataChecking;
}
@Parameters
public static Collection<Object[]> configs() {
return Arrays.asList(new Object[][] { { false, false }, { false, true }, { true, false },
{ true, true } });
}
@Override
@Before
public void setUp() throws IOException {
Cluster cluster = ServerTestUtils.getLocalCluster(2, new int[][] { { 0, 1 }, { 2, 3 } });
servers = new VoldemortServer[2];
servers[0] = startServer(useNio, 0, storesXmlfile, cluster, enableMetadataChecking);
servers[1] = startServer(useNio, 1, storesXmlfile, cluster, enableMetadataChecking);
}
@Override
@After
public void tearDown() {
for(int i = 0; i < servers.length; i++) {
try {
ServerTestUtils.stopVoldemortServer(servers[i]);
} catch(VoldemortException e) {
// ignore these at stop time
} catch(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Test
public void testServerSideRouting() {
checkServerSideRouting(servers[0], servers[1]);
}
private void checkServerSideRouting(VoldemortServer server0, VoldemortServer server1) {
// create bunch of key-value pairs
HashMap<ByteArray, byte[]> entryMap = ServerTestUtils.createRandomKeyValuePairs(TEST_VALUES_SIZE);
// populate all entries in server1
Store<ByteArray, byte[], byte[]> store = server1.getStoreRepository()
.getRoutedStore(testStoreName);
for(Entry<ByteArray, byte[]> entry: entryMap.entrySet()) {
store.put(entry.getKey(),
Versioned.value(entry.getValue(),
new VectorClock().incremented(0, System.currentTimeMillis())),
null);
}
// try fetching them from server0
store = server0.getStoreRepository().getLocalStore(testStoreName);
RoutingStrategy routing = server0.getMetadataStore().getRoutingStrategy(testStoreName);
for(Entry<ByteArray, byte[]> entry: entryMap.entrySet()) {
List<Node> nodes = routing.routeRequest(entry.getKey().get());
if(hasNode(nodes, 0)) {
assertTrue("ServerSideRouting should return keys from other nodes.",
ByteUtils.compare(entry.getValue(), store.get(entry.getKey(), null)
.get(0)
.getValue()) == 0);
}
}
}
/**
* Checks if a list of nodes contains a node with the passed node id
*
*/
private boolean hasNode(List<Node> nodes, int nodeId) {
for(Node node: nodes) {
if(node.getId() == nodeId) {
return true;
}
}
return false;
}
private VoldemortServer startServer(boolean useNio,
int node,
String storesXmlfile,
Cluster cluster,
boolean metadataChecking) throws IOException {
VoldemortConfig config = ServerTestUtils.createServerConfig(useNio,
node,
TestUtils.createTempDir()
.getAbsolutePath(),
null,
storesXmlfile,
new Properties());
if(metadataChecking)
config.setEnableMetadataChecking(true);
else
config.setEnableMetadataChecking(false);
// set server side routing true.
config.setEnableServerRouting(true);
VoldemortServer server = new VoldemortServer(config, cluster);
server.start();
return server;
}
}