| // 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.impala.catalog; |
| |
| import java.util.List; |
| import java.util.Set; |
| |
| import com.google.common.base.Preconditions; |
| import org.apache.hadoop.hive.metastore.IMetaStoreClient; |
| |
| import org.apache.impala.common.ImpalaException; |
| import org.apache.impala.common.JniUtil; |
| import org.apache.impala.thrift.TCatalogObjectType; |
| import org.apache.impala.thrift.TErrorCode; |
| import org.apache.impala.thrift.TGetPartialCatalogObjectRequest; |
| import org.apache.impala.thrift.TGetPartialCatalogObjectResponse; |
| import org.apache.impala.thrift.TStatus; |
| import org.apache.impala.thrift.TTable; |
| import org.apache.impala.thrift.TTableDescriptor; |
| import com.google.common.base.Joiner; |
| import com.google.common.base.Throwables; |
| import com.google.common.collect.Lists; |
| |
| /** |
| * Represents a table with incomplete metadata. The metadata may be incomplete because |
| * it has not yet been loaded or because of errors encountered during the loading |
| * process. |
| * |
| * NOTE: this is used on the catalogd (CatalogServiceCatalog) and on the "v1" |
| * ImpaladCatalog. LocalCatalog does not use this, and instead uses |
| * FailedLoadLocalTable to represent a failed table. |
| */ |
| public class IncompleteTable extends Table implements FeIncompleteTable { |
| // The cause for the incomplete metadata. If there is no cause given (cause_ = null), |
| // then this is assumed to be an uninitialized table (table that does not have |
| // its metadata loaded). |
| private ImpalaException cause_; |
| |
| private IncompleteTable(Db db, String name, |
| ImpalaException cause) { |
| super(null, db, name, null); |
| cause_ = cause; |
| } |
| |
| /** |
| * Returns the cause (ImpalaException) which led to this table's metadata being |
| * incomplete. |
| */ |
| @Override |
| public ImpalaException getCause() { return cause_; } |
| |
| /** |
| * See comment on cause_. |
| */ |
| @Override |
| public boolean isLoaded() { return cause_ != null; } |
| |
| @Override |
| public TCatalogObjectType getCatalogObjectType() { return TCatalogObjectType.TABLE; } |
| |
| @Override |
| public TTableDescriptor toThriftDescriptor(int tableId, Set<Long> referencedPartitions) { |
| throw new IllegalStateException(cause_); |
| } |
| |
| @Override |
| public void load(boolean reuseMetadata, IMetaStoreClient client, |
| org.apache.hadoop.hive.metastore.api.Table msTbl, String reason) |
| throws TableLoadingException { |
| if (cause_ instanceof TableLoadingException) { |
| throw (TableLoadingException) cause_; |
| } else { |
| throw new TableLoadingException("Table metadata incomplete: ", cause_); |
| } |
| } |
| |
| @Override |
| public TTable toThrift() { |
| TTable table = new TTable(db_.getName(), name_); |
| if (cause_ != null) { |
| table.setLoad_status(new TStatus(TErrorCode.INTERNAL_ERROR, |
| Lists.newArrayList(JniUtil.throwableToString(cause_), |
| JniUtil.throwableToStackTrace(cause_)))); |
| } |
| return table; |
| } |
| |
| @Override |
| protected void loadFromThrift(TTable thriftTable) throws TableLoadingException { |
| if (thriftTable.isSetLoad_status()) { |
| // Since the load status is set, it indicates the table is incomplete due to |
| // an error loading the table metadata. The error message in the load status |
| // should provide details on why. By convention, the final error message should |
| // be the remote (Catalog Server) call stack. This shouldn't be displayed to the |
| // user under normal circumstances, but needs to be recorded somewhere so append |
| // it to the call stack of the local TableLoadingException created here. |
| // TODO: Provide a mechanism (query option?) to optionally allow returning more |
| // detailed errors (including the full call stack(s)) to the user. |
| List<String> errorMsgs = thriftTable.getLoad_status().getError_msgs(); |
| String callStackStr = "<None available>"; |
| if (errorMsgs.size() > 1) callStackStr = errorMsgs.remove(errorMsgs.size() - 1); |
| |
| String errorMsg = Joiner.on("\n").join(errorMsgs); |
| // The errorMsg will always be prefixed with "ExceptionClassName: ". Since we treat |
| // all errors as TableLoadingExceptions, the prefix "TableLoadingException" is |
| // redundant and can be stripped out. |
| errorMsg = errorMsg.replaceFirst("^TableLoadingException: ", ""); |
| TableLoadingException loadingException = new TableLoadingException(errorMsg); |
| List<StackTraceElement> stackTrace = |
| Lists.newArrayList(loadingException.getStackTrace()); |
| stackTrace.add(new StackTraceElement("========", |
| "<Remote stack trace on catalogd>: " + callStackStr, "", -1)); |
| loadingException.setStackTrace( |
| stackTrace.toArray(new StackTraceElement[stackTrace.size()])); |
| this.cause_ = loadingException; |
| } |
| } |
| |
| public static IncompleteTable createUninitializedTable(Db db, String name) { |
| return new IncompleteTable(db, name, null); |
| } |
| |
| public static IncompleteTable createFailedMetadataLoadTable(Db db, String name, |
| ImpalaException e) { |
| return new IncompleteTable(db, name, e); |
| } |
| |
| @Override |
| public TGetPartialCatalogObjectResponse getPartialInfo( |
| TGetPartialCatalogObjectRequest req) throws TableLoadingException { |
| Preconditions.checkNotNull(cause_); |
| Throwables.propagateIfPossible(cause_, TableLoadingException.class); |
| throw new TableLoadingException(cause_.getMessage()); |
| } |
| } |