/*
* 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 java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransportException;
import org.apache.log4j.Logger;
import tachyon.Constants;
import tachyon.HeartbeatThread;
import tachyon.LeaderInquireClient;
import tachyon.conf.CommonConf;
import tachyon.conf.UserConf;
import tachyon.thrift.BlockInfoException;
import tachyon.thrift.ClientBlockInfo;
import tachyon.thrift.ClientDependencyInfo;
import tachyon.thrift.ClientFileInfo;
import tachyon.thrift.ClientRawTableInfo;
import tachyon.thrift.ClientWorkerInfo;
import tachyon.thrift.Command;
import tachyon.thrift.DependencyDoesNotExistException;
import tachyon.thrift.FileAlreadyExistException;
import tachyon.thrift.FileDoesNotExistException;
import tachyon.thrift.InvalidPathException;
import tachyon.thrift.MasterService;
import tachyon.thrift.NetAddress;
import tachyon.thrift.NoWorkerException;
import tachyon.thrift.SuspectedFileSizeException;
import tachyon.thrift.TableColumnException;
import tachyon.thrift.TableDoesNotExistException;
import tachyon.thrift.TachyonException;
import tachyon.util.CommonUtils;
/**
* The master server client side.
*
* Since MasterService.Client is not thread safe, this class has to guarantee thread safe.
*/
public class MasterClient {
private final static int MAX_CONNECT_TRY = 5;
private final Logger LOG = Logger.getLogger(Constants.LOGGER_TYPE);
private boolean mUseZookeeper;
private MasterService.Client mClient = null;
private InetSocketAddress mMasterAddress = null;
private TProtocol mProtocol = null;
private volatile boolean mIsConnected;
private volatile boolean mIsShutdown;
private volatile long mLastAccessedMs;
private HeartbeatThread mHeartbeatThread = null;
public MasterClient(InetSocketAddress masterAddress) {
this(masterAddress, CommonConf.get().USE_ZOOKEEPER);
}
public MasterClient(InetSocketAddress masterAddress, boolean useZookeeper) {
mUseZookeeper = useZookeeper;
if (!mUseZookeeper) {
mMasterAddress = masterAddress;
}
mIsConnected = false;
mIsShutdown = false;
}
/**
* @param workerId
* if -1, means the checkpoint is added directly by the client from underlayer fs.
* @param fileId
* @param length
* @param checkpointPath
* @return
* @throws FileDoesNotExistException
* @throws SuspectedFileSizeException
* @throws BlockInfoException
* @throws TException
*/
public synchronized boolean addCheckpoint(long workerId, int fileId, long length,
String checkpointPath) throws FileDoesNotExistException, SuspectedFileSizeException,
BlockInfoException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.addCheckpoint(workerId, fileId, length, checkpointPath);
} catch (TException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return false;
}
/**
* Clean the connect. E.g. if the client has not connect the master for a while, the connection
* should be shut down.
*/
public synchronized void cleanConnect() {
if (mIsConnected) {
LOG.debug("Disconnecting from the master " + mMasterAddress);
mIsConnected = false;
}
if (mProtocol != null) {
mProtocol.getTransport().close();
}
if (mHeartbeatThread != null) {
mHeartbeatThread.shutdown();
}
}
/**
* Connects to the Tachyon Master; an exception is thrown if this fails.
*/
public synchronized void connect() throws TException {
mLastAccessedMs = System.currentTimeMillis();
if (mIsConnected) {
return;
}
cleanConnect();
if (mIsShutdown) {
throw new TException("Client is shutdown, will not try to connect");
}
int tries = 0;
Exception lastException = null;
while (tries ++ < MAX_CONNECT_TRY && !mIsShutdown) {
mMasterAddress = getMasterAddress();
mProtocol =
new TBinaryProtocol(new TFramedTransport(new TSocket(mMasterAddress.getHostName(),
mMasterAddress.getPort())));
mClient = new MasterService.Client(mProtocol);
mLastAccessedMs = System.currentTimeMillis();
try {
mProtocol.getTransport().open();
mHeartbeatThread =
new HeartbeatThread("Master_Client Heartbeat", new MasterClientHeartbeatExecutor(this,
UserConf.get().MASTER_CLIENT_TIMEOUT_MS),
UserConf.get().MASTER_CLIENT_TIMEOUT_MS / 2);
mHeartbeatThread.start();
} catch (TTransportException e) {
lastException = e;
LOG.error("Failed to connect (" + tries + ") to master " + mMasterAddress + " : "
+ e.getMessage());
if (mHeartbeatThread != null) {
mHeartbeatThread.shutdown();
}
CommonUtils.sleepMs(LOG, Constants.SECOND_MS);
continue;
}
mIsConnected = true;
return;
}
// Reaching here indicates that we did not successfully connect.
throw new TException("Failed to connect to master " + mMasterAddress + " after " + (tries - 1)
+ " attempts", lastException);
}
public ClientDependencyInfo getClientDependencyInfo(int did) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_getClientDependencyInfo(did);
} catch (DependencyDoesNotExistException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public synchronized ClientFileInfo getClientFileInfoById(int id) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.getClientFileInfoById(id);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (TException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
long getLastAccessedMs() {
return mLastAccessedMs;
}
private InetSocketAddress getMasterAddress() {
if (!mUseZookeeper) {
return mMasterAddress;
}
LeaderInquireClient leaderInquireClient =
LeaderInquireClient.getClient(CommonConf.get().ZOOKEEPER_ADDRESS,
CommonConf.get().ZOOKEEPER_LEADER_PATH);
try {
String temp = leaderInquireClient.getMasterAddress();
return CommonUtils.parseInetSocketAddress(temp);
} catch (IOException e) {
LOG.error(e.getMessage(), e);
CommonUtils.runtimeException(e);
}
return null;
}
public synchronized long getUserId() throws TException {
while (!mIsShutdown) {
connect();
try {
long ret = mClient.user_getUserId();
LOG.info("User registered at the master " + mMasterAddress + " got UserId " + ret);
return ret;
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return -1;
}
public synchronized List<ClientWorkerInfo> getWorkersInfo() throws TException {
while (!mIsShutdown) {
connect();
try {
return mClient.getWorkersInfo();
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public synchronized boolean isConnected() {
return mIsConnected;
}
public synchronized List<ClientFileInfo> listStatus(String path) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.liststatus(path);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (TException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public void shutdown() {
mIsShutdown = true;
if (mProtocol != null) {
mProtocol.getTransport().close();
}
cleanConnect();
}
public synchronized void user_completeFile(int fId) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
mClient.user_completeFile(fId);
return;
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
}
public synchronized int user_createDependency(List<String> parents, List<String> children,
String commandPrefix, List<ByteBuffer> data, String comment, String framework,
String frameworkVersion, int dependencyType, long childrenBlockSizeByte) throws IOException,
TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_createDependency(parents, children, commandPrefix, data, comment,
framework, frameworkVersion, dependencyType, childrenBlockSizeByte);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (FileAlreadyExistException e) {
throw new IOException(e);
} catch (BlockInfoException e) {
throw new IOException(e);
} catch (TachyonException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return -1;
}
public synchronized int user_createFile(String path, long blockSizeByte) throws IOException,
TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_createFile(path, blockSizeByte);
} catch (FileAlreadyExistException e) {
throw new IOException(e);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (BlockInfoException e) {
throw new IOException(e);
} catch (TachyonException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return -1;
}
public int user_createFileOnCheckpoint(String path, String checkpointPath) throws IOException,
TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_createFileOnCheckpoint(path, checkpointPath);
} catch (FileAlreadyExistException e) {
throw new IOException(e);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (SuspectedFileSizeException e) {
throw new IOException(e);
} catch (BlockInfoException e) {
throw new IOException(e);
} catch (TachyonException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return -1;
}
public synchronized long user_createNewBlock(int fId) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_createNewBlock(fId);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return -1;
}
public synchronized int user_createRawTable(String path, int columns, ByteBuffer metadata)
throws IOException, TException {
if (metadata == null) {
metadata = ByteBuffer.allocate(0);
}
while (!mIsShutdown) {
connect();
try {
return mClient.user_createRawTable(path, columns, metadata);
} catch (FileAlreadyExistException e) {
throw new IOException(e);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (TableColumnException e) {
throw new IOException(e);
} catch (TachyonException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return -1;
}
public synchronized boolean user_delete(int fileId, boolean recursive) throws IOException,
TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_deleteById(fileId, recursive);
} catch (TachyonException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return false;
}
public synchronized boolean user_delete(String path, boolean recursive) throws IOException,
TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_deleteByPath(path, recursive);
} catch (TachyonException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return false;
}
public synchronized long user_getBlockId(int fId, int index) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_getBlockId(fId, index);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return -1;
}
public ClientBlockInfo user_getClientBlockInfo(long blockId) throws FileDoesNotExistException,
BlockInfoException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_getClientBlockInfo(blockId);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public synchronized ClientFileInfo user_getClientFileInfoByPath(String path) throws IOException,
TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_getClientFileInfoByPath(path);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public synchronized ClientRawTableInfo user_getClientRawTableInfoById(int id)
throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
ClientRawTableInfo ret = mClient.user_getClientRawTableInfoById(id);
ret.setMetadata(CommonUtils.generateNewByteBufferFromThriftRPCResults(ret.metadata));
return ret;
} catch (TableDoesNotExistException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public synchronized ClientRawTableInfo user_getClientRawTableInfoByPath(String path)
throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
ClientRawTableInfo ret = mClient.user_getClientRawTableInfoByPath(path);
ret.setMetadata(CommonUtils.generateNewByteBufferFromThriftRPCResults(ret.metadata));
return ret;
} catch (TableDoesNotExistException e) {
throw new IOException(e);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public synchronized List<ClientBlockInfo> user_getFileBlocks(int id) throws IOException,
TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_getFileBlocksById(id);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public synchronized int user_getFileId(String path) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_getFileId(path);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return -1;
}
public synchronized int user_getNumberOfFiles(String folderPath) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_getNumberOfFiles(folderPath);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return -1;
}
public synchronized int user_getRawTableId(String path) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_getRawTableId(path);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return -1;
}
public synchronized String user_getUnderfsAddress() throws TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_getUnderfsAddress();
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public synchronized NetAddress user_getWorker(boolean random, String hostname)
throws NoWorkerException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_getWorker(random, hostname);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public synchronized List<Integer> user_listFiles(String path, boolean recursive)
throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_listFiles(path, recursive);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public synchronized List<String> user_ls(String path, boolean recursive) throws IOException,
TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_ls(path, recursive);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public synchronized boolean user_mkdir(String path) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_mkdir(path);
} catch (FileAlreadyExistException e) {
throw new IOException(e);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (TachyonException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return false;
}
public synchronized void user_outOfMemoryForPinFile(int fileId) throws TException {
while (!mIsShutdown) {
connect();
try {
mClient.user_outOfMemoryForPinFile(fileId);
return;
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
}
public synchronized boolean user_rename(String srcPath, String dstPath) throws IOException,
TException {
while (!mIsShutdown) {
connect();
try {
return mClient.user_rename(srcPath, dstPath);
} catch (FileAlreadyExistException e) {
throw new IOException(e);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return false;
}
public void user_renameTo(int fId, String path) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
mClient.user_renameTo(fId, path);
return;
} catch (FileAlreadyExistException e) {
throw new IOException(e);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (InvalidPathException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
}
public synchronized void user_reportLostFile(int fileId) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
mClient.user_reportLostFile(fileId);
return;
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
}
public synchronized void user_requestFilesInDependency(int depId) throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
mClient.user_requestFilesInDependency(depId);
return;
} catch (DependencyDoesNotExistException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
}
public synchronized void user_setPinned(int id, boolean pinned)
throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
mClient.user_setPinned(id, pinned);
return;
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
}
public synchronized void user_updateRawTableMetadata(int id, ByteBuffer metadata)
throws IOException, TException {
while (!mIsShutdown) {
connect();
try {
mClient.user_updateRawTableMetadata(id, metadata);
return;
} catch (TableDoesNotExistException e) {
throw new IOException(e);
} catch (TachyonException e) {
throw new IOException(e);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
}
public synchronized void worker_cacheBlock(long workerId, long workerUsedBytes, long blockId,
long length) throws FileDoesNotExistException, SuspectedFileSizeException,
BlockInfoException, TException {
while (!mIsShutdown) {
connect();
try {
mClient.worker_cacheBlock(workerId, workerUsedBytes, blockId, length);
return;
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
}
public synchronized Set<Integer> worker_getPinIdList() throws TException {
while (!mIsShutdown) {
connect();
try {
return mClient.worker_getPinIdList();
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
public synchronized List<Integer> worker_getPriorityDependencyList() throws TException {
while (!mIsShutdown) {
connect();
try {
return mClient.worker_getPriorityDependencyList();
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return new ArrayList<Integer>();
}
public synchronized Command worker_heartbeat(long workerId, long usedBytes,
List<Long> removedPartitionList) throws BlockInfoException, TException {
while (!mIsShutdown) {
connect();
try {
return mClient.worker_heartbeat(workerId, usedBytes, removedPartitionList);
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return null;
}
/**
* Register the worker to the master.
*
* @param workerNetAddress
* Worker's NetAddress
* @param totalBytes
* Worker's capacity
* @param usedBytes
* Worker's used storage
* @param currentBlockList
* Blocks in worker's space.
* @return the worker id assigned by the master.
* @throws BlockInfoException
* @throws TException
*/
public synchronized long worker_register(NetAddress workerNetAddress, long totalBytes,
long usedBytes, List<Long> currentBlockList) throws BlockInfoException, TException {
while (!mIsShutdown) {
connect();
try {
long ret =
mClient.worker_register(workerNetAddress, totalBytes, usedBytes, currentBlockList);
LOG.info("Registered at the master " + mMasterAddress + " from worker " + workerNetAddress
+ " , got WorkerId " + ret);
return ret;
} catch (TTransportException e) {
LOG.error(e.getMessage());
mIsConnected = false;
}
}
return -1;
}
}