/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 tachyon.master;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import tachyon.Constants;
import tachyon.UnderFileSystem;
import tachyon.UnderFileSystemCluster;
import tachyon.client.TachyonFS;
import tachyon.conf.CommonConf;
import tachyon.conf.MasterConf;
import tachyon.conf.UserConf;
import tachyon.conf.WorkerConf;
import tachyon.util.CommonUtils;
import tachyon.worker.TachyonWorker;
/**
* Local Tachyon cluster for unit tests.
*/
public class LocalTachyonCluster {
public static void main(String[] args) throws Exception {
LocalTachyonCluster cluster = new LocalTachyonCluster(100);
cluster.start();
CommonUtils.sleepMs(null, Constants.SECOND_MS);
cluster.stop();
CommonUtils.sleepMs(null, Constants.SECOND_MS);
cluster = new LocalTachyonCluster(100);
cluster.start();
CommonUtils.sleepMs(null, Constants.SECOND_MS);
cluster.stop();
CommonUtils.sleepMs(null, Constants.SECOND_MS);
}
private TachyonMaster mMaster = null;
private TachyonWorker mWorker = null;
private int mMasterPort;
private int mWorkerPort;
private long mWorkerCapacityBytes;
private String mTachyonHome;
private String mWorkerDataFolder;
private Thread mMasterThread = null;
private Thread mWorkerThread = null;
private String mLocalhostName = null;
private UnderFileSystemCluster mUnderFSCluster = null;
private List<TachyonFS> mClients = new ArrayList<TachyonFS>();
public LocalTachyonCluster(int masterPort, int workerPort, long workerCapacityBytes) {
mMasterPort = masterPort;
mWorkerPort = workerPort;
mWorkerCapacityBytes = workerCapacityBytes;
}
public LocalTachyonCluster(long workerCapacityBytes) {
mMasterPort = Constants.DEFAULT_MASTER_PORT - 1000;
mWorkerPort = Constants.DEFAULT_WORKER_PORT - 1000;
mWorkerCapacityBytes = workerCapacityBytes;
}
public synchronized TachyonFS getClient() throws IOException {
mClients.add(TachyonFS.get(Constants.HEADER + mLocalhostName + ":" + mMasterPort));
return mClients.get(mClients.size() - 1);
}
public String getEditLogPath() {
return mUnderFSCluster.getUnderFilesystemAddress() + "/journal/log.data";
}
public String getImagePath() {
return mUnderFSCluster.getUnderFilesystemAddress() + "/journal/image.data";
}
public InetSocketAddress getMasterAddress() {
return new InetSocketAddress(mLocalhostName, mMasterPort);
}
public String getMasterHostname() {
return mLocalhostName;
}
public MasterInfo getMasterInfo() {
return mMaster.getMasterInfo();
}
public int getMasterPort() {
return mMasterPort;
}
public String getTachyonHome() {
return mTachyonHome;
}
public String getTempFolderInUnderFs() {
return CommonConf.get().UNDERFS_ADDRESS;
}
public TachyonWorker getWorker() {
return mWorker;
}
public InetSocketAddress getWorkerAddress() {
return new InetSocketAddress(mLocalhostName, mWorkerPort);
}
public String getWorkerDataFolder() {
return mWorkerDataFolder;
}
public int getWorkerPort() {
return mWorkerPort;
}
private void deleteDir(String path) throws IOException {
UnderFileSystem ufs = UnderFileSystem.get(path);
if (ufs.exists(path) && !ufs.delete(path, true)) {
throw new IOException("Folder " + path + " already exists but can not be deleted.");
}
}
private void mkdir(String path) throws IOException {
UnderFileSystem ufs = UnderFileSystem.get(path);
if (!ufs.mkdirs(path, true)) {
throw new IOException("Failed to make folder: " + path);
}
}
public void start() throws IOException {
mTachyonHome =
File.createTempFile("Tachyon", "").getAbsoluteFile() + "U" + System.currentTimeMillis();
mWorkerDataFolder = mTachyonHome + "/ramdisk";
String masterDataFolder = mTachyonHome + "/data";
String masterLogFolder = mTachyonHome + "/logs";
deleteDir(mTachyonHome);
mkdir(mTachyonHome);
mkdir(masterDataFolder);
mkdir(masterLogFolder);
mLocalhostName = InetAddress.getLocalHost().getCanonicalHostName();
// To start the UFS either for integration or unit test. If it targets the unit test, UFS is
// setup over the local file system (see also {@link LocalFilesystemCluster} - under folder of
// "mTachyonHome/tachyon*". Otherwise, it starts some distributed file system cluster e.g.,
// miniDFSCluster (see also {@link tachyon.LocalMiniDFScluster} and setup the folder like
// "hdfs://xxx:xxx/tachyon*".
mUnderFSCluster = UnderFileSystemCluster.get(mTachyonHome + "/dfs");
String underfsFolder = mUnderFSCluster.getUnderFilesystemAddress() + "/tachyon_underfs_folder";
// To setup the journalFolder under either local file system or distributed ufs like
// miniDFSCluster
String masterJournalFolder = mUnderFSCluster.getUnderFilesystemAddress() + "/journal";
System.setProperty("tachyon.home", mTachyonHome);
System.setProperty("tachyon.master.hostname", mLocalhostName);
System.setProperty("tachyon.master.journal.folder", masterJournalFolder);
System.setProperty("tachyon.master.port", mMasterPort + "");
System.setProperty("tachyon.master.web.port", (mMasterPort + 1) + "");
System.setProperty("tachyon.worker.port", mWorkerPort + "");
System.setProperty("tachyon.worker.data.port", (mWorkerPort + 1) + "");
System.setProperty("tachyon.worker.data.folder", mWorkerDataFolder);
System.setProperty("tachyon.worker.memory.size", mWorkerCapacityBytes + "");
System.setProperty("tachyon.worker.to.master.heartbeat.interval.ms", 15 + "");
System.setProperty("tachyon.underfs.address", underfsFolder);
System.setProperty("tachyon.user.remote.read.buffer.size.byte", 64 + "");
CommonConf.clear();
MasterConf.clear();
WorkerConf.clear();
UserConf.clear();
mkdir(masterJournalFolder);
CommonUtils.touch(masterJournalFolder + "/_format_" + System.currentTimeMillis());
mkdir(CommonConf.get().UNDERFS_DATA_FOLDER);
mkdir(CommonConf.get().UNDERFS_WORKERS_FOLDER);
mMaster =
new TachyonMaster(new InetSocketAddress(mLocalhostName, mMasterPort), mMasterPort + 1, 1,
1, 1);
Runnable runMaster = new Runnable() {
@Override
public void run() {
try {
mMaster.start();
} catch (Exception e) {
CommonUtils.runtimeException(e + " \n Start Master Error \n" + e.getMessage());
}
}
};
mMasterThread = new Thread(runMaster);
mMasterThread.start();
CommonUtils.sleepMs(null, 10);
mWorker =
TachyonWorker.createWorker(new InetSocketAddress(mLocalhostName, mMasterPort),
new InetSocketAddress(mLocalhostName, mWorkerPort), mWorkerPort + 1, 1, 1, 1,
mWorkerDataFolder, mWorkerCapacityBytes);
Runnable runWorker = new Runnable() {
@Override
public void run() {
try {
mWorker.start();
} catch (Exception e) {
CommonUtils.runtimeException(e + " \n Start Worker Error \n" + e.getMessage());
}
}
};
mWorkerThread = new Thread(runWorker);
mWorkerThread.start();
}
/**
* Stop both of the tachyon and underfs service threads.
*
* @throws Exception
*/
public void stop() throws Exception {
stopTFS();
stopUFS();
}
/**
* Stop the tachyon filesystem's service thread only
*
* @throws Exception
*/
public void stopTFS() throws Exception {
for (TachyonFS fs : mClients) {
fs.close();
}
mWorker.stop();
mMaster.stop();
System.clearProperty("tachyon.home");
System.clearProperty("tachyon.master.hostname");
System.clearProperty("tachyon.master.port");
System.clearProperty("tachyon.master.web.port");
System.clearProperty("tachyon.worker.port");
System.clearProperty("tachyon.worker.data.port");
System.clearProperty("tachyon.worker.data.folder");
System.clearProperty("tachyon.worker.memory.size");
System.clearProperty("tachyon.user.remote.read.buffer.size.byte");
System.clearProperty("tachyon.worker.to.master.heartbeat.interval.ms");
}
/**
* Cleanup the underfs cluster test folder only
*
* @throws Exception
*/
public void stopUFS() throws Exception {
if (null != mUnderFSCluster) {
mUnderFSCluster.cleanup();
}
System.clearProperty("tachyon.master.journal.folder");
System.clearProperty("tachyon.underfs.address");
}
public void stopWorker() throws Exception {
for (TachyonFS fs : mClients) {
fs.close();
}
mClients.clear();
mWorker.stop();
}
}