/** * 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.catalog; import com.google.common.base.Objects; 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.yarn.service.AbstractService; import org.apache.tajo.TajoConstants; import org.apache.tajo.annotation.ThreadSafe; import org.apache.tajo.catalog.CatalogProtocol.CatalogProtocolService; import org.apache.tajo.catalog.exception.*; import org.apache.tajo.catalog.proto.CatalogProtos.*; import org.apache.tajo.catalog.store.CatalogStore; import org.apache.tajo.catalog.store.DerbyStore; import org.apache.tajo.common.TajoDataTypes; import org.apache.tajo.common.TajoDataTypes.DataType; import org.apache.tajo.conf.TajoConf; import org.apache.tajo.conf.TajoConf.ConfVars; import org.apache.tajo.rpc.BlockingRpcServer; import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos.BoolProto; import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos.NullProto; import org.apache.tajo.rpc.protocolrecords.PrimitiveProtos.StringProto; import org.apache.tajo.util.NetUtils; import org.apache.tajo.util.ProtoUtil; import org.apache.tajo.util.TUtil; import java.io.IOException; import java.lang.reflect.Constructor; import java.net.InetSocketAddress; import java.net.URI; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantReadWriteLock; import static org.apache.tajo.catalog.proto.CatalogProtos.AlterTablespaceProto.AlterTablespaceCommand; import static org.apache.tajo.catalog.proto.CatalogProtos.FunctionType.*; import static org.apache.tajo.rpc.protocolrecords.PrimitiveProtos.StringListProto; /** * This class provides the catalog service. The catalog service enables clients * to register, unregister and access information about tables, functions, and * cluster information. */ @ThreadSafe public class CatalogServer extends AbstractService { private final static String DEFAULT_NAMESPACE = "public"; private final static Log LOG = LogFactory.getLog(CatalogServer.class); private TajoConf conf; private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private final Lock rlock = lock.readLock(); private final Lock wlock = lock.writeLock(); private CatalogStore store; private Map<String, List<FunctionDescProto>> functions = new ConcurrentHashMap<String, List<FunctionDescProto>>(); // RPC variables private BlockingRpcServer rpcServer; private InetSocketAddress bindAddress; private String bindAddressStr; final CatalogProtocolHandler handler; // Server status variables private volatile boolean stopped = false; @SuppressWarnings("unused") private volatile boolean isOnline = false; private static BoolProto BOOL_TRUE = BoolProto.newBuilder(). setValue(true).build(); private static BoolProto BOOL_FALSE = BoolProto.newBuilder(). setValue(false).build(); private List<FunctionDesc> builtingFuncs; public CatalogServer() throws IOException { super(CatalogServer.class.getName()); this.handler = new CatalogProtocolHandler(); this.builtingFuncs = new ArrayList<FunctionDesc>(); } public CatalogServer(List<FunctionDesc> sqlFuncs) throws IOException { this(); this.builtingFuncs = sqlFuncs; } public void reloadBuiltinFunctions(List<FunctionDesc> builtingFuncs) throws ServiceException { this.builtingFuncs = builtingFuncs; initBuiltinFunctions(builtingFuncs); } @Override public void init(Configuration conf) { Constructor<?> cons; try { if (conf instanceof TajoConf) { this.conf = (TajoConf) conf; } else { throw new CatalogException("conf must be a TajoConf instance"); } Class<?> storeClass = this.conf.getClass(CatalogConstants.STORE_CLASS, DerbyStore.class); LOG.info("Catalog Store Class: " + storeClass.getCanonicalName()); cons = storeClass. getConstructor(new Class [] {Configuration.class}); this.store = (CatalogStore) cons.newInstance(this.conf); initBuiltinFunctions(builtingFuncs); } catch (Throwable t) { LOG.error("CatalogServer initialization failed", t); throw new CatalogException(t); } super.init(conf); } public TajoConf getConf() { return conf; } public String getStoreClassName() { return store.getClass().getCanonicalName(); } public String getCatalogServerName() { String catalogUri = null; if(conf.get(CatalogConstants.DEPRECATED_CATALOG_URI) != null) { LOG.warn("Configuration parameter " + CatalogConstants.DEPRECATED_CATALOG_URI + " " + "is deprecated. Use " + CatalogConstants.CATALOG_URI + " instead."); catalogUri = conf.get(CatalogConstants.DEPRECATED_CATALOG_URI); } else { catalogUri = conf.get(CatalogConstants.CATALOG_URI); } return bindAddressStr + ", store=" + this.store.getClass().getSimpleName() + ", catalogUri=" + catalogUri; } private void initBuiltinFunctions(List<FunctionDesc> functions) throws ServiceException { for (FunctionDesc desc : functions) { handler.createFunction(null, desc.getProto()); } } public void start() { String serverAddr = conf.getVar(ConfVars.CATALOG_ADDRESS); InetSocketAddress initIsa = NetUtils.createSocketAddr(serverAddr); int workerNum = conf.getIntVar(ConfVars.CATALOG_RPC_SERVER_WORKER_THREAD_NUM); try { this.rpcServer = new BlockingRpcServer(CatalogProtocol.class, handler, initIsa, workerNum); this.rpcServer.start(); this.bindAddress = NetUtils.getConnectAddress(this.rpcServer.getListenAddress()); this.bindAddressStr = NetUtils.normalizeInetSocketAddress(bindAddress); conf.setVar(ConfVars.CATALOG_ADDRESS, bindAddressStr); } catch (Exception e) { LOG.error("CatalogServer startup failed", e); throw new CatalogException(e); } LOG.info("Catalog Server startup (" + bindAddressStr + ")"); super.start(); } public void stop() { if (rpcServer != null) { this.rpcServer.shutdown(); } LOG.info("Catalog Server (" + bindAddressStr + ") shutdown"); try { store.close(); } catch (IOException ioe) { LOG.error(ioe.getMessage(), ioe); } super.stop(); } public CatalogProtocolHandler getHandler() { return this.handler; } public InetSocketAddress getBindAddress() { return this.bindAddress; } public class CatalogProtocolHandler implements CatalogProtocolService.BlockingInterface { @Override public BoolProto createTablespace(RpcController controller, CreateTablespaceRequest request) throws ServiceException { final String tablespaceName = request.getTablespaceName(); final String uri = request.getTablespaceUri(); wlock.lock(); try { if (store.existTablespace(tablespaceName)) { throw new AlreadyExistsDatabaseException(tablespaceName); } store.createTablespace(tablespaceName, uri); LOG.info(String.format("tablespace \"%s\" (%s) is created", tablespaceName, uri)); return ProtoUtil.TRUE; } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { wlock.unlock(); } } @Override public BoolProto dropTablespace(RpcController controller, StringProto request) throws ServiceException { String tablespaceName = request.getValue(); wlock.lock(); try { if (tablespaceName.equals(TajoConstants.DEFAULT_TABLESPACE_NAME)) { throw new CatalogException("default tablespace cannot be dropped."); } if (!store.existTablespace(tablespaceName)) { throw new NoSuchTablespaceException(tablespaceName); } store.dropTablespace(tablespaceName); return ProtoUtil.TRUE; } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { wlock.unlock(); } } @Override public BoolProto existTablespace(RpcController controller, StringProto request) throws ServiceException { String tablespaceName = request.getValue(); rlock.lock(); try { if (store.existTablespace(tablespaceName)) { return ProtoUtil.TRUE; } else { return ProtoUtil.FALSE; } } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { rlock.unlock(); } } @Override public StringListProto getAllTablespaceNames(RpcController controller, NullProto request) throws ServiceException { rlock.lock(); try { return ProtoUtil.convertStrings(store.getAllDatabaseNames()); } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { rlock.unlock(); } } @Override public TablespaceProto getTablespace(RpcController controller, StringProto request) throws ServiceException { rlock.lock(); try { return store.getTablespace(request.getValue()); } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { rlock.unlock(); } } @Override public BoolProto alterTablespace(RpcController controller, AlterTablespaceProto request) throws ServiceException { wlock.lock(); try { if (!store.existTablespace(request.getSpaceName())) { throw new NoSuchTablespaceException(request.getSpaceName()); } if (request.getCommandList().size() > 0) { for (AlterTablespaceCommand command : request.getCommandList()) { if (command.getType() == AlterTablespaceProto.AlterTablespaceType.LOCATION) { try { URI uri = URI.create(command.getLocation().getUri()); Preconditions.checkArgument(uri.getScheme() != null); } catch (Exception e) { throw new ServiceException("ALTER TABLESPACE's LOCATION must be a URI form (scheme:///.../), but " + command.getLocation().getUri()); } } } } store.alterTablespace(request); return ProtoUtil.TRUE; } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { wlock.unlock(); } } @Override public BoolProto createDatabase(RpcController controller, CreateDatabaseRequest request) throws ServiceException { String databaseName = request.getDatabaseName(); String tablespaceName = request.getTablespaceName(); wlock.lock(); try { if (store.existDatabase(databaseName)) { throw new AlreadyExistsDatabaseException(databaseName); } store.createDatabase(databaseName, tablespaceName); LOG.info(String.format("database \"%s\" is created", databaseName)); return ProtoUtil.TRUE; } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { wlock.unlock(); } } @Override public BoolProto alterTable(RpcController controller, AlterTableDescProto proto) throws ServiceException { wlock.lock(); try { String [] split = CatalogUtil.splitTableName(proto.getTableName()); if (!store.existTable(split[0], split[1])) { throw new NoSuchTableException(proto.getTableName()); } store.alterTable(proto); } catch (Exception e) { LOG.error(e.getMessage(), e); return BOOL_FALSE; } finally { wlock.unlock(); LOG.info("Table " + proto.getTableName() + " is altered in the catalog (" + bindAddressStr + ")"); } return BOOL_TRUE; } @Override public BoolProto dropDatabase(RpcController controller, StringProto request) throws ServiceException { String databaseName = request.getValue(); wlock.lock(); try { if (!store.existDatabase(databaseName)) { throw new NoSuchDatabaseException(databaseName); } store.dropDatabase(databaseName); return ProtoUtil.TRUE; } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { wlock.unlock(); } } @Override public BoolProto existDatabase(RpcController controller, StringProto request) throws ServiceException { String databaseName = request.getValue(); rlock.lock(); try { if (store.existDatabase(databaseName)) { return ProtoUtil.TRUE; } else { return ProtoUtil.FALSE; } } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { rlock.unlock(); } } @Override public StringListProto getAllDatabaseNames(RpcController controller, NullProto request) throws ServiceException { rlock.lock(); try { return ProtoUtil.convertStrings(store.getAllDatabaseNames()); } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { rlock.unlock(); } } @Override public TableDescProto getTableDesc(RpcController controller, TableIdentifierProto request) throws ServiceException { String databaseName = request.getDatabaseName(); String tableName = request.getTableName(); rlock.lock(); try { boolean contain; contain = store.existDatabase(databaseName); if (contain) { contain = store.existTable(databaseName, tableName); if (contain) { return store.getTable(databaseName, tableName); } else { throw new NoSuchTableException(tableName); } } else { throw new NoSuchDatabaseException(databaseName); } } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { rlock.unlock(); } } @Override public StringListProto getAllTableNames(RpcController controller, StringProto request) throws ServiceException { String databaseName = request.getValue(); rlock.lock(); try { if (store.existDatabase(databaseName)) { return ProtoUtil.convertStrings(store.getAllTableNames(databaseName)); } else { throw new NoSuchDatabaseException(databaseName); } } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { rlock.unlock(); } } @Override public GetFunctionsResponse getFunctions(RpcController controller, NullProto request) throws ServiceException { Iterator<List<FunctionDescProto>> iterator = functions.values().iterator(); GetFunctionsResponse.Builder builder = GetFunctionsResponse.newBuilder(); while (iterator.hasNext()) { builder.addAllFunctionDesc(iterator.next()); } return builder.build(); } @Override public BoolProto createTable(RpcController controller, TableDescProto request)throws ServiceException { String [] splitted = CatalogUtil.splitFQTableName(request.getTableName()); String databaseName = splitted[0]; String tableName = splitted[1]; wlock.lock(); try { boolean contain = store.existDatabase(databaseName); if (contain) { if (store.existTable(databaseName, tableName)) { throw new AlreadyExistsTableException(databaseName, tableName); } store.createTable(request); LOG.info(String.format("relation \"%s\" is added to the catalog (%s)", CatalogUtil.getCanonicalTableName(databaseName, tableName), bindAddressStr)); } else { throw new NoSuchDatabaseException(databaseName); } } catch (Exception e) { LOG.error(e.getMessage(), e); return ProtoUtil.FALSE; } finally { wlock.unlock(); } return ProtoUtil.TRUE; } @Override public BoolProto dropTable(RpcController controller, TableIdentifierProto request) throws ServiceException { String databaseName = request.getDatabaseName(); String tableName = request.getTableName(); wlock.lock(); try { boolean contain = store.existDatabase(databaseName); if (contain) { if (!store.existTable(databaseName, tableName)) { throw new NoSuchTableException(databaseName, tableName); } store.dropTable(databaseName, tableName); LOG.info(String.format("relation \"%s\" is deleted from the catalog (%s)", CatalogUtil.getCanonicalTableName(databaseName, tableName), bindAddressStr)); } else { throw new NoSuchDatabaseException(databaseName); } } catch (Exception e) { LOG.error(e.getMessage(), e); return BOOL_FALSE; } finally { wlock.unlock(); } return BOOL_TRUE; } @Override public BoolProto existsTable(RpcController controller, TableIdentifierProto request) throws ServiceException { String databaseName = request.getDatabaseName(); String tableName = request.getTableName(); rlock.lock(); try { boolean contain = store.existDatabase(databaseName); if (contain) { if (store.existTable(databaseName, tableName)) { return BOOL_TRUE; } else { return BOOL_FALSE; } } else { throw new NoSuchDatabaseException(databaseName); } } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { rlock.unlock(); } } @Override public PartitionMethodProto getPartitionMethodByTableName(RpcController controller, TableIdentifierProto request) throws ServiceException { String databaseName = request.getDatabaseName(); String tableName = request.getTableName(); rlock.lock(); try { boolean contain; contain = store.existDatabase(databaseName); if (contain) { contain = store.existTable(databaseName, tableName); if (contain) { if (store.existPartitionMethod(databaseName, tableName)) { return store.getPartitionMethod(databaseName, tableName); } else { throw new NoPartitionedTableException(databaseName, tableName); } } else { throw new NoSuchTableException(databaseName); } } else { throw new NoSuchDatabaseException(databaseName); } } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { rlock.unlock(); } } @Override public BoolProto existPartitionMethod(RpcController controller, TableIdentifierProto request) throws ServiceException { String databaseName = request.getDatabaseName(); String tableName = request.getTableName(); rlock.lock(); try { boolean contain; contain = store.existDatabase(databaseName); if (contain) { contain = store.existTable(databaseName, tableName); if (contain) { if (store.existPartitionMethod(databaseName, tableName)) { return ProtoUtil.TRUE; } else { return ProtoUtil.FALSE; } } else { throw new NoSuchTableException(databaseName); } } else { throw new NoSuchDatabaseException(databaseName); } } catch (Exception e) { LOG.error(e); throw new ServiceException(e); } finally { rlock.unlock(); } } @Override public BoolProto dropPartitionMethod(RpcController controller, TableIdentifierProto request) throws ServiceException { return ProtoUtil.TRUE; } @Override public BoolProto addPartitions(RpcController controller, PartitionsProto request) throws ServiceException { return ProtoUtil.TRUE; } @Override public BoolProto addPartition(RpcController controller, PartitionDescProto request) throws ServiceException { return ProtoUtil.TRUE; } @Override public PartitionDescProto getPartitionByPartitionName(RpcController controller, StringProto request) throws ServiceException { return null; } @Override public PartitionsProto getPartitionsByTableName(RpcController controller, StringProto request) throws ServiceException { return null; } @Override public PartitionsProto delAllPartitions(RpcController controller, StringProto request) throws ServiceException { return null; } @Override public BoolProto createIndex(RpcController controller, IndexDescProto indexDesc) throws ServiceException { rlock.lock(); try { if (store.existIndexByName( indexDesc.getTableIdentifier().getDatabaseName(), indexDesc.getIndexName())) { throw new AlreadyExistsIndexException(indexDesc.getIndexName()); } store.createIndex(indexDesc); } catch (Exception e) { LOG.error("ERROR : cannot add index " + indexDesc.getIndexName(), e); LOG.error(indexDesc); throw new ServiceException(e); } finally { rlock.unlock(); } return BOOL_TRUE; } @Override public BoolProto existIndexByName(RpcController controller, IndexNameProto request) throws ServiceException { String databaseName = request.getDatabaseName(); String indexName = request.getIndexName(); rlock.lock(); try { return store.existIndexByName(databaseName, indexName) ? ProtoUtil.TRUE : ProtoUtil.FALSE; } catch (Exception e) { LOG.error(e); return BoolProto.newBuilder().setValue(false).build(); } finally { rlock.unlock(); } } @Override public BoolProto existIndexByColumn(RpcController controller, GetIndexByColumnRequest request) throws ServiceException { TableIdentifierProto identifier = request.getTableIdentifier(); String databaseName = identifier.getDatabaseName(); String tableName = identifier.getTableName(); String columnName = request.getColumnName(); rlock.lock(); try { return store.existIndexByColumn(databaseName, tableName, columnName) ? ProtoUtil.TRUE : ProtoUtil.FALSE; } catch (Exception e) { LOG.error(e); return BoolProto.newBuilder().setValue(false).build(); } finally { rlock.unlock(); } } @Override public IndexDescProto getIndexByName(RpcController controller, IndexNameProto request) throws ServiceException { String databaseName = request.getDatabaseName(); String indexName = request.getIndexName(); rlock.lock(); try { if (!store.existIndexByName(databaseName, indexName)) { throw new NoSuchIndexException(databaseName, indexName); } return store.getIndexByName(databaseName, indexName); } catch (Exception e) { LOG.error("ERROR : cannot get index " + indexName, e); return null; } finally { rlock.unlock(); } } @Override public IndexDescProto getIndexByColumn(RpcController controller, GetIndexByColumnRequest request) throws ServiceException { TableIdentifierProto identifier = request.getTableIdentifier(); String databaseName = identifier.getDatabaseName(); String tableName = identifier.getTableName(); String columnName = request.getColumnName(); rlock.lock(); try { if (!store.existIndexByColumn(databaseName, tableName, columnName)) { throw new NoSuchIndexException(databaseName, columnName); } return store.getIndexByColumn(databaseName, tableName, columnName); } catch (Exception e) { LOG.error("ERROR : cannot get index for " + tableName + "." + columnName, e); return null; } finally { rlock.unlock(); } } @Override public BoolProto dropIndex(RpcController controller, IndexNameProto request) throws ServiceException { String databaseName = request.getDatabaseName(); String indexName = request.getIndexName(); wlock.lock(); try { if (!store.existIndexByName(databaseName, indexName)) { throw new NoSuchIndexException(indexName); } store.dropIndex(databaseName, indexName); } catch (Exception e) { LOG.error(e); } finally { wlock.unlock(); } return BOOL_TRUE; } public boolean checkIfBuiltin(FunctionType type) { return type == GENERAL || type == AGGREGATION || type == DISTINCT_AGGREGATION; } private boolean containFunction(String signature) { List<FunctionDescProto> found = findFunction(signature); return found != null && found.size() > 0; } private boolean containFunction(String signature, List<DataType> params) { return findFunction(signature, params) != null; } private boolean containFunction(String signature, FunctionType type, List<DataType> params) { return findFunction(signature, type, params, false) != null; } private List<FunctionDescProto> findFunction(String signature) { return functions.get(signature); } private FunctionDescProto findFunction(String signature, List<TajoDataTypes.DataType> params) { if (functions.containsKey(signature)) { for (FunctionDescProto existing : functions.get(signature)) { if (existing.getParameterTypesList() != null && existing.getParameterTypesList().equals(params)) { return existing; } } } /* * * FALL BACK to look for nearest match * WORKING BUT BAD WAY TO IMPLEMENT.I WOULD RATHER implement compareTo in FunctionDesc to keep them * in sorted order of param types LIKE INT1 SHOULD BE BEFORE INT2 should be before INT3 so on. * Due to possibility of multiple parameters and types the permutation and combinations are endless * to implement compareTo so decided to take the shortcut. * * */ for (FunctionDescProto existing : functions.get(signature)) { if (existing.getParameterTypesList() != null && CatalogUtil.isMatchedFunction(existing.getParameterTypesList(), params)) { return existing; } } return null; } private FunctionDescProto findFunction(String signature, FunctionType type, List<TajoDataTypes.DataType> params, boolean strictTypeCheck) { if (functions.containsKey(signature)) { if (strictTypeCheck) { for (FunctionDescProto existing : functions.get(signature)) { if (existing.getType() == type && existing.getParameterTypesList().equals(params)) { return existing; } } } else { for (FunctionDescProto existing : functions.get(signature)) { if (existing.getParameterTypesList() != null && CatalogUtil.isMatchedFunction(existing.getParameterTypesList(), params)) { return existing; } } } } return null; } private FunctionDescProto findFunctionStrictType(FunctionDescProto target, boolean strictTypeCheck) { return findFunction(target.getSignature(), target.getType(), target.getParameterTypesList(), strictTypeCheck); } @Override public BoolProto createFunction(RpcController controller, FunctionDescProto funcDesc) throws ServiceException { FunctionSignature signature = FunctionSignature.create(funcDesc); if (functions.containsKey(funcDesc.getSignature())) { FunctionDescProto found = findFunctionStrictType(funcDesc, true); if (found != null) { throw new AlreadyExistsFunctionException(signature.toString()); } } TUtil.putToNestedList(functions, funcDesc.getSignature(), funcDesc); if (LOG.isDebugEnabled()) { LOG.info("Function " + signature + " is registered."); } return BOOL_TRUE; } @Override public BoolProto dropFunction(RpcController controller, UnregisterFunctionRequest request) throws ServiceException { if (!containFunction(request.getSignature())) { throw new NoSuchFunctionException(request.getSignature(), new DataType[] {}); } functions.remove(request.getSignature()); LOG.info(request.getSignature() + " is dropped."); return BOOL_TRUE; } @Override public FunctionDescProto getFunctionMeta(RpcController controller, GetFunctionMetaRequest request) throws ServiceException { FunctionDescProto function = null; if (request.hasFunctionType()) { if (containFunction(request.getSignature(), request.getFunctionType(), request.getParameterTypesList())) { function = findFunction(request.getSignature(), request.getFunctionType(), request.getParameterTypesList(),true); } } else { function = findFunction(request.getSignature(), request.getParameterTypesList()); } if (function == null) { throw new NoSuchFunctionException(request.getSignature(), request.getParameterTypesList()); } else { return function; } } @Override public BoolProto containFunction(RpcController controller, ContainFunctionRequest request) throws ServiceException { boolean returnValue; if (request.hasFunctionType()) { returnValue = containFunction(request.getSignature(), request.getFunctionType(), request.getParameterTypesList()); } else { returnValue = containFunction(request.getSignature(), request.getParameterTypesList()); } return BoolProto.newBuilder().setValue(returnValue).build(); } } private static class FunctionSignature { private String signature; private FunctionType type; private DataType [] arguments; public FunctionSignature(String signature, FunctionType type, List<DataType> arguments) { this.signature = signature; this.type = type; this.arguments = arguments.toArray(new DataType[arguments.size()]); } public static FunctionSignature create(FunctionDescProto proto) { return new FunctionSignature(proto.getSignature(), proto.getType(), proto.getParameterTypesList()); } public static FunctionSignature create (GetFunctionMetaRequest proto) { return new FunctionSignature(proto.getSignature(), proto.getFunctionType(), proto.getParameterTypesList()); } public static FunctionSignature create(ContainFunctionRequest proto) { return new FunctionSignature(proto.getSignature(), proto.getFunctionType(), proto.getParameterTypesList()); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(signature); sb.append("#").append(type.name()); sb.append("("); int i = 0; for (DataType type : arguments) { sb.append(type.getType()); sb.append("[").append(type.getLength()).append("]"); if(i < arguments.length - 1) { sb.append(","); } i++; } sb.append(")"); return sb.toString(); } @Override public boolean equals(Object o) { if (this == o) { return true; } else if (o == null || getClass() != o.getClass()) { return false; } else { return (signature.equals(((FunctionSignature) o).signature) && type.equals(((FunctionSignature) o).type) && Arrays.equals(arguments, ((FunctionSignature) o).arguments)); } } @Override public int hashCode() { return Objects.hashCode(signature, type, Objects.hashCode(arguments)); } } public static void main(String[] args) throws Exception { TajoConf conf = new TajoConf(); CatalogServer catalog = new CatalogServer(new ArrayList<FunctionDesc>()); catalog.init(conf); catalog.start(); } }