You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ch...@apache.org on 2019/11/07 02:06:33 UTC

[phoenix] branch 4.x-HBase-1.3 updated: PHOENIX-5544: Dropping a base table with cascade with an older client does not clear all child view metadata

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

chinmayskulkarni pushed a commit to branch 4.x-HBase-1.3
in repository https://gitbox.apache.org/repos/asf/phoenix.git


The following commit(s) were added to refs/heads/4.x-HBase-1.3 by this push:
     new b7d626e  PHOENIX-5544: Dropping a base table with cascade with an older client does not clear all child view metadata
b7d626e is described below

commit b7d626ec9956cbe2872a1f63a32212e92800887c
Author: Chinmay Kulkarni <ch...@gmail.com>
AuthorDate: Wed Nov 6 00:59:19 2019 -0800

    PHOENIX-5544: Dropping a base table with cascade with an older client does not clear all child view metadata
---
 .../phoenix/coprocessor/MetaDataEndpointImpl.java  | 81 +++++++++++++++-------
 .../phoenix/coprocessor/MetaDataProtocol.java      |  1 +
 .../query/DelegateConnectionQueryServices.java     |  2 +-
 .../java/org/apache/phoenix/util/ViewUtil.java     | 40 +++++++++++
 4 files changed, 98 insertions(+), 26 deletions(-)

diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
index 3651927..5e6ad9f 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
@@ -18,6 +18,7 @@
 package org.apache.phoenix.coprocessor;
 
 import static org.apache.hadoop.hbase.KeyValueUtil.createFirstOnRow;
+import static org.apache.phoenix.coprocessor.generated.MetaDataProtos.MutationCode.UNABLE_TO_CREATE_CHILD_LINK;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.APPEND_ONLY_SCHEMA_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ARRAY_SIZE_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.AUTO_PARTITION_SEQ_BYTES;
@@ -57,7 +58,6 @@ import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SALT_BUCKETS_BYTES
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SORT_ORDER_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.STORAGE_SCHEME_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.STORE_NULLS_BYTES;
-import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SEQ_NUM_BYTES;
@@ -76,6 +76,7 @@ import static org.apache.phoenix.query.QueryConstants.VIEW_MODIFIED_PROPERTY_TAG
 import static org.apache.phoenix.schema.PTableType.INDEX;
 import static org.apache.phoenix.util.SchemaUtil.getVarCharLength;
 import static org.apache.phoenix.util.SchemaUtil.getVarChars;
+import static org.apache.phoenix.util.ViewUtil.getSystemTableForChildLinks;
 
 import java.io.IOException;
 import java.security.PrivilegedExceptionAction;
@@ -1715,15 +1716,14 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
                 }
             }
 
-            // check if the table was dropped, but had child views that were have not yet been cleaned up
+            // check if the table was previously dropped, but had child views that have not
+            // yet been cleaned up.
+            // Note that for old clients connecting to a 4.15 server whose metadata hasn't been
+            // upgraded, we disallow dropping a base table that has child views, so in that case
+            // this is a no-op (See PHOENIX-5544)
             if (!Bytes.toString(schemaName).equals(QueryConstants.SYSTEM_SCHEMA_NAME)) {
-                byte[] sysCatOrSysChildLink = SchemaUtil.getPhysicalTableName(
-                        clientVersion >= MIN_SPLITTABLE_SYSTEM_CATALOG ?
-                        SYSTEM_CHILD_LINK_NAME_BYTES : SYSTEM_CATALOG_NAME_BYTES,
-                        env.getConfiguration()).getName();
-                // TODO: PHOENIX-5544 In the case of old clients, this actually does not do anything since the
-                // parent->child links were already removed when dropping the base table
-                ViewUtil.dropChildViews(env, tenantIdBytes, schemaName, tableName, sysCatOrSysChildLink);
+                ViewUtil.dropChildViews(env, tenantIdBytes, schemaName, tableName,
+                        getSystemTableForChildLinks(clientVersion, env.getConfiguration()).getName());
             }
 
             byte[] parentTableKey = null;
@@ -1973,6 +1973,26 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
                 // 3. Finally write the mutations to create the table
 
                 if (tableType == PTableType.VIEW) {
+                    // If we are connecting with an old client to a server that has new metadata
+                    // i.e. it was previously connected to by a 4.15 client, then the client will
+                    // also send the parent->child link metadata to SYSTEM.CATALOG rather than using
+                    // the new ChildLinkMetaDataEndpoint coprocessor. In this case, we must continue
+                    // doing the server-server RPC to send these mutations to SYSTEM.CHILD_LINK.
+                    if (clientVersion < MIN_SPLITTABLE_SYSTEM_CATALOG &&
+                            getSystemTableForChildLinks(clientVersion, env.getConfiguration()).equals(
+                                    SchemaUtil.getPhysicalTableName(SYSTEM_CHILD_LINK_NAME_BYTES,
+                                            env.getConfiguration()))) {
+                        List<Mutation> childLinkMutations =
+                                MetaDataUtil.removeChildLinkMutations(tableMetadata);
+                        MetaDataResponse response =
+                                processRemoteRegionMutations(
+                                        PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME_BYTES,
+                                        childLinkMutations, UNABLE_TO_CREATE_CHILD_LINK);
+                        if (response != null) {
+                            done.run(response);
+                            return;
+                        }
+                    }
                     // Pass in the parent's PTable so that we only tag cells corresponding to the
                     // view's property in case they are different from the parent
                     ViewUtil.addTagsToPutsForViewAlteredProperties(tableMetadata, parentTable);
@@ -2242,10 +2262,10 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
                 }
 
                 // after the view metadata is dropped, drop parent->child link
-                MetaDataResponse response =
-                        processRemoteRegionMutations(
-                                SYSTEM_CHILD_LINK_NAME_BYTES,
-                                childLinkMutations, MetaDataProtos.MutationCode.UNABLE_TO_DELETE_CHILD_LINK);
+                MetaDataResponse response = processRemoteRegionMutations(
+                        getSystemTableForChildLinks(request.getClientVersion(),
+                                env.getConfiguration()).getName(), childLinkMutations,
+                        MetaDataProtos.MutationCode.UNABLE_TO_DELETE_CHILD_LINK);
                 if (response != null) {
                     done.run(response);
                     return;
@@ -2348,32 +2368,44 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
 
             if (tableType == PTableType.TABLE || tableType == PTableType.VIEW || tableType == PTableType.SYSTEM) {
                 // check to see if the table has any child views
-                try (Table hTable = env.getTable(SchemaUtil.getPhysicalTableName(
-                        clientVersion >= MIN_SPLITTABLE_SYSTEM_CATALOG ?
-                                SYSTEM_CHILD_LINK_NAME_BYTES : SYSTEM_CATALOG_NAME_BYTES,
+                try (Table hTable = env.getTable(getSystemTableForChildLinks(clientVersion,
                         env.getConfiguration()))) {
                     boolean hasChildViews =
                             ViewUtil.hasChildViews(hTable, tenantId, schemaName, tableName,
                                     clientTimeStamp);
                     if (hasChildViews) {
                         if (!isCascade) {
+                            LOGGER.error("DROP without CASCADE on tables with child views "
+                                    + "is not permitted");
                             // DROP without CASCADE on tables with child views is not permitted
                             return new MetaDataMutationResult(MutationCode.UNALLOWED_TABLE_MUTATION,
                                     EnvironmentEdgeManager.currentTimeMillis(), null);
                         }
-                        try {
-                            if (clientVersion >= MIN_SPLITTABLE_SYSTEM_CATALOG) {
+                        // For 4.15+ clients and older clients connecting to an upgraded server,
+                        // add a task to drop child views of the base table.
+                        if (clientVersion >= MIN_SPLITTABLE_SYSTEM_CATALOG ||
+                                SchemaUtil.getPhysicalTableName(SYSTEM_CHILD_LINK_NAME_BYTES,
+                                env.getConfiguration()).equals(hTable.getName())) {
+                            try {
                                 PhoenixConnection conn =
                                         QueryUtil.getConnectionOnServer(env.getConfiguration())
                                                 .unwrap(PhoenixConnection.class);
                                 Task.addTask(conn, PTable.TaskType.DROP_CHILD_VIEWS,
                                         Bytes.toString(tenantId), Bytes.toString(schemaName),
                                         Bytes.toString(tableName), this.accessCheckEnabled);
+                            } catch (Throwable t) {
+                                LOGGER.error("Adding a task to drop child views failed!", t);
                             }
-                            // else: the client version is old, so we cannot add a task to cleanup
-                            // child view metadata since SYSTEM.TASK may not exist
-                        } catch (Throwable t) {
-                            LOGGER.error("Adding a task to drop child views failed!", t);
+                        } else {
+                            // (See PHOENIX-5544) For an old client connecting to a non-upgraded
+                            // server, we disallow dropping a base table that has child views.
+                            LOGGER.error("Dropping a table that has child views is not permitted "
+                                    + "for old clients connecting to a new server with old metadata."
+                                    + " Please upgrade the client to " +
+                                    MIN_SPLITTABLE_SYSTEM_CATALOG_VERSION);
+                            return new MetaDataMutationResult(
+                                    MutationCode.UNALLOWED_TABLE_MUTATION,
+                                    EnvironmentEdgeManager.currentTimeMillis(), null);
                         }
                     }
                 }
@@ -2474,9 +2506,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
                         // Also if QueryServices.ALLOW_SPLITTABLE_SYSTEM_CATALOG_ROLLBACK is true, we block adding
                         // a column to a parent table so that we can rollback the upgrade if required.
                         if (clientVersion < MIN_SPLITTABLE_SYSTEM_CATALOG) {
-                            LOGGER.error(
-                                    "Unable to add or drop a column as the client is older than "
-                                            + MIN_SPLITTABLE_SYSTEM_CATALOG);
+                            LOGGER.error("Unable to add or drop a column as the client is older "
+                                    + "than " + MIN_SPLITTABLE_SYSTEM_CATALOG_VERSION);
                             return new MetaDataProtocol.MetaDataMutationResult(MetaDataProtocol.MutationCode.UNALLOWED_TABLE_MUTATION,
                                     EnvironmentEdgeManager.currentTimeMillis(), null);
                         } else if (allowSplittableSystemCatalogRollback) {
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java
index e217a3b..a83b04b 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java
@@ -112,6 +112,7 @@ public abstract class MetaDataProtocol extends MetaDataService {
     public static final int CLIENT_KEY_VALUE_BUILDER_THRESHOLD = VersionUtil.encodeVersion("0", "94", "14");
     // Version at which we allow SYSTEM.CATALOG to split
     public static final int MIN_SPLITTABLE_SYSTEM_CATALOG = VersionUtil.encodeVersion("4", "15", "0");
+    public static final String MIN_SPLITTABLE_SYSTEM_CATALOG_VERSION = "4.15.0";
 
     // Version at and after which we will no longer expect client to serialize thresholdBytes for
     // spooling into the scan
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java
index 761b758..0e0554e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java
@@ -363,7 +363,7 @@ public class DelegateConnectionQueryServices extends DelegateQueryServices imple
 
     @Override
     public void clearUpgradeRequired() {
-        getDelegate().isUpgradeRequired();
+        getDelegate().clearUpgradeRequired();
     }
 
     @Override
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/ViewUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/ViewUtil.java
index 100c9ab..8c81234 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/ViewUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/ViewUtil.java
@@ -19,7 +19,10 @@ import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.HBaseAdmin;
 import org.apache.hadoop.hbase.client.Mutation;
 import org.apache.hadoop.hbase.client.Put;
 import org.apache.hadoop.hbase.client.Result;
@@ -68,8 +71,11 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
+import static org.apache.phoenix.coprocessor.MetaDataProtocol.MIN_SPLITTABLE_SYSTEM_CATALOG;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LINK_TYPE_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PARENT_TENANT_ID_BYTES;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME_BYTES;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_TYPE_BYTES;
 import static org.apache.phoenix.schema.PTableImpl.getColumnsToClone;
@@ -219,6 +225,40 @@ public class ViewUtil {
         }
     }
 
+
+    /**
+     * Determines whether we should use SYSTEM.CATALOG or SYSTEM.CHILD_LINK to find parent->child
+     * links i.e. {@link LinkType#CHILD_TABLE}.
+     * If the client is older than 4.15.0 and the SYSTEM.CHILD_LINK table does not exist, we use
+     * the SYSTEM.CATALOG table. In all other cases, we use the SYSTEM.CHILD_LINK table.
+     * This is required for backwards compatibility.
+     * @param clientVersion client version
+     * @param conf server-side configuration
+     * @return name of the system table to be used
+     * @throws SQLException
+     */
+    public static TableName getSystemTableForChildLinks(int clientVersion,
+            Configuration conf) throws SQLException, IOException {
+        byte[] fullTableName = SYSTEM_CHILD_LINK_NAME_BYTES;
+        if (clientVersion < MIN_SPLITTABLE_SYSTEM_CATALOG) {
+            try (PhoenixConnection connection = QueryUtil.getConnectionOnServer(
+                    conf).unwrap(PhoenixConnection.class);
+                    HBaseAdmin admin = connection.getQueryServices().getAdmin()) {
+
+                // If this is an old client and the CHILD_LINK table doesn't exist i.e. metadata
+                // hasn't been updated since there was never a connection from a 4.15 client
+                if (!admin.tableExists(SchemaUtil.getPhysicalTableName(
+                        SYSTEM_CHILD_LINK_NAME_BYTES, conf))) {
+                    fullTableName = SYSTEM_CATALOG_NAME_BYTES;
+                }
+            } catch (ClassNotFoundException e) {
+                logger.error("Error getting a connection on the server : " + e);
+                throw new SQLException(e);
+            }
+        }
+        return SchemaUtil.getPhysicalTableName(fullTableName, conf);
+    }
+
     public static boolean isDivergedView(PTable view) {
         return view.getBaseColumnCount() == QueryConstants.DIVERGED_VIEW_BASE_COLUMN_COUNT;
     }