You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by vj...@apache.org on 2022/08/03 17:57:01 UTC

[phoenix] branch 5.1 updated: PHOENIX-6758 During HBase 2 upgrade Phoenix Self healing task fails to create server side connection before reading SYSTEM.TASK (#1478)

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

vjasani pushed a commit to branch 5.1
in repository https://gitbox.apache.org/repos/asf/phoenix.git


The following commit(s) were added to refs/heads/5.1 by this push:
     new 5363c94c62 PHOENIX-6758 During HBase 2 upgrade Phoenix Self healing task fails to create server side connection before reading SYSTEM.TASK (#1478)
5363c94c62 is described below

commit 5363c94c6280daa6966c83b676481e358c9d7410
Author: Viraj Jasani <vj...@apache.org>
AuthorDate: Wed Aug 3 10:56:56 2022 -0700

    PHOENIX-6758 During HBase 2 upgrade Phoenix Self healing task fails to create server side connection before reading SYSTEM.TASK (#1478)
    
    Signed-off-by: Andrew Purtell <ap...@apache.org>
    Signed-off-by: Kadir Ozdemir <ko...@apache.org>
    Signed-off-by: Geoffrey Jacoby <gj...@apache.org>
---
 .../phoenix/query/AdminUtilWithFallback.java       | 123 +++++++++++++++++++++
 .../phoenix/query/ConnectionQueryServicesImpl.java |  13 ++-
 2 files changed, 131 insertions(+), 5 deletions(-)

diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/AdminUtilWithFallback.java b/phoenix-core/src/main/java/org/apache/phoenix/query/AdminUtilWithFallback.java
new file mode 100644
index 0000000000..0402910df1
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/AdminUtilWithFallback.java
@@ -0,0 +1,123 @@
+/*
+ * 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.phoenix.query;
+
+import java.io.IOException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.TableState;
+import org.apache.hadoop.hbase.exceptions.DeserializationException;
+import org.apache.hadoop.hbase.regionserver.NoSuchColumnFamilyException;
+import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.ZooKeeperProtos;
+import org.apache.hadoop.hbase.zookeeper.ZKUtil;
+import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
+import org.apache.hadoop.hbase.zookeeper.ZNodePaths;
+import org.apache.zookeeper.KeeperException;
+
+/**
+ * Admin utility class specifically useful for running Admin APIs in the middle of the
+ * rolling upgrade from HBase 1.x to 2.x versions. Some Admin APIs fail to retrieve
+ * table state details from meta table if master is running on 1.x version and coprocs are
+ * running on 2.x version. Hence, as a fallback, server side coproc can directly perform
+ * zookeeper look-up to retrieve table state data. The fallback use-cases would not be
+ * encountered for fully upgraded 2.x cluster.
+ */
+public class AdminUtilWithFallback {
+
+  private static final Logger LOG = LoggerFactory.getLogger(AdminUtilWithFallback.class);
+
+  public static boolean tableExists(Admin admin, TableName tableName)
+      throws IOException, InterruptedException {
+    try {
+      return admin.tableExists(tableName);
+    } catch (IOException e) {
+      if (e instanceof NoSuchColumnFamilyException || (e.getCause() != null
+          && e.getCause() instanceof NoSuchColumnFamilyException)) {
+        LOG.warn("Admin API to retrieve table existence failed due to missing CF in meta."
+            + " This should happen only when HBase master is running on 1.x and"
+            + " current regionserver is on 2.x. Falling back to retrieve info from ZK.", e);
+        return getTableStateFromZk(tableName, admin) != null;
+      }
+      throw e;
+    }
+  }
+
+  private static ZooKeeperProtos.DeprecatedTableState.State getTableState(ZKWatcher zkw,
+      TableName tableName) throws KeeperException, InterruptedException {
+    String znode =
+        ZNodePaths.joinZNode(zkw.getZNodePaths().tableZNode, tableName.getNameAsString());
+    byte[] data = ZKUtil.getData(zkw, znode);
+    if (data != null && data.length > 0) {
+      try {
+        ProtobufUtil.expectPBMagicPrefix(data);
+        ZooKeeperProtos.DeprecatedTableState.Builder builder =
+            ZooKeeperProtos.DeprecatedTableState.newBuilder();
+        int magicLen = ProtobufUtil.lengthOfPBMagic();
+        ProtobufUtil.mergeFrom(builder, data, magicLen, data.length - magicLen);
+        return builder.getState();
+      } catch (IOException ioe) {
+        KeeperException ke = new KeeperException.DataInconsistencyException();
+        ke.initCause(ioe);
+        throw ke;
+      } catch (DeserializationException de) {
+        throw ZKUtil.convert(de);
+      }
+    } else {
+      return null;
+    }
+  }
+
+  private static TableState.State getTableStateFromZk(TableName tableName, Admin admin)
+      throws IOException, InterruptedException {
+    try (ZKWatcher zkWatcher = new ZKWatcher(admin.getConfiguration(), "phoenix-admin-fallback",
+        null)) {
+      ZooKeeperProtos.DeprecatedTableState.State state =
+          getTableState(zkWatcher, tableName);
+      if (state == null) {
+        return null;
+      }
+      TableState.State tableState;
+      switch (state) {
+      case ENABLED:
+        tableState = TableState.State.ENABLED;
+        break;
+      case DISABLED:
+        tableState = TableState.State.DISABLED;
+        break;
+      case DISABLING:
+        tableState = TableState.State.DISABLING;
+        break;
+      case ENABLING:
+        tableState = TableState.State.ENABLING;
+        break;
+      default:
+        throw new IOException("ZK state inconsistent");
+      }
+      return tableState;
+    } catch (KeeperException e) {
+      throw new IOException(e);
+    }
+  }
+
+}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
index 68fe9bda71..5234695077 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
@@ -514,12 +514,12 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
     @Override
     public Table getTableIfExists(byte[] tableName) throws SQLException {
         try (Admin admin = getAdmin()) {
-            if (!admin.tableExists(TableName.valueOf(tableName))) {
+            if (!AdminUtilWithFallback.tableExists(admin, TableName.valueOf(tableName))) {
                 throw new TableNotFoundException(
                     SchemaUtil.getSchemaNameFromFullName(tableName),
                     SchemaUtil.getTableNameFromFullName(tableName));
             }
-        } catch (IOException e) {
+        } catch (IOException | InterruptedException e) {
             throw new SQLException(e);
         }
         return getTable(tableName);
@@ -1350,7 +1350,8 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
                         // if the NS does not exist, we will error as expected, or
                         // if the NS does exist and tables are already mapped, the check will exit gracefully
                     }
-                    if (admin.tableExists(SchemaUtil.getPhysicalTableName(SYSTEM_CATALOG_NAME_BYTES, false))) {
+                    if (AdminUtilWithFallback.tableExists(admin,
+                        SchemaUtil.getPhysicalTableName(SYSTEM_CATALOG_NAME_BYTES, false))) {
                         // SYSTEM.CATALOG exists, so at this point, we have 3 cases:
                         // 1) If server-side namespace mapping is disabled, drop the SYSTEM namespace if it was created
                         //    above and throw Inconsistent namespace mapping exception
@@ -1374,7 +1375,8 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
                         // Thrown so we can force an upgrade which will just migrate SYSTEM tables to the SYSTEM namespace
                         throw new UpgradeRequiredException(MIN_SYSTEM_TABLE_TIMESTAMP);
                     }
-                } else if (admin.tableExists(SchemaUtil.getPhysicalTableName(SYSTEM_CATALOG_NAME_BYTES, true))) {
+                } else if (AdminUtilWithFallback.tableExists(admin,
+                    SchemaUtil.getPhysicalTableName(SYSTEM_CATALOG_NAME_BYTES, true))) {
                     // If SYSTEM:CATALOG exists, but client-side namespace mapping for SYSTEM tables is disabled, throw an exception
                     throw new SQLExceptionInfo.Builder(
                       SQLExceptionCode.INCONSISTENT_NAMESPACE_MAPPING_PROPERTIES)
@@ -4499,7 +4501,8 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
                     .getPhysicalName(PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME_BYTES, this.getProps()).getName();
             metatable = getTable(mappedSystemTable);
             if (tableNames.contains(PhoenixDatabaseMetaData.SYSTEM_CATALOG_HBASE_TABLE_NAME)) {
-                if (!admin.tableExists(TableName.valueOf(mappedSystemTable))) {
+                if (!AdminUtilWithFallback.tableExists(admin,
+                    TableName.valueOf(mappedSystemTable))) {
                     LOGGER.info("Migrating SYSTEM.CATALOG table to SYSTEM namespace.");
                     // Actual migration of SYSCAT table
                     UpgradeUtil.mapTableToNamespace(admin, metatable,