/* This file is part of VoltDB. * Copyright (C) 2008-2017 VoltDB Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ package org.voltdb; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import java.util.Map; import org.junit.BeforeClass; import org.junit.Test; import org.voltdb.VoltDB.Configuration; import org.voltdb.compiler.VoltProjectBuilder; import org.voltdb.regressionsuites.JUnit4LocalClusterTest; import org.voltdb.regressionsuites.LocalCluster; import org.voltdb.utils.MiscUtils; import com.google_voltpatches.common.collect.Maps; public class TestMixedSitesPerHostCluster extends JUnit4LocalClusterTest { static final int K = MiscUtils.isPro() ? 1 : 0; static final String JAR_NAME = "mixed.jar"; static final VoltProjectBuilder m_builder = new VoltProjectBuilder(); private class MixedSitesPerHostCluster { LocalCluster m_cluster = null; MixedSitesPerHostCluster(Map<Integer, Integer> sphMap) { assert(sphMap != null); assertFalse(sphMap.isEmpty()); m_cluster = new LocalCluster( JAR_NAME, 2, sphMap.size(), K, BackendTarget.NATIVE_EE_JNI); m_cluster.setOverridesForSitesperhost(sphMap); m_cluster.setHasLocalServer(false); m_cluster.setDeploymentAndVoltDBRoot( m_builder.getPathToDeployment(), m_builder.getPathToVoltRoot().getAbsolutePath()); } boolean start() { m_cluster.startUp(); return true; } boolean killAndRejoin(int hostId, Map<Integer, Integer> sphMap) { try { m_cluster.killSingleHost(hostId); // just set the override for the last host m_cluster.setOverridesForSitesperhost(sphMap); return m_cluster.recoverOne(hostId, 0, ""); } catch (Exception e) { e.printStackTrace(); return false; } } void shutdown() throws InterruptedException { if (m_cluster != null) { m_cluster.shutDown(); } } } @BeforeClass public static void compileCatalog() throws IOException { // just use it to fool VoltDB compiler, use overrides CLI option to provide actual sitesperhost final int fakeSph = 2; final int hostCount = 3; m_builder.addLiteralSchema("CREATE TABLE V0 (id BIGINT);"); m_builder.configureLogging(null, null, false, false, 200, Integer.MAX_VALUE, null); assertTrue(m_builder.compile(Configuration.getPathToCatalogForTest(JAR_NAME), fakeSph, hostCount, K)); } @Test public void testSameSitesPerHost() throws InterruptedException { MixedSitesPerHostCluster cluster = null; // Same sitesperhost across cluster, should work Map<Integer, Integer> sameSphMap = Maps.newHashMap(); sameSphMap.put(0, 2); sameSphMap.put(1, 2); sameSphMap.put(2, 2); cluster = new MixedSitesPerHostCluster(sameSphMap); assertTrue(cluster.start()); cluster.shutdown(); } @Test public void testMixedSitesPerHostOptimal() throws InterruptedException { MixedSitesPerHostCluster cluster = null; // Mixed sitesperhost, optimal, should work Map<Integer, Integer> mixedSphMap = Maps.newHashMap(); mixedSphMap.put(0, 2); mixedSphMap.put(1, 6); mixedSphMap.put(2, 4); cluster = new MixedSitesPerHostCluster(mixedSphMap); assertTrue(cluster.start()); cluster.shutdown(); } @Test public void testMixedSitesPerHostSubOptimal() throws InterruptedException { if (!MiscUtils.isPro()) { return; } // join tests are pro only MixedSitesPerHostCluster cluster = null; // Mixed sitesperhost, suboptimal, shouldn't allow to start Map<Integer, Integer> subOptimalSphMap = Maps.newHashMap(); subOptimalSphMap.put(0, 2); subOptimalSphMap.put(1, 6); subOptimalSphMap.put(2, 3); cluster = new MixedSitesPerHostCluster(subOptimalSphMap); try { cluster.start(); fail(); } catch (RuntimeException e) { assertTrue(e.getMessage().endsWith("external processes failed to start")); } finally { cluster.shutdown(); } } @Test public void testSameSitesPerHostJoins() throws InterruptedException { if (!MiscUtils.isPro()) { return; } // join tests are pro only MixedSitesPerHostCluster cluster = null; // test same sitesperhost rejoins Map<Integer, Integer> sameSphMap = Maps.newHashMap(); sameSphMap.put(0, 2); sameSphMap.put(1, 2); sameSphMap.put(2, 2); cluster = new MixedSitesPerHostCluster(sameSphMap); assertTrue(cluster.start()); assertTrue(cluster.killAndRejoin(0, sameSphMap)); assertTrue(cluster.killAndRejoin(1, sameSphMap)); assertTrue(cluster.killAndRejoin(2, sameSphMap)); cluster.shutdown(); } @Test public void testMixedSitesPerHostJoins() throws InterruptedException { if (!MiscUtils.isPro()) { return; } // join tests are pro only MixedSitesPerHostCluster cluster = null; // test mixed sitesperhost rejoins Map<Integer, Integer> mixedSphMap = Maps.newHashMap(); mixedSphMap.put(0, 6); mixedSphMap.put(1, 1); mixedSphMap.put(2, 5); cluster = new MixedSitesPerHostCluster(mixedSphMap); assertTrue(cluster.start()); assertTrue(cluster.killAndRejoin(0, mixedSphMap)); assertTrue(cluster.killAndRejoin(1, mixedSphMap)); assertTrue(cluster.killAndRejoin(2, mixedSphMap)); cluster.shutdown(); } }