/**
* 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 org.apache.tajo.worker;
import com.google.common.base.Preconditions;
import com.google.protobuf.RpcController;
import com.google.protobuf.ServiceException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.yarn.service.AbstractService;
import org.apache.tajo.QueryId;
import org.apache.tajo.QueryIdFactory;
import org.apache.tajo.TajoIdProtos;
import org.apache.tajo.TajoProtos;
import org.apache.tajo.conf.TajoConf;
import org.apache.tajo.ipc.ClientProtos;
import org.apache.tajo.ipc.QueryMasterClientProtocol;
import org.apache.tajo.master.querymaster.Query;
import org.apache.tajo.master.querymaster.QueryMasterTask;
import org.apache.tajo.rpc.BlockingRpcServer;
import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos;
import org.apache.tajo.util.NetUtils;
import java.io.IOException;
import java.net.InetSocketAddress;
public class TajoWorkerClientService extends AbstractService {
private static final Log LOG = LogFactory.getLog(TajoWorkerClientService.class);
private final PrimitiveProtos.BoolProto BOOL_TRUE =
PrimitiveProtos.BoolProto.newBuilder().setValue(true).build();
private final PrimitiveProtos.BoolProto BOOL_FALSE =
PrimitiveProtos.BoolProto.newBuilder().setValue(false).build();
private BlockingRpcServer rpcServer;
private InetSocketAddress bindAddr;
private String addr;
private int port;
private TajoConf conf;
private TajoWorker.WorkerContext workerContext;
private TajoWorkerClientProtocolServiceHandler serviceHandler;
public TajoWorkerClientService(TajoWorker.WorkerContext workerContext, int port) {
super(TajoWorkerClientService.class.getName());
this.port = port;
this.workerContext = workerContext;
}
@Override
public void init(Configuration conf) {
Preconditions.checkArgument(conf instanceof TajoConf);
this.conf = (TajoConf) conf;
this.serviceHandler = new TajoWorkerClientProtocolServiceHandler();
// init RPC Server in constructor cause Heartbeat Thread use bindAddr
// Setup RPC server
try {
// TODO initial port num is value of config and find unused port with sequence
InetSocketAddress initIsa = new InetSocketAddress("0.0.0.0", port);
if (initIsa.getAddress() == null) {
throw new IllegalArgumentException("Failed resolve of " + initIsa);
}
// TODO blocking/non-blocking??
int workerNum = this.conf.getIntVar(TajoConf.ConfVars.WORKER_SERVICE_RPC_SERVER_WORKER_THREAD_NUM);
this.rpcServer = new BlockingRpcServer(QueryMasterClientProtocol.class, serviceHandler, initIsa, workerNum);
this.rpcServer.start();
this.bindAddr = NetUtils.getConnectAddress(rpcServer.getListenAddress());
this.addr = bindAddr.getHostName() + ":" + bindAddr.getPort();
this.port = bindAddr.getPort();
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
// Get the master address
LOG.info(TajoWorkerClientService.class.getSimpleName() + " is bind to " + addr);
super.init(conf);
}
@Override
public void start() {
super.start();
}
@Override
public void stop() {
LOG.info("TajoWorkerClientService stopping");
if(rpcServer != null) {
rpcServer.shutdown();
}
LOG.info("TajoWorkerClientService stopped");
super.stop();
}
public InetSocketAddress getBindAddr() {
return bindAddr;
}
public class TajoWorkerClientProtocolServiceHandler
implements QueryMasterClientProtocol.QueryMasterClientProtocolService.BlockingInterface {
@Override
public PrimitiveProtos.BoolProto updateSessionVariables(
RpcController controller,
ClientProtos.UpdateSessionVariableRequest request) throws ServiceException {
return null;
}
@Override
public ClientProtos.GetQueryResultResponse getQueryResult(
RpcController controller,
ClientProtos.GetQueryResultRequest request) throws ServiceException {
QueryId queryId = new QueryId(request.getQueryId());
Query query = workerContext.getQueryMaster().getQueryMasterTask(queryId, true).getQuery();
ClientProtos.GetQueryResultResponse.Builder builder = ClientProtos.GetQueryResultResponse.newBuilder();
try {
builder.setTajoUserName(UserGroupInformation.getCurrentUser().getUserName());
} catch (IOException e) {
LOG.warn("Can't get current user name");
}
if(query == null) {
builder.setErrorMessage("No Query for " + queryId);
} else {
switch (query.getState()) {
case QUERY_SUCCEEDED:
builder.setTableDesc(query.getResultDesc().getProto());
break;
case QUERY_FAILED:
case QUERY_ERROR:
builder.setErrorMessage("Query " + queryId + " is failed");
default:
builder.setErrorMessage("Query " + queryId + " is still running");
}
}
return builder.build();
}
@Override
public ClientProtos.GetQueryStatusResponse getQueryStatus(
RpcController controller,
ClientProtos.GetQueryStatusRequest request) throws ServiceException {
ClientProtos.GetQueryStatusResponse.Builder builder
= ClientProtos.GetQueryStatusResponse.newBuilder();
QueryId queryId = new QueryId(request.getQueryId());
builder.setQueryId(request.getQueryId());
if (queryId.equals(QueryIdFactory.NULL_QUERY_ID)) {
builder.setResultCode(ClientProtos.ResultCode.OK);
builder.setState(TajoProtos.QueryState.QUERY_SUCCEEDED);
} else {
QueryMasterTask queryMasterTask = workerContext.getQueryMaster().getQueryMasterTask(queryId);
builder.setResultCode(ClientProtos.ResultCode.OK);
builder.setQueryMasterHost(bindAddr.getHostName());
builder.setQueryMasterPort(bindAddr.getPort());
if (queryMasterTask == null) {
queryMasterTask = workerContext.getQueryMaster().getQueryMasterTask(queryId, true);
}
if (queryMasterTask == null) {
builder.setState(TajoProtos.QueryState.QUERY_NOT_ASSIGNED);
return builder.build();
}
builder.setHasResult(
!(queryMasterTask.getQueryTaskContext().getQueryContext().isCreateTable() ||
queryMasterTask.getQueryTaskContext().getQueryContext().isInsert())
);
queryMasterTask.touchSessionTime();
Query query = queryMasterTask.getQuery();
if (query != null) {
builder.setState(query.getState());
builder.setProgress(query.getProgress());
builder.setSubmitTime(query.getAppSubmitTime());
if (query.getState() == TajoProtos.QueryState.QUERY_SUCCEEDED) {
builder.setFinishTime(query.getFinishTime());
} else {
builder.setFinishTime(System.currentTimeMillis());
}
} else {
builder.setState(queryMasterTask.getState());
builder.setErrorMessage(queryMasterTask.getErrorMessage());
}
}
return builder.build();
}
@Override
public PrimitiveProtos.BoolProto closeQuery (
RpcController controller,
TajoIdProtos.QueryIdProto request) throws ServiceException {
final QueryId queryId = new QueryId(request);
LOG.info("Stop Query:" + queryId);
return BOOL_TRUE;
}
}
}