This is an automated email from the ASF dual-hosted git repository.

tarmstrong pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/impala.git

commit c561fcc9225312ac7b1b1df4fbab912ef8d8d905
Author: Todd Lipcon <t...@cloudera.com>
AuthorDate: Wed Jun 6 15:00:13 2018 -0700

    IMPALA-7135. Skeleton implementation of LocalCatalog
    
    This adds some of the high level classes for implementing the local
    catalog:
    
    - LocalCatalog is the top level implementation. The plan is to
      instantiate this once per query, so that no thread safety is required.
    
    - It loads metadata from a MetaProvider interface. The current
      implementation fetches directly from HMS and provides no caching. A
      future subtask will add a CachingMetaProvider implementation.
      Separating out caching will make it easier to experiment with
      different policies or storage mechanisms.
    
    - It instantiates LocalDb and LocalTable objects to implement FeDb and
      FeTable. These are mostly stubbed out except for the most basic
      functionality. Functionality will be filled in incrementally in
      further patches.
    
    Since it's not yet possible to hook this up to most of the existing
    tests, a very simple new unit test is included to cover the bits of
    functionality that are not stubbed out. I didn't concentrate on too much
    test coverage here, since once we've implemented more functionality we
    can switch over all of the existing tests to get coverage of the new
    implementation.
    
    Change-Id: Iab653371188b21c72f50ee1ec4e94950aa6fb9ee
    Reviewed-on: http://gerrit.cloudera.org:8080/10627
    Reviewed-by: Impala Public Jenkins <impala-public-jenk...@cloudera.com>
    Tested-by: Impala Public Jenkins <impala-public-jenk...@cloudera.com>
---
 .../java/org/apache/impala/catalog/Catalog.java    |   8 +-
 .../org/apache/impala/catalog/CatalogObject.java   |   3 +-
 .../main/java/org/apache/impala/catalog/FeDb.java  |   3 +-
 .../catalog/{CatalogObject.java => HasName.java}   |  26 +--
 .../impala/catalog/local/DirectMetaProvider.java   |  83 ++++++++
 .../apache/impala/catalog/local/LocalCatalog.java  | 212 +++++++++++++++++++++
 .../catalog/local/LocalCatalogException.java       |  34 ++++
 .../org/apache/impala/catalog/local/LocalDb.java   | 173 +++++++++++++++++
 .../apache/impala/catalog/local/LocalTable.java    | 160 ++++++++++++++++
 .../apache/impala/catalog/local/MetaProvider.java  |  48 +++++
 .../impala/catalog/local/LocalCatalogTest.java     |  76 ++++++++
 11 files changed, 800 insertions(+), 26 deletions(-)

diff --git a/fe/src/main/java/org/apache/impala/catalog/Catalog.java 
b/fe/src/main/java/org/apache/impala/catalog/Catalog.java
index 82b411a..7403bc2 100644
--- a/fe/src/main/java/org/apache/impala/catalog/Catalog.java
+++ b/fe/src/main/java/org/apache/impala/catalog/Catalog.java
@@ -332,7 +332,7 @@ public abstract class Catalog {
    * The results are sorted in String.CASE_INSENSITIVE_ORDER.
    * matcher must not be null.
    */
-  private List<String> filterStringsByPattern(Iterable<String> candidates,
+  public static List<String> filterStringsByPattern(Iterable<String> 
candidates,
       PatternMatcher matcher) {
     Preconditions.checkNotNull(matcher);
     List<String> filtered = Lists.newArrayList();
@@ -343,9 +343,9 @@ public abstract class Catalog {
     return filtered;
   }
 
-  private static class CatalogObjectOrder implements Comparator<CatalogObject> 
{
+  private static class CatalogObjectOrder implements Comparator<HasName> {
     @Override
-    public int compare(CatalogObject o1, CatalogObject o2) {
+    public int compare(HasName o1, HasName o2) {
       return String.CASE_INSENSITIVE_ORDER.compare(o1.getName(), o2.getName());
     }
   }
@@ -357,7 +357,7 @@ public abstract class Catalog {
    * The results are sorted in CATALOG_OBJECT_ORDER.
    * matcher must not be null.
    */
-  private <T extends CatalogObject> List<T> filterCatalogObjectsByPattern(
+  public static <T extends HasName> List<T> filterCatalogObjectsByPattern(
       Iterable<? extends T> candidates, PatternMatcher matcher) {
     Preconditions.checkNotNull(matcher);
     List<T> filtered = Lists.newArrayList();
diff --git a/fe/src/main/java/org/apache/impala/catalog/CatalogObject.java 
b/fe/src/main/java/org/apache/impala/catalog/CatalogObject.java
index cc4c495..34310c3 100644
--- a/fe/src/main/java/org/apache/impala/catalog/CatalogObject.java
+++ b/fe/src/main/java/org/apache/impala/catalog/CatalogObject.java
@@ -22,11 +22,12 @@ import org.apache.impala.thrift.TCatalogObjectType;
 /**
  * Interface that all catalog objects implement.
  */
-public interface CatalogObject {
+public interface CatalogObject extends HasName {
   // Returns the TCatalogObject type of this Catalog object.
   public TCatalogObjectType getCatalogObjectType();
 
   // Returns the unqualified object name.
+  @Override
   public String getName();
 
   // Returns the unique name of this catalog object.
diff --git a/fe/src/main/java/org/apache/impala/catalog/FeDb.java 
b/fe/src/main/java/org/apache/impala/catalog/FeDb.java
index 8de877f..111fbd0 100644
--- a/fe/src/main/java/org/apache/impala/catalog/FeDb.java
+++ b/fe/src/main/java/org/apache/impala/catalog/FeDb.java
@@ -26,10 +26,11 @@ import org.apache.impala.util.PatternMatcher;
 /**
  * Frontend interface for interacting with a database.
  */
-public interface FeDb {
+public interface FeDb extends HasName {
   /**
    * @return the name of the database
    */
+  @Override
   String getName();
 
   /**
diff --git a/fe/src/main/java/org/apache/impala/catalog/CatalogObject.java 
b/fe/src/main/java/org/apache/impala/catalog/HasName.java
similarity index 56%
copy from fe/src/main/java/org/apache/impala/catalog/CatalogObject.java
copy to fe/src/main/java/org/apache/impala/catalog/HasName.java
index cc4c495..594d541 100644
--- a/fe/src/main/java/org/apache/impala/catalog/CatalogObject.java
+++ b/fe/src/main/java/org/apache/impala/catalog/HasName.java
@@ -17,27 +17,13 @@
 
 package org.apache.impala.catalog;
 
-import org.apache.impala.thrift.TCatalogObjectType;
-
 /**
- * Interface that all catalog objects implement.
+ * Interface for named catalog objects, used for sorting and pattern
+ * matching.
  */
-public interface CatalogObject {
-  // Returns the TCatalogObject type of this Catalog object.
-  public TCatalogObjectType getCatalogObjectType();
-
-  // Returns the unqualified object name.
+public interface HasName {
+  /**
+   * @return the unqualified name of the object
+   */
   public String getName();
-
-  // Returns the unique name of this catalog object.
-  public String getUniqueName();
-
-  // Returns the version of this catalog object.
-  public long getCatalogVersion();
-
-  // Sets the version of this catalog object.
-  public void setCatalogVersion(long newVersion);
-
-  // Returns true if this CatalogObject has had its metadata loaded, false 
otherwise.
-  public boolean isLoaded();
 }
diff --git 
a/fe/src/main/java/org/apache/impala/catalog/local/DirectMetaProvider.java 
b/fe/src/main/java/org/apache/impala/catalog/local/DirectMetaProvider.java
new file mode 100644
index 0000000..0867091
--- /dev/null
+++ b/fe/src/main/java/org/apache/impala/catalog/local/DirectMetaProvider.java
@@ -0,0 +1,83 @@
+// 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.local;
+
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.hadoop.hive.metastore.api.MetaException;
+import org.apache.hadoop.hive.metastore.api.NoSuchObjectException;
+import org.apache.hadoop.hive.metastore.api.Table;
+import org.apache.hadoop.hive.metastore.api.UnknownDBException;
+import org.apache.impala.catalog.MetaStoreClientPool;
+import org.apache.impala.catalog.MetaStoreClientPool.MetaStoreClient;
+import org.apache.impala.service.BackendConfig;
+import org.apache.impala.thrift.TBackendGflags;
+import org.apache.thrift.TException;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Metadata provider which calls out directly to the source systems
+ * (filesystem, HMS, etc) with no caching.
+ */
+class DirectMetaProvider implements MetaProvider {
+  private static MetaStoreClientPool msClientPool_;
+
+  DirectMetaProvider() {
+    initMsClientPool();
+  }
+
+  private static synchronized void initMsClientPool() {
+    // Lazy-init the metastore client pool based on the backend configuration.
+    // TODO(todd): this should probably be a process-wide singleton.
+    if (msClientPool_ == null) {
+      TBackendGflags cfg = BackendConfig.INSTANCE.getBackendCfg();
+      msClientPool_ = new MetaStoreClientPool(cfg.num_metadata_loading_threads,
+          cfg.initial_hms_cnxn_timeout_s);
+    }
+  }
+
+  @Override
+  public ImmutableList<String> loadDbList() throws TException {
+    try (MetaStoreClient c = msClientPool_.getClient()) {
+      return ImmutableList.copyOf(c.getHiveClient().getAllDatabases());
+    }
+  }
+
+  @Override
+  public Database loadDb(String dbName) throws TException {
+    try (MetaStoreClient c = msClientPool_.getClient()) {
+      return c.getHiveClient().getDatabase(dbName);
+    }
+  }
+
+  @Override
+  public ImmutableList<String> loadTableNames(String dbName)
+      throws MetaException, UnknownDBException, TException {
+    try (MetaStoreClient c = msClientPool_.getClient()) {
+      return ImmutableList.copyOf(c.getHiveClient().getAllTables(dbName));
+    }
+  }
+
+  @Override
+  public Table loadTable(String dbName, String tableName)
+      throws MetaException, NoSuchObjectException, TException {
+    try (MetaStoreClient c = msClientPool_.getClient()) {
+      return c.getHiveClient().getTable(dbName, tableName);
+    }
+  }
+}
diff --git a/fe/src/main/java/org/apache/impala/catalog/local/LocalCatalog.java 
b/fe/src/main/java/org/apache/impala/catalog/local/LocalCatalog.java
new file mode 100644
index 0000000..beac563
--- /dev/null
+++ b/fe/src/main/java/org/apache/impala/catalog/local/LocalCatalog.java
@@ -0,0 +1,212 @@
+// 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.local;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hive.metastore.api.Table;
+import org.apache.impala.analysis.TableName;
+import org.apache.impala.catalog.AuthorizationPolicy;
+import org.apache.impala.catalog.BuiltinsDb;
+import org.apache.impala.catalog.Catalog;
+import org.apache.impala.catalog.CatalogException;
+import org.apache.impala.catalog.DatabaseNotFoundException;
+import org.apache.impala.catalog.Db;
+import org.apache.impala.catalog.FeCatalog;
+import org.apache.impala.catalog.FeDataSource;
+import org.apache.impala.catalog.FeDb;
+import org.apache.impala.catalog.FeFsPartition;
+import org.apache.impala.catalog.FeTable;
+import org.apache.impala.catalog.Function;
+import org.apache.impala.catalog.Function.CompareMode;
+import org.apache.impala.catalog.HdfsCachePool;
+import org.apache.impala.catalog.ImpaladCatalog;
+import org.apache.impala.thrift.TCatalogObject;
+import org.apache.impala.thrift.TPartitionKeyValue;
+import org.apache.impala.thrift.TUniqueId;
+import org.apache.impala.util.PatternMatcher;
+import org.apache.thrift.TException;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Maps;
+
+/**
+ * Implementation of FeCatalog which runs within the impalad and fetches 
metadata
+ * on-demand using a {@link MetaProvider} instance.
+ *
+ * This class should be instantiated once per query. As the catalog is queried,
+ * it lazy-loads those pieces of metadata into the instance and instantiates
+ * appropriate catalog object implementations. This provides caching within a
+ * query -- multiple calls to fetch a given database, table, etc, will return
+ * the same instance. However, this class does not inherently provide any 
caching
+ * outside the scope of a single query: that caching should be performed at the
+ * level of the MetaProvider.
+ *
+ * This class is not thread-safe, nor are any of the catalog object 
implementations
+ * returned from its methods.
+ */
+public class LocalCatalog implements FeCatalog {
+  private final MetaProvider metaProvider_;
+  private Map<String, FeDb> dbs_ = Maps.newHashMap();
+  private static final Db builtinsDb_ = new 
BuiltinsDb(ImpaladCatalog.BUILTINS_DB);
+
+  public LocalCatalog(MetaProvider metaProvider) {
+    metaProvider_ = Preconditions.checkNotNull(metaProvider);
+  }
+
+  @Override
+  public List<? extends FeDb> getDbs(PatternMatcher matcher) {
+    loadDbs();
+    return Catalog.filterCatalogObjectsByPattern(dbs_.values(), matcher);
+  }
+
+  private void loadDbs() {
+    if (!dbs_.isEmpty()) return;
+    Map<String, FeDb> dbs = Maps.newHashMap();
+    List<String> names;
+    try {
+      names = metaProvider_.loadDbList();
+    } catch (TException e) {
+      throw new LocalCatalogException("Unable to load database names", e);
+    }
+    for (String dbName : names) {
+      dbName = dbName.toLowerCase();
+      if (dbs_.containsKey(dbName)) {
+        dbs.put(dbName, dbs_.get(dbName));
+      } else {
+        dbs.put(dbName, new LocalDb(this, dbName));
+      }
+    }
+    dbs.put(builtinsDb_.getName(), builtinsDb_);
+    dbs_ = dbs;
+  }
+
+
+  @Override
+  public List<String> getTableNames(String dbName, PatternMatcher matcher)
+      throws DatabaseNotFoundException {
+    return 
Catalog.filterStringsByPattern(getDbOrThrow(dbName).getAllTableNames(), 
matcher);
+  }
+
+  @Override
+  public FeTable getTable(String dbName, String tableName)
+      throws DatabaseNotFoundException {
+    return getDbOrThrow(dbName).getTable(tableName);
+  }
+
+  @Override
+  public TCatalogObject getTCatalogObject(TCatalogObject objectDesc)
+      throws CatalogException {
+    // TODO(todd): this probably makes the /catalog page not load with an 
error.
+    // We should probably disable that page in local-catalog mode.
+    throw new UnsupportedOperationException("LocalCatalog.getTCatalogObject");
+  }
+
+  @Override
+  public FeDb getDb(String db) {
+    loadDbs();
+    return dbs_.get(db);
+  }
+
+  private FeDb getDbOrThrow(String dbName) throws DatabaseNotFoundException {
+    Preconditions.checkNotNull(dbName);
+    FeDb db = getDb(dbName);
+    if (db == null) {
+      throw new DatabaseNotFoundException("Database '" + dbName + "' not 
found");
+    }
+    return db;
+  }
+
+  @Override
+  public FeFsPartition getHdfsPartition(
+      String db, String tbl, List<TPartitionKeyValue> partition_spec)
+      throws CatalogException {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public List<? extends FeDataSource> getDataSources(
+      PatternMatcher createHivePatternMatcher) {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public FeDataSource getDataSource(String dataSourceName) {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public Function getFunction(Function desc, CompareMode mode) {
+    FeDb db = getDb(desc.dbName());
+    if (db == null) return null;
+    return db.getFunction(desc, mode);
+  }
+
+  @Override
+  public HdfsCachePool getHdfsCachePool(String poolName) {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public void prioritizeLoad(Set<TableName> tableNames) {
+    // No-op for local catalog.
+  }
+
+  @Override
+  public void waitForCatalogUpdate(long timeoutMs) {
+    // No-op for local catalog.
+  }
+
+  @Override
+  public Path getTablePath(Table msTbl) {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public TUniqueId getCatalogServiceId() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public AuthorizationPolicy getAuthPolicy() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public String getDefaultKuduMasterHosts() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public boolean isReady() {
+    // We are always ready.
+    return true;
+  }
+
+  @Override
+  public void setIsReady(boolean isReady) {
+    // No-op for local catalog.
+  }
+
+  MetaProvider getMetaProvider() {
+    return metaProvider_;
+  }
+}
\ No newline at end of file
diff --git 
a/fe/src/main/java/org/apache/impala/catalog/local/LocalCatalogException.java 
b/fe/src/main/java/org/apache/impala/catalog/local/LocalCatalogException.java
new file mode 100644
index 0000000..59e0be4
--- /dev/null
+++ 
b/fe/src/main/java/org/apache/impala/catalog/local/LocalCatalogException.java
@@ -0,0 +1,34 @@
+// 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.local;
+
+
+/**
+ * Exception indicating an error loading catalog information into
+ * the impalad.
+ *
+ * TODO(todd): should this be changed to a checked exception? The frontend
+ * interfaces don't have appropriate "throws" clauses to do so without some
+ * significant virality.
+ */
+public class LocalCatalogException extends RuntimeException {
+  private static final long serialVersionUID = -429271377417249918L;
+
+  public LocalCatalogException(String msg, Throwable cause) {
+    super(msg, cause);
+  }
+}
diff --git a/fe/src/main/java/org/apache/impala/catalog/local/LocalDb.java 
b/fe/src/main/java/org/apache/impala/catalog/local/LocalDb.java
new file mode 100644
index 0000000..1bbe9b8
--- /dev/null
+++ b/fe/src/main/java/org/apache/impala/catalog/local/LocalDb.java
@@ -0,0 +1,173 @@
+// 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.local;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.impala.catalog.FeDb;
+import org.apache.impala.catalog.FeTable;
+import org.apache.impala.catalog.Function;
+import org.apache.impala.catalog.Function.CompareMode;
+import org.apache.impala.thrift.TDatabase;
+import org.apache.impala.thrift.TFunctionCategory;
+import org.apache.impala.util.PatternMatcher;
+import org.apache.thrift.TException;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Maps;
+
+/**
+ * Database instance loaded from {@link LocalCatalog}.
+ *
+ * This class is not thread-safe. A new instance is created for
+ * each catalog instance.
+ */
+class LocalDb implements FeDb {
+  private final LocalCatalog catalog_;
+  /** The lower-case name of the database. */
+  private final String name_;
+  private Database msDb_;
+
+  /**
+   * Map from lower-cased table name to table object. Values will be
+   * null for tables which have not yet been loaded.
+   */
+  private Map<String, LocalTable> tables_;
+
+  public LocalDb(LocalCatalog catalog, String dbName) {
+    Preconditions.checkNotNull(catalog);
+    Preconditions.checkNotNull(dbName);
+    Preconditions.checkArgument(dbName.toLowerCase().equals(dbName));
+    this.catalog_ = catalog;
+    this.name_ = dbName;
+  }
+
+  @Override
+  public String getName() {
+    return name_;
+  }
+
+  @Override
+  public Database getMetaStoreDb() {
+    if (msDb_ == null) {
+      try {
+        msDb_ = catalog_.getMetaProvider().loadDb(name_);
+      } catch (TException e) {
+        throw new LocalCatalogException(String.format(
+            "Could not load database '%s' from HMS", name_), e);
+      }
+    }
+    return msDb_;
+  }
+
+  @Override
+  public boolean containsTable(String tableName) {
+    loadTableNames();
+    return tables_.containsKey(tableName.toLowerCase());
+  }
+
+  @Override
+  public FeTable getTable(String tblName) {
+    Preconditions.checkNotNull(tblName);
+    Preconditions.checkArgument(tblName.toLowerCase().equals(tblName));
+    loadTableNames();
+    if (!tables_.containsKey(tblName)) {
+      // Table doesn't exist.
+      return null;
+    }
+    LocalTable tbl = tables_.get(tblName);
+    if (tbl == null) {
+      // The table exists but hasn't been loaded yet.
+      tbl = LocalTable.load(this, tblName);
+      tables_.put(tblName, tbl);
+    }
+    return tbl;
+  }
+
+  @Override
+  public List<String> getAllTableNames() {
+    loadTableNames();
+    return ImmutableList.copyOf(tables_.keySet());
+  }
+
+  /**
+   * Populate the 'tables_' map if it is not already populated.
+   *
+   * The map is populated with appropriate keys but null values which
+   * will be replaced on-demand.
+   */
+  private void loadTableNames() {
+    if (tables_ != null) return;
+    Map<String, LocalTable> newMap = Maps.newHashMap();
+    try {
+      List<String> names = catalog_.getMetaProvider().loadTableNames(name_);
+      for (String tableName : names) {
+        newMap.put(tableName.toLowerCase(), null);
+      }
+    } catch (TException e) {
+      throw new LocalCatalogException(String.format(
+          "Could not load table names for database '%s' from HMS", name_), e);
+    }
+    tables_ = newMap;
+  }
+
+  @Override
+  public boolean isSystemDb() {
+    return false;
+  }
+
+  @Override
+  public Function getFunction(Function desc, CompareMode mode) {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public List<Function> getFunctions(String functionName) {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public List<Function> getFunctions(
+      TFunctionCategory category, String function) {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public List<Function> getFunctions(
+      TFunctionCategory category, PatternMatcher patternMatcher) {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public int numFunctions() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public boolean containsFunction(String function) {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public TDatabase toThrift() {
+    throw new UnsupportedOperationException("TODO");
+  }
+}
diff --git a/fe/src/main/java/org/apache/impala/catalog/local/LocalTable.java 
b/fe/src/main/java/org/apache/impala/catalog/local/LocalTable.java
new file mode 100644
index 0000000..58c0580
--- /dev/null
+++ b/fe/src/main/java/org/apache/impala/catalog/local/LocalTable.java
@@ -0,0 +1,160 @@
+// 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.local;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.hadoop.hive.metastore.api.Table;
+import org.apache.impala.analysis.TableName;
+import org.apache.impala.catalog.ArrayType;
+import org.apache.impala.catalog.Column;
+import org.apache.impala.catalog.FeDb;
+import org.apache.impala.catalog.FeTable;
+import org.apache.impala.thrift.TCatalogObjectType;
+import org.apache.impala.thrift.TTableDescriptor;
+import org.apache.impala.thrift.TTableStats;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Table instance loaded from {@link LocalCatalog}.
+ *
+ * This class is not thread-safe. A new instance is created for
+ * each catalog instance.
+ */
+class LocalTable implements FeTable {
+  private final LocalDb db_;
+  /** The lower-case name of the table. */
+  private final String name_;
+
+  public static LocalTable load(LocalDb db, String tblName) {
+    // TODO: change this function to instantiate the appropriate
+    // subclass based on the table type (eg view, hbase table, etc)
+    return new LocalTable(db, tblName);
+  }
+
+  public LocalTable(LocalDb db, String tblName) {
+    Preconditions.checkNotNull(db);
+    Preconditions.checkNotNull(tblName);
+    Preconditions.checkArgument(tblName.toLowerCase().equals(tblName));
+    this.db_ = db;
+    this.name_ = tblName;
+  }
+
+  @Override
+  public boolean isLoaded() {
+    return true;
+  }
+
+  @Override
+  public Table getMetaStoreTable() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public String getStorageHandlerClassName() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public TCatalogObjectType getCatalogObjectType() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public String getName() {
+    return name_;
+  }
+
+  @Override
+  public String getFullName() {
+    return db_.getName() + "." + name_;
+  }
+
+  @Override
+  public TableName getTableName() {
+    return new TableName(db_.getName(), name_);
+  }
+
+  @Override
+  public ArrayList<Column> getColumns() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public List<Column> getColumnsInHiveOrder() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public List<String> getColumnNames() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public List<Column> getClusteringColumns() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public List<Column> getNonClusteringColumns() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public int getNumClusteringCols() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public boolean isClusteringColumn(Column c) {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public Column getColumn(String name) {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public ArrayType getType() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public FeDb getDb() {
+    return db_;
+  }
+
+  @Override
+  public long getNumRows() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public TTableStats getTTableStats() {
+    throw new UnsupportedOperationException("TODO");
+  }
+
+  @Override
+  public TTableDescriptor toThriftDescriptor(int tableId, Set<Long> 
referencedPartitions) {
+    throw new UnsupportedOperationException("TODO");
+  }
+}
diff --git a/fe/src/main/java/org/apache/impala/catalog/local/MetaProvider.java 
b/fe/src/main/java/org/apache/impala/catalog/local/MetaProvider.java
new file mode 100644
index 0000000..cd8d3b9
--- /dev/null
+++ b/fe/src/main/java/org/apache/impala/catalog/local/MetaProvider.java
@@ -0,0 +1,48 @@
+// 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.local;
+
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.hadoop.hive.metastore.api.MetaException;
+import org.apache.hadoop.hive.metastore.api.NoSuchObjectException;
+import org.apache.hadoop.hive.metastore.api.Table;
+import org.apache.hadoop.hive.metastore.api.UnknownDBException;
+import org.apache.thrift.TException;
+
+import com.google.common.collect.ImmutableList;
+
+/**
+ * Interface for loading metadata. See {@link LocalCatalog} for an example.
+ *
+ * Implementations may directly access the metadata from the source systems
+ * or may include caching, etc.
+ *
+ * TODO(IMPALA-7127): expand this to include file metadata, sentry metadata,
+ * etc.
+ */
+interface MetaProvider {
+  ImmutableList<String> loadDbList() throws TException;
+
+  Database loadDb(String dbName) throws TException;
+
+  ImmutableList<String> loadTableNames(String dbName)
+      throws MetaException, UnknownDBException, TException;
+
+  Table loadTable(String dbName, String tableName)
+      throws NoSuchObjectException, MetaException, TException;
+}
diff --git 
a/fe/src/test/java/org/apache/impala/catalog/local/LocalCatalogTest.java 
b/fe/src/test/java/org/apache/impala/catalog/local/LocalCatalogTest.java
new file mode 100644
index 0000000..52ff255
--- /dev/null
+++ b/fe/src/test/java/org/apache/impala/catalog/local/LocalCatalogTest.java
@@ -0,0 +1,76 @@
+// 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.local;
+
+import static org.junit.Assert.*;
+
+import java.util.Set;
+
+import org.apache.impala.catalog.FeDb;
+import org.apache.impala.catalog.FeTable;
+import org.apache.impala.util.PatternMatcher;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+
+public class LocalCatalogTest {
+
+  private LocalCatalog catalog_;
+
+  @Before
+  public void setupCatalog() {
+    catalog_ = new LocalCatalog(new DirectMetaProvider());
+  }
+
+  @Test
+  public void testDbs() throws Exception {
+    FeDb functionalDb = catalog_.getDb("functional");
+    assertNotNull(functionalDb);
+    FeDb functionalSeqDb = catalog_.getDb("functional_seq");
+    assertNotNull(functionalSeqDb);
+
+    Set<FeDb> dbs = ImmutableSet.copyOf(
+        catalog_.getDbs(PatternMatcher.MATCHER_MATCH_ALL));
+    assertTrue(dbs.contains(functionalDb));
+    assertTrue(dbs.contains(functionalSeqDb));
+
+    dbs = ImmutableSet.copyOf(
+        catalog_.getDbs(PatternMatcher.createHivePatternMatcher("*_seq")));
+    assertFalse(dbs.contains(functionalDb));
+    assertTrue(dbs.contains(functionalSeqDb));
+  }
+
+  @Test
+  public void testTables() throws Exception {
+    Set<String> names = ImmutableSet.copyOf(catalog_.getTableNames(
+        "functional", PatternMatcher.MATCHER_MATCH_ALL));
+    assertTrue(names.contains("alltypes"));
+
+    FeDb db = catalog_.getDb("functional");
+    assertNotNull(db);
+    FeTable t = catalog_.getTable("functional", "alltypes");
+    assertNotNull(t);
+    assertSame(t, db.getTable("alltypes"));
+    assertSame(db, t.getDb());
+    assertEquals("alltypes", t.getName());
+    assertEquals("functional", t.getDb().getName());
+    assertEquals("functional.alltypes", t.getFullName());
+  }
+
+}

Reply via email to