/*
* 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.worker;
import java.io.IOException;
import java.net.InetSocketAddress;
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.conf.UserConf;
import tachyon.thrift.BlockInfoException;
import tachyon.thrift.FailedToCheckpointException;
import tachyon.thrift.FileDoesNotExistException;
import tachyon.thrift.SuspectedFileSizeException;
import tachyon.thrift.TachyonException;
import tachyon.thrift.WorkerService;
/**
* The client talks to a worker server. It keeps sending keep alive message to the worker server.
*
* Since WorkerService.Client is not thread safe, this class has to guarantee thread safe.
*/
public class WorkerClient {
private final Logger LOG = Logger.getLogger(Constants.LOGGER_TYPE);
private final WorkerService.Client CLIENT;
private TProtocol mProtocol;
private InetSocketAddress mWorkerAddress;
private boolean mIsConnected = false;
private long mUserId;
private HeartbeatThread mHeartbeatThread = null;
private String mRootFolder = null;
/**
* @param address
* The address of the worker the client trying to contect to.
* @param userId
* The user id of the client
*/
public WorkerClient(InetSocketAddress address, long userId) {
mWorkerAddress = address;
mProtocol =
new TBinaryProtocol(new TFramedTransport(new TSocket(mWorkerAddress.getHostName(),
mWorkerAddress.getPort())));
CLIENT = new WorkerService.Client(mProtocol);
mUserId = userId;
mHeartbeatThread =
new HeartbeatThread("WorkerClientToWorkerHeartbeat", new WorkerClientHeartbeatExecutor(
this, mUserId), UserConf.get().HEARTBEAT_INTERVAL_MS);
}
/**
* Update the latest block access time on the worker.
*
* @param blockId
* The id of the block
* @throws TException
*/
public synchronized void accessBlock(long blockId) throws TException {
CLIENT.accessBlock(blockId);
}
/**
* Notify the worker that the checkpoint file of the file has been added.
*
* @param userId
* The user id of the client who send the notification
* @param fileId
* The id of the checkpointed file
* @throws IOException
* @throws TException
*/
public synchronized void addCheckpoint(long userId, int fileId) throws IOException, TException {
try {
CLIENT.addCheckpoint(userId, fileId);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (SuspectedFileSizeException e) {
throw new IOException(e);
} catch (FailedToCheckpointException e) {
throw new IOException(e);
} catch (BlockInfoException e) {
throw new IOException(e);
}
}
/**
* Notify the worker to checkpoint the file asynchronously.
*
* @param fid
* The id of the file
* @return true if succeed, false otherwise
* @throws TachyonException
* @throws TException
*/
public synchronized boolean asyncCheckpoint(int fid) throws TachyonException, TException {
return CLIENT.asyncCheckpoint(fid);
}
/**
* Notify the worker the block is cached.
*
* @param userId
* The user id of the client who send the notification
* @param blockId
* The id of the block
* @throws IOException
* @throws TException
*/
public synchronized void cacheBlock(long userId, long blockId) throws IOException, TException {
try {
CLIENT.cacheBlock(userId, blockId);
} catch (FileDoesNotExistException e) {
throw new IOException(e);
} catch (BlockInfoException e) {
throw new IOException(e);
} catch (SuspectedFileSizeException e) {
throw new IOException(e);
}
}
/**
* Close the connection to worker. Shutdown the heartbeat thread.
*/
public synchronized void close() {
if (mIsConnected) {
mProtocol.getTransport().close();
mHeartbeatThread.shutdown();
mIsConnected = false;
}
}
/**
* @return The root local data folder of the worker
* @throws TException
*/
public synchronized String getDataFolder() throws TException {
if (mRootFolder == null) {
mRootFolder = CLIENT.getDataFolder();
}
return mRootFolder;
}
/**
* Get the local user temporary folder of the specified user.
*
* @param userId
* The id of the user
* @return The local user temporary folder of the specified user
* @throws TException
*/
public synchronized String getUserTempFolder(long userId) throws TException {
return CLIENT.getUserTempFolder(userId);
}
/**
* Get the user temporary folder in the under file system of the specified user.
*
* @param userId
* The id of the user
* @return The user temporary folder in the under file system
* @throws TException
*/
public synchronized String getUserUnderfsTempFolder(long userId) throws TException {
return CLIENT.getUserUnderfsTempFolder(userId);
}
/**
* @return true if it's connected to the worker, false otherwise
*/
public synchronized boolean isConnected() {
return mIsConnected;
}
/**
* Lock the block, therefore, the worker will lock evict the block from the memory untill it is
* unlocked.
*
* @param blockId
* The id of the block
* @param userId
* The id of the user who wants to lock the block
* @throws TException
*/
public synchronized void lockBlock(long blockId, long userId) throws TException {
CLIENT.lockBlock(blockId, userId);
}
/**
* Open the connection to the worker. And start the heartbeat thread.
*
* @return true if succeed, false otherwise
*/
public synchronized boolean open() {
if (!mIsConnected) {
try {
mProtocol.getTransport().open();
} catch (TTransportException e) {
LOG.error(e.getMessage(), e);
return false;
}
mHeartbeatThread.start();
mIsConnected = true;
}
return mIsConnected;
}
/**
* Request space from the worker's memory
*
* @param userId
* The id of the user who send the request
* @param requestBytes
* The requested space size, in bytes
* @return true if succeed, false otherwise
* @throws TException
*/
public synchronized boolean requestSpace(long userId, long requestBytes) throws TException {
return CLIENT.requestSpace(userId, requestBytes);
}
/**
* Return the space which has been requested
*
* @param userId
* The id of the user who wants to return the space
* @param returnSpaceBytes
* The returned space size, in bytes
* @throws TException
*/
public synchronized void returnSpace(long userId, long returnSpaceBytes) throws TException {
CLIENT.returnSpace(userId, returnSpaceBytes);
}
/**
* Unlock the block
*
* @param blockId
* The id of the block
* @param userId
* The id of the user who wants to unlock the block
* @throws TException
*/
public synchronized void unlockBlock(long blockId, long userId) throws TException {
CLIENT.unlockBlock(blockId, userId);
}
/**
* Users' heartbeat to the Worker.
*
* @param userId
* The id of the user
* @throws TException
*/
public synchronized void userHeartbeat(long userId) throws TException {
CLIENT.userHeartbeat(userId);
}
}