/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/
package alluxio.underfs;
import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import javax.annotation.concurrent.NotThreadSafe;
/**
* Base class for a UFS cluster.
*/
@NotThreadSafe
public abstract class UnderFileSystemCluster {
private static final Logger LOG = LoggerFactory.getLogger(UnderFileSystemCluster.class);
class ShutdownHook extends Thread {
UnderFileSystemCluster mUFSCluster = null;
public ShutdownHook(UnderFileSystemCluster ufsCluster) {
mUFSCluster = ufsCluster;
}
@Override
public void run() {
if (mUFSCluster != null) {
try {
mUFSCluster.shutdown();
} catch (IOException e) {
LOG.warn("Failed to shutdown underfs cluster: {}" + e.getMessage());
}
}
}
}
private static final String INTEGRATION_UFS_PROFILE_KEY = "ufs";
private static String sUnderFSClass;
private static UnderFileSystemCluster sUnderFSCluster = null;
/**
* @return the existing underfs, throwing IllegalStateException if it hasn't been initialized yet
*/
public static synchronized UnderFileSystemCluster get() {
Preconditions.checkNotNull(sUnderFSCluster, "sUnderFSCluster has not been initialized yet");
return sUnderFSCluster;
}
/**
* Creates an underfs test bed and register the shutdown hook.
*
* @param baseDir base directory
* @return an instance of the UnderFileSystemCluster class
*/
public static synchronized UnderFileSystemCluster get(String baseDir)
throws IOException {
if (sUnderFSCluster == null) {
sUnderFSCluster = getUnderFilesystemCluster(baseDir);
}
if (!sUnderFSCluster.isStarted()) {
sUnderFSCluster.start();
sUnderFSCluster.registerJVMOnExistHook();
}
return sUnderFSCluster;
}
/**
* Gets the {@link UnderFileSystemCluster}.
*
* @param baseDir the base directory
* @return the {@link UnderFileSystemCluster}
*/
public static UnderFileSystemCluster getUnderFilesystemCluster(String baseDir) {
sUnderFSClass = System.getProperty(INTEGRATION_UFS_PROFILE_KEY);
if (!StringUtils.isEmpty(sUnderFSClass)) {
try {
UnderFileSystemCluster ufsCluster =
(UnderFileSystemCluster) Class.forName(sUnderFSClass).getConstructor(String.class)
.newInstance(baseDir);
LOG.info("Initialized ufs cluster {} for integration testing.", sUnderFSClass);
return ufsCluster;
} catch (Exception e) {
LOG.warn("Failed to initialize the ufs cluster {} for integration testing: {}",
sUnderFSClass, e.getMessage());
throw Throwables.propagate(e);
}
}
LOG.info("Using default {} for integration testing.", LocalFileSystemCluster.class.getName());
return new LocalFileSystemCluster(baseDir);
}
/**
*
* @return the {@link UnderFileSystem} class name
*/
public static synchronized String getUnderFSClass() {
return sUnderFSClass;
}
protected String mBaseDir;
/**
* @param baseDir the base directory
*/
public UnderFileSystemCluster(String baseDir) {
mBaseDir = baseDir;
}
/**
* Cleans up the test environment over underfs cluster system, so that we can re-use the running
* system for the next test round instead of turning on/off it from time to time. This function is
* expected to be called either before or after each test case which avoids certain overhead from
* the bootstrap.
*/
public abstract void cleanup() throws IOException;
/**
* @return the address of the UFS
*/
public abstract String getUnderFilesystemAddress();
/**
* @return if the cluster has started
*/
public abstract boolean isStarted();
/**
* Adds a shutdown hook. The {@link #shutdown()} phase will be automatically called while the
* process exists.
*/
public void registerJVMOnExistHook() throws IOException {
Runtime.getRuntime().addShutdownHook(new ShutdownHook(this));
}
/**
* Stops the underfs cluster system.
*/
public abstract void shutdown() throws IOException;
/**
* Starts the underfs cluster system.
*/
public abstract void start() throws IOException;
}