package com.splout.db.qnode;
/*
* #%L
* Splout SQL Server
* %%
* Copyright (C) 2012 Datasalt Systems S.L.
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Test;
import com.hazelcast.core.Hazelcast;
import com.splout.db.common.PartitionMap;
import com.splout.db.common.ReplicationEntry;
import com.splout.db.common.SploutConfiguration;
import com.splout.db.common.TestUtils;
import com.splout.db.dnode.DNode;
import com.splout.db.dnode.DNodeHandler;
import com.splout.db.qnode.beans.DeployRequest;
import com.splout.db.thrift.DNodeException;
import com.splout.db.thrift.DeployAction;
/**
* This test asserts that the deploy mechanism can be canceled (aborted) when one DNode fails. We will have 2 DNodes:
* one will fail and the other one will wait forever. In this way we will test that the other DNode is cancelled too.
*/
public class TestDeployAbort {
// This folder should never be created
// So that the DNode will fail when trying to deploy it
public final static String DEPLOY_FOLDER_THAT_DOESNT_EXIST = "deploy-folder-that-doesnt-exist";
@After
public void cleanUp() throws IOException {
TestUtils.cleanUpTmpFolders(this.getClass().getName(), 2);
}
/*
* This DNodeHandler is a normal DNodeHandler except that when it receives a deploy() order it will just stuck in a
* Thread.sleep(FOREVER). This way we can test deploy cancellation to DNodes: we set a flag if the Thread.sleep() has
* been interrupted.
*/
public static class StuckInDeployHandler extends DNodeHandler {
public static long FOREVER = Long.MAX_VALUE;
public boolean interrupted = false;
@Override
public String deploy(List<DeployAction> deployActions, long version) throws DNodeException {
synchronized(deployLock) {
deployInProgress.incrementAndGet();
deployThread.submit(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(FOREVER);
} catch(InterruptedException e) {
interrupted = true;
}
}
});
}
return "FOO";
}
}
@Test
public void testDeployFinalizing() throws Throwable {
QNodeHandler handler = new QNodeHandler();
SploutConfiguration config = SploutConfiguration.getTestConfig();
SploutConfiguration config1 = SploutConfiguration.getTestConfig();
SploutConfiguration config2 = SploutConfiguration.getTestConfig();
// since #12 and #7 we must disable replica balancing which is enabled for testing to fail the deploy
config.setProperty(QNodeProperties.REPLICA_BALANCE_ENABLE, false);
config.setProperty(QNodeProperties.DEPLOY_SECONDS_TO_CHECK_ERROR, 1); // this has to be quick for testing
DNodeHandler dHandler = new DNodeHandler();
DNode dnode1 = TestUtils
.getTestDNode(config1, dHandler, "dnode-" + this.getClass().getName() + "-1");
StuckInDeployHandler stuck = new StuckInDeployHandler();
DNode dnode2 = TestUtils.getTestDNode(config2, stuck, "dnode-" + this.getClass().getName() + "-2");
try {
handler.init(config);
ReplicationEntry repEntry1 = new ReplicationEntry(0, dnode1.getAddress(), dnode2.getAddress());
DeployRequest deployRequest1 = new DeployRequest();
deployRequest1.setTablespace("partition1");
deployRequest1.setPartitionMap(PartitionMap.oneShardOpenedMap().getPartitionEntries());
deployRequest1.setReplicationMap(Arrays.asList(repEntry1));
File fakeDeployFolder = new File(DEPLOY_FOLDER_THAT_DOESNT_EXIST);
// Remember we don't create the folder on purpose for making the DNode fail
deployRequest1.setData_uri(fakeDeployFolder.toURI().toString());
List<DeployRequest> l = new ArrayList<DeployRequest>();
l.add(deployRequest1);
handler.deploy(l);
Thread.sleep(3000);
assertEquals(0, handler.getContext().getTablespaceVersionsMap().size());
// the other DNode should have been interrupted
assertEquals(true, stuck.interrupted);
// everything OK
} finally {
handler.close();
dnode1.stop();
dnode2.stop();
Hazelcast.shutdownAll();
}
}
}