/*
* 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.IOException;
import java.net.InetSocketAddress;
import org.apache.log4j.Logger;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TThreadedSelectorServer;
import org.apache.thrift.transport.TNonblockingServerSocket;
import org.apache.thrift.transport.TTransportException;
import tachyon.Constants;
import tachyon.LeaderSelectorClient;
import tachyon.UnderFileSystem;
import tachyon.Version;
import tachyon.conf.CommonConf;
import tachyon.conf.MasterConf;
import tachyon.thrift.MasterService;
import tachyon.util.CommonUtils;
import tachyon.web.UIWebServer;
/**
* Entry point for the Master program.
*/
public class TachyonMaster {
private static final Logger LOG = Logger.getLogger(Constants.LOGGER_TYPE);
public static void main(String[] args) {
if (args.length != 0) {
LOG.info("java -cp target/tachyon-" + Version.VERSION + "-jar-with-dependencies.jar "
+ "tachyon.Master");
System.exit(-1);
}
MasterConf mConf = MasterConf.get();
TachyonMaster master =
new TachyonMaster(new InetSocketAddress(mConf.HOSTNAME, mConf.PORT), mConf.WEB_PORT,
mConf.SELECTOR_THREADS, mConf.QUEUE_SIZE_PER_SELECTOR, mConf.SERVER_THREADS);
master.start();
}
private boolean mIsStarted;
private MasterInfo mMasterInfo;
private InetSocketAddress mMasterAddress;
private UIWebServer mWebServer;
private TNonblockingServerSocket mServerTNonblockingServerSocket;
private TServer mMasterServiceServer;
private MasterServiceHandler mMasterServiceHandler;
private Journal mJournal;
private EditLogProcessor mEditLogProcessor;
private int mWebPort;
private int mSelectorThreads;
private int mAcceptQueueSizePerThread;
private int mWorkerThreads;
private boolean mZookeeperMode = false;
private LeaderSelectorClient mLeaderSelectorClient = null;
public TachyonMaster(InetSocketAddress address, int webPort, int selectorThreads,
int acceptQueueSizePerThreads, int workerThreads) {
if (CommonConf.get().USE_ZOOKEEPER) {
mZookeeperMode = true;
}
mIsStarted = false;
mWebPort = webPort;
mSelectorThreads = selectorThreads;
mAcceptQueueSizePerThread = acceptQueueSizePerThreads;
mWorkerThreads = workerThreads;
try {
mMasterAddress = address;
String journalFolder = MasterConf.get().JOURNAL_FOLDER;
if (!isFormatted(journalFolder, MasterConf.get().FORMAT_FILE_PREFIX)) {
LOG.error("Tachyon was not formatted!");
CommonUtils.runtimeException("Tachyon was not formatted!");
}
mJournal = new Journal(journalFolder, "image.data", "log.data");
mMasterInfo = new MasterInfo(mMasterAddress, mJournal);
if (mZookeeperMode) {
CommonConf conf = CommonConf.get();
mLeaderSelectorClient =
new LeaderSelectorClient(conf.ZOOKEEPER_ADDRESS, conf.ZOOKEEPER_ELECTION_PATH,
conf.ZOOKEEPER_LEADER_PATH, address.getHostName() + ":" + address.getPort());
mEditLogProcessor = new EditLogProcessor(mJournal, journalFolder, mMasterInfo);
Thread logProcessor = new Thread(mEditLogProcessor);
logProcessor.start();
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
CommonUtils.runtimeException(e);
}
}
/**
* Get MasterInfo instance for Unit Test
*
* @return MasterInfo of the Master
*/
MasterInfo getMasterInfo() {
return mMasterInfo;
}
private boolean isFormatted(String folder, String path) throws IOException {
if (!folder.endsWith(Constants.PATH_SEPARATOR)) {
folder += Constants.PATH_SEPARATOR;
}
UnderFileSystem ufs = UnderFileSystem.get(folder);
String[] files = ufs.list(folder);
if (files == null) {
return false;
}
for (String file : files) {
if (file.startsWith(path)) {
return true;
}
}
return false;
}
/**
* Get wehether the system is the leader under zookeeper mode, for unit test only.
*
* @return true if the system is the leader under zookeeper mode, false otherwise.
*/
boolean isStarted() {
return mIsStarted;
}
/**
* Get whether the system is for zookeeper mode, for unit test only.
*
* @return true if the master is under zookeeper mode, false otherwise.
*/
boolean isZookeeperMode() {
return mZookeeperMode;
}
private void setup() throws IOException, TTransportException {
if (mZookeeperMode) {
mEditLogProcessor.stop();
}
mMasterInfo.init();
mWebServer =
new UIWebServer("Tachyon Master Server", new InetSocketAddress(
mMasterAddress.getHostName(), mWebPort), mMasterInfo);
mMasterServiceHandler = new MasterServiceHandler(mMasterInfo);
MasterService.Processor<MasterServiceHandler> masterServiceProcessor =
new MasterService.Processor<MasterServiceHandler>(mMasterServiceHandler);
mServerTNonblockingServerSocket = new TNonblockingServerSocket(mMasterAddress);
mMasterServiceServer =
new TThreadedSelectorServer(new TThreadedSelectorServer.Args(
mServerTNonblockingServerSocket).processor(masterServiceProcessor)
.selectorThreads(mSelectorThreads).acceptQueueSizePerThread(mAcceptQueueSizePerThread)
.workerThreads(mWorkerThreads));
mIsStarted = true;
}
public void start() {
if (mZookeeperMode) {
try {
mLeaderSelectorClient.start();
} catch (IOException e) {
LOG.error(e.getMessage(), e);
CommonUtils.runtimeException(e);
}
Thread currentThread = Thread.currentThread();
mLeaderSelectorClient.setCurrentMasterThread(currentThread);
boolean running = false;
while (true) {
if (mLeaderSelectorClient.isLeader()) {
if (!running) {
running = true;
try {
setup();
} catch (IOException e) {
LOG.error(e.getMessage(), e);
CommonUtils.runtimeException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage(), e);
CommonUtils.runtimeException(e);
}
mWebServer.startWebServer();
LOG.info("The master (leader) server started @ " + mMasterAddress);
mMasterServiceServer.serve();
LOG.info("The master (previous leader) server ended @ " + mMasterAddress);
mJournal.close();
}
} else {
if (running) {
mMasterServiceServer.stop();
running = false;
}
}
CommonUtils.sleepMs(LOG, 100);
}
} else {
try {
setup();
} catch (IOException e) {
LOG.error(e.getMessage(), e);
CommonUtils.runtimeException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage(), e);
CommonUtils.runtimeException(e);
}
mWebServer.startWebServer();
LOG.info("The master server started @ " + mMasterAddress);
mMasterServiceServer.serve();
LOG.info("The master server ended @ " + mMasterAddress);
}
}
public void stop() throws Exception {
if (mIsStarted) {
mWebServer.shutdownWebServer();
mMasterInfo.stop();
mMasterServiceServer.stop();
mServerTNonblockingServerSocket.close();
mIsStarted = false;
}
if (mZookeeperMode) {
if (mLeaderSelectorClient != null) {
mLeaderSelectorClient.close();
}
if (mEditLogProcessor != null) {
mEditLogProcessor.stop();
}
}
}
}