/*
* 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.master;
import alluxio.AlluxioTestDirectory;
import alluxio.Configuration;
import alluxio.Constants;
import alluxio.PropertyKey;
import alluxio.client.file.FileSystem;
import alluxio.util.io.FileUtils;
import alluxio.util.network.NetworkAddressUtils;
import alluxio.util.network.NetworkAddressUtils.ServiceType;
import com.google.common.base.Supplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.annotation.concurrent.NotThreadSafe;
/**
* Constructs an isolated master. Primary users of this class are the {@link LocalAlluxioCluster}
* and {@link MultiMasterLocalAlluxioCluster}.
*
* Isolated is defined as having its own root directory, and port.
*/
@NotThreadSafe
public final class LocalAlluxioMaster {
private static final Logger LOG = LoggerFactory.getLogger(LocalAlluxioMaster.class);
private final String mHostname;
private final String mJournalFolder;
private final Supplier<String> mClientSupplier = new Supplier<String>() {
@Override
public String get() {
return getUri();
}
};
private final ClientPool mClientPool = new ClientPool(mClientSupplier);
private MasterProcess mMasterProcess;
private Thread mMasterThread;
private AlluxioSecondaryMaster mSecondaryMaster;
private Thread mSecondaryMasterThread;
private LocalAlluxioMaster() throws IOException {
mHostname = NetworkAddressUtils.getConnectHost(ServiceType.MASTER_RPC);
mJournalFolder = Configuration.get(PropertyKey.MASTER_JOURNAL_FOLDER);
}
/**
* Creates a new local Alluxio master with an isolated work directory and port.
*
* @return an instance of Alluxio master
*/
public static LocalAlluxioMaster create() throws IOException {
String workDirectory = uniquePath();
FileUtils.deletePathRecursively(workDirectory);
Configuration.set(PropertyKey.WORK_DIR, workDirectory);
return create(workDirectory);
}
/**
* Creates a new local Alluxio master with a isolated port.
*
* @param workDirectory Alluxio work directory, this method will create it if it doesn't exist yet
* @return the created Alluxio master
*/
public static LocalAlluxioMaster create(final String workDirectory) throws IOException {
if (!Files.isDirectory(Paths.get(workDirectory))) {
Files.createDirectory(Paths.get(workDirectory));
}
return new LocalAlluxioMaster();
}
/**
* Starts the master.
*/
public void start() {
mMasterProcess = MasterProcess.Factory.create();
Runnable runMaster = new Runnable() {
@Override
public void run() {
try {
LOG.info("Starting Alluxio master {}.", mMasterProcess);
mMasterProcess.start();
} catch (InterruptedException e) {
// this is expected
} catch (Exception e) {
// Log the exception as the RuntimeException will be caught and handled silently by JUnit
LOG.error("Start master error", e);
throw new RuntimeException(e + " \n Start Master Error \n" + e.getMessage(), e);
}
}
};
mMasterThread = new Thread(runMaster);
mMasterThread.setName("MasterThread-" + System.identityHashCode(mMasterThread));
mMasterThread.start();
mMasterProcess.waitForReady();
mSecondaryMaster = new AlluxioSecondaryMaster();
Runnable runSecondaryMaster = new Runnable() {
@Override
public void run() {
try {
LOG.info("Starting secondary master {}.", mSecondaryMaster);
mSecondaryMaster.start();
} catch (InterruptedException e) {
// this is expected
} catch (Exception e) {
// Log the exception as the RuntimeException will be caught and handled silently by JUnit
LOG.error("Start secondary master error", e);
throw new RuntimeException(e + " \n Start Secondary Master Error \n" + e.getMessage(), e);
}
}
};
mSecondaryMasterThread = new Thread(runSecondaryMaster);
mSecondaryMasterThread
.setName("SecondaryMasterThread-" + System.identityHashCode(mSecondaryMasterThread));
mSecondaryMasterThread.start();
mSecondaryMaster.waitForReady();
}
/**
* @return true if the master is serving, false otherwise
*/
public boolean isServing() {
return mMasterProcess.isServing();
}
/**
* Stops the master processes and cleans up client connections.
*/
public void stop() throws Exception {
mSecondaryMaster.stop();
if (mSecondaryMasterThread != null) {
while (mSecondaryMasterThread.isAlive()) {
LOG.info("Stopping thread {}.", mSecondaryMasterThread.getName());
mSecondaryMasterThread.interrupt();
mSecondaryMasterThread.join(1000);
}
mSecondaryMasterThread = null;
}
mMasterProcess.stop();
if (mMasterThread != null) {
while (mMasterThread.isAlive()) {
LOG.info("Stopping thread {}.", mMasterThread.getName());
mMasterThread.interrupt();
mMasterThread.join(1000);
}
mMasterThread = null;
}
clearClients();
System.clearProperty("alluxio.web.resources");
System.clearProperty("alluxio.master.min.worker.threads");
}
/**
* Clears all the clients.
*/
public void clearClients() throws IOException {
mClientPool.close();
}
/**
* @return the externally resolvable address of the master
*/
public InetSocketAddress getAddress() {
return mMasterProcess.getRpcAddress();
}
/**
* @return the internal {@link MasterProcess}
*/
public MasterProcess getMasterProcess() {
return mMasterProcess;
}
/**
* Gets the actual port that the RPC service is listening on.
*
* @return the RPC local port
*/
public int getRpcLocalPort() {
return mMasterProcess.getRpcAddress().getPort();
}
/**
* @return the URI of the master
*/
public String getUri() {
return Constants.HEADER + mHostname + ":" + getRpcLocalPort();
}
/**
* @return the client from the pool
*/
public FileSystem getClient() throws IOException {
return mClientPool.getClient();
}
private static String uniquePath() throws IOException {
return AlluxioTestDirectory.createTemporaryDirectory("alluxio-master").getAbsolutePath();
}
/**
* @return the folder of the journal
*/
public String getJournalFolder() {
return mJournalFolder;
}
}