blob: be8ac977e8b8f0eef5f1f2e03e1996c3ffa8fd38 [file] [log] [blame]
// 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());
}
}