This is an automated email from the ASF dual-hosted git repository. chinmayskulkarni pushed a commit to branch 4.x-HBase-1.5 in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/4.x-HBase-1.5 by this push: new 0db6313 PHOENIX-4810: Send parent->child link mutations to SYSTEM.CHILD_LINK table in MetdataClient.createTableInternal 0db6313 is described below commit 0db6313987b8473f296a952978697145168356ec Author: Chinmay Kulkarni <chinmayskulka...@gmail.com> AuthorDate: Mon Sep 30 18:32:07 2019 -0700 PHOENIX-4810: Send parent->child link mutations to SYSTEM.CHILD_LINK table in MetdataClient.createTableInternal --- .../apache/phoenix/end2end/BasePermissionsIT.java | 100 +-- .../phoenix/end2end/PermissionNSEnabledIT.java | 72 ++ .../it/java/org/apache/phoenix/end2end/ViewIT.java | 67 +- .../coprocessor/BaseMetaDataEndpointObserver.java | 5 + .../coprocessor/ChildLinkMetaDataEndpoint.java | 121 ++++ .../phoenix/coprocessor/MetaDataEndpointImpl.java | 74 +- .../coprocessor/MetaDataEndpointObserver.java | 3 + .../phoenix/coprocessor/MetaDataProtocol.java | 3 + .../PhoenixMetaDataCoprocessorHost.java | 33 +- .../generated/ChildLinkMetaDataProtos.java | 786 +++++++++++++++++++++ .../coprocessor/generated/MetaDataProtos.java | 60 +- .../apache/phoenix/exception/SQLExceptionCode.java | 7 + .../org/apache/phoenix/protobuf/ProtobufUtil.java | 6 + .../phoenix/query/ConnectionQueryServicesImpl.java | 88 ++- .../org/apache/phoenix/schema/MetaDataClient.java | 13 +- .../java/org/apache/phoenix/util/MetaDataUtil.java | 18 +- .../src/main/ChildLinkMetaDataService.proto | 36 + phoenix-protocol/src/main/MetaDataService.proto | 1 + 18 files changed, 1350 insertions(+), 143 deletions(-) diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BasePermissionsIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BasePermissionsIT.java index c4e3907..4301ec8 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BasePermissionsIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BasePermissionsIT.java @@ -76,26 +76,26 @@ public abstract class BasePermissionsIT extends BaseTest { private static final Logger LOGGER = LoggerFactory.getLogger(BasePermissionsIT.class); - static String SUPER_USER = System.getProperty("user.name"); + private static String SUPER_USER = System.getProperty("user.name"); - static HBaseTestingUtility testUtil; - static final Set<String> PHOENIX_SYSTEM_TABLES = + private static HBaseTestingUtility testUtil; + private static final Set<String> PHOENIX_SYSTEM_TABLES = new HashSet<>(Arrays.asList("SYSTEM.CATALOG", "SYSTEM.SEQUENCE", "SYSTEM.STATS", - "SYSTEM.FUNCTION", "SYSTEM.MUTEX")); + "SYSTEM.FUNCTION", "SYSTEM.MUTEX", "SYSTEM.CHILD_LINK")); - static final Set<String> PHOENIX_SYSTEM_TABLES_IDENTIFIERS = + private static final Set<String> PHOENIX_SYSTEM_TABLES_IDENTIFIERS = new HashSet<>(Arrays.asList("SYSTEM.\"CATALOG\"", "SYSTEM.\"SEQUENCE\"", - "SYSTEM.\"STATS\"", "SYSTEM.\"FUNCTION\"", "SYSTEM.\"MUTEX\"")); + "SYSTEM.\"STATS\"", "SYSTEM.\"FUNCTION\"", "SYSTEM.\"MUTEX\"", "SYSTEM.\"CHILD_LINK\"")); - static final String SYSTEM_SEQUENCE_IDENTIFIER = + private static final String SYSTEM_SEQUENCE_IDENTIFIER = QueryConstants.SYSTEM_SCHEMA_NAME + "." + "\"" + PhoenixDatabaseMetaData.SYSTEM_SEQUENCE_TABLE+ "\""; - static final String SYSTEM_MUTEX_IDENTIFIER = + private static final String SYSTEM_MUTEX_IDENTIFIER = QueryConstants.SYSTEM_SCHEMA_NAME + "." + "\"" + PhoenixDatabaseMetaData.SYSTEM_MUTEX_TABLE_NAME + "\""; static final Set<String> PHOENIX_NAMESPACE_MAPPED_SYSTEM_TABLES = new HashSet<>(Arrays.asList( - "SYSTEM:CATALOG", "SYSTEM:SEQUENCE", "SYSTEM:STATS", "SYSTEM:FUNCTION", "SYSTEM:MUTEX")); + "SYSTEM:CATALOG", "SYSTEM:SEQUENCE", "SYSTEM:STATS", "SYSTEM:FUNCTION", "SYSTEM:MUTEX", "SYSTEM:CHILD_LINK")); // Create Multiple users so that we can use Hadoop UGI to run tasks as various users // Permissions can be granted or revoke by superusers and admins only @@ -104,23 +104,23 @@ public abstract class BasePermissionsIT extends BaseTest { // Super User has all the access static User superUser1 = null; - static User superUser2 = null; + private static User superUser2 = null; // Regular users are granted and revoked permissions as needed User regularUser1 = null; - User regularUser2 = null; - User regularUser3 = null; - User regularUser4 = null; + private User regularUser2 = null; + private User regularUser3 = null; + private User regularUser4 = null; // Group User is equivalent of regular user but inside a group // Permissions can be granted to group should affect this user static final String GROUP_SYSTEM_ACCESS = "group_system_access"; - User groupUser = null; + private User groupUser = null; // Unpriviledged User doesn't have any access and is denied for every action User unprivilegedUser = null; - static final int NUM_RECORDS = 5; + private static final int NUM_RECORDS = 5; boolean isNamespaceMapped; @@ -134,12 +134,12 @@ public abstract class BasePermissionsIT extends BaseTest { private String view1TableName; private String view2TableName; - public BasePermissionsIT(final boolean isNamespaceMapped) throws Exception { + BasePermissionsIT(final boolean isNamespaceMapped) throws Exception { this.isNamespaceMapped = isNamespaceMapped; this.tableName = generateUniqueName(); } - public static void initCluster(boolean isNamespaceMapped) throws Exception { + static void initCluster(boolean isNamespaceMapped) throws Exception { if (null != testUtil) { testUtil.shutdownMiniCluster(); testUtil = null; @@ -234,7 +234,7 @@ public abstract class BasePermissionsIT extends BaseTest { AccessControlClient.revoke(getUtility().getConnection(), unprivilegedUser.getShortName(), Permission.Action.values() ); } - Properties getClientProperties(String tenantId) { + private Properties getClientProperties(String tenantId) { Properties props = new Properties(); if(tenantId != null) { props.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, tenantId); @@ -255,7 +255,7 @@ public abstract class BasePermissionsIT extends BaseTest { return "jdbc:phoenix:localhost:" + testUtil.getZkCluster().getClientPort() + ":/hbase"; } - static Set<String> getHBaseTables() throws IOException { + private static Set<String> getHBaseTables() throws IOException { Set<String> tables = new HashSet<>(); for (TableName tn : testUtil.getHBaseAdmin().listTableNames()) { tables.add(tn.getNameAsString()); @@ -266,12 +266,12 @@ public abstract class BasePermissionsIT extends BaseTest { // UG Object // 1. Instance of String --> represents GROUP name // 2. Instance of User --> represents HBase user - AccessTestAction grantPermissions(final String actions, final Object ug, + private AccessTestAction grantPermissions(final String actions, final Object ug, final String tableOrSchemaList, final boolean isSchema) throws SQLException { return grantPermissions(actions, ug, Collections.singleton(tableOrSchemaList), isSchema); } - AccessTestAction grantPermissions(final String actions, final Object ug, + private AccessTestAction grantPermissions(final String actions, final Object ug, final Set<String> tableOrSchemaList, final boolean isSchema) throws SQLException { return new AccessTestAction() { @Override @@ -289,7 +289,7 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction grantPermissions(final String actions, final User user) throws SQLException { + private AccessTestAction grantPermissions(final String actions, final User user) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -303,12 +303,12 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction revokePermissions(final Object ug, + private AccessTestAction revokePermissions(final Object ug, final String tableOrSchemaList, final boolean isSchema) throws SQLException { return revokePermissions(ug, Collections.singleton(tableOrSchemaList), isSchema); } - AccessTestAction revokePermissions(final Object ug, + private AccessTestAction revokePermissions(final Object ug, final Set<String> tableOrSchemaList, final boolean isSchema) throws SQLException { return new AccessTestAction() { @Override @@ -326,7 +326,7 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction revokePermissions(final Object ug) throws SQLException { + private AccessTestAction revokePermissions(final Object ug) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -343,7 +343,7 @@ public abstract class BasePermissionsIT extends BaseTest { // Attempts to get a Phoenix Connection // New connections could create SYSTEM tables if appropriate perms are granted - AccessTestAction getConnectionAction() throws SQLException { + private AccessTestAction getConnectionAction() throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -403,7 +403,7 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction createMultiTenantTable(final String tableName) throws SQLException { + private AccessTestAction createMultiTenantTable(final String tableName) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -426,7 +426,7 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction dropTable(final String tableName) throws SQLException { + private AccessTestAction dropTable(final String tableName) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -443,7 +443,7 @@ public abstract class BasePermissionsIT extends BaseTest { // AccessDeniedException is only triggered when ResultSet#next() method is called // The first call triggers HBase Scan object // The Statement#executeQuery() method returns an iterator and doesn't interact with HBase API at all - AccessTestAction readTableWithoutVerification(final String tableName) throws SQLException { + private AccessTestAction readTableWithoutVerification(final String tableName) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -458,11 +458,11 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction readTable(final String tableName) throws SQLException { + private AccessTestAction readTable(final String tableName) throws SQLException { return readTable(tableName,null); } - AccessTestAction readTable(final String tableName, final String indexName) throws SQLException { + private AccessTestAction readTable(final String tableName, final String indexName) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -484,11 +484,11 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction readMultiTenantTableWithoutIndex(final String tableName) throws SQLException { + private AccessTestAction readMultiTenantTableWithoutIndex(final String tableName) throws SQLException { return readMultiTenantTableWithoutIndex(tableName, null); } - AccessTestAction readMultiTenantTableWithoutIndex(final String tableName, final String tenantId) throws SQLException { + private AccessTestAction readMultiTenantTableWithoutIndex(final String tableName, final String tenantId) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -522,11 +522,11 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction readMultiTenantTableWithIndex(final String tableName) throws SQLException { + private AccessTestAction readMultiTenantTableWithIndex(final String tableName) throws SQLException { return readMultiTenantTableWithIndex(tableName, null); } - AccessTestAction readMultiTenantTableWithIndex(final String tableName, final String tenantId) throws SQLException { + private AccessTestAction readMultiTenantTableWithIndex(final String tableName, final String tenantId) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -559,7 +559,7 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction addProperties(final String tableName, final String property, final String value) + private AccessTestAction addProperties(final String tableName, final String property, final String value) throws SQLException { return new AccessTestAction() { @Override @@ -584,7 +584,7 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction dropColumn(final String tableName, final String columnName) throws SQLException { + private AccessTestAction dropColumn(final String tableName, final String columnName) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -596,11 +596,11 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction createIndex(final String indexName, final String dataTable) throws SQLException { + private AccessTestAction createIndex(final String indexName, final String dataTable) throws SQLException { return createIndex(indexName, dataTable, null); } - AccessTestAction createIndex(final String indexName, final String dataTable, final String tenantId) throws SQLException { + private AccessTestAction createIndex(final String indexName, final String dataTable, final String tenantId) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -613,7 +613,7 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction createLocalIndex(final String indexName, final String dataTable) throws SQLException { + private AccessTestAction createLocalIndex(final String indexName, final String dataTable) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -626,7 +626,7 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction dropIndex(final String indexName, final String dataTable) throws SQLException { + private AccessTestAction dropIndex(final String indexName, final String dataTable) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -638,7 +638,7 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction rebuildIndex(final String indexName, final String dataTable) throws SQLException { + private AccessTestAction rebuildIndex(final String indexName, final String dataTable) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -651,7 +651,7 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - AccessTestAction dropView(final String viewName) throws SQLException { + private AccessTestAction dropView(final String viewName) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -667,7 +667,7 @@ public abstract class BasePermissionsIT extends BaseTest { return createView(viewName, dataTable, null); } - AccessTestAction createView(final String viewName, final String dataTable, final String tenantId) throws SQLException { + private AccessTestAction createView(final String viewName, final String dataTable, final String tenantId) throws SQLException { return new AccessTestAction() { @Override public Object run() throws Exception { @@ -680,7 +680,7 @@ public abstract class BasePermissionsIT extends BaseTest { }; } - static interface AccessTestAction extends PrivilegedExceptionAction<Object> { } + interface AccessTestAction extends PrivilegedExceptionAction<Object> { } /** This fails only in case of ADE or empty list for any of the users. */ void verifyAllowed(AccessTestAction action, User... users) throws Exception { @@ -692,13 +692,13 @@ public abstract class BasePermissionsIT extends BaseTest { } } - void verifyAllowed(User user, AccessTestAction... actions) throws Exception { + private void verifyAllowed(User user, AccessTestAction... actions) throws Exception { for (AccessTestAction action : actions) { try { Object obj = user.runAs(action); if (obj != null && obj instanceof List<?>) { List<?> results = (List<?>) obj; - if (results != null && results.isEmpty()) { + if (results.isEmpty()) { fail("Empty non null results from action for user '" + user.getShortName() + "'"); } } @@ -719,7 +719,7 @@ public abstract class BasePermissionsIT extends BaseTest { } /** This passes only if desired exception is caught for all users. */ - <T> void verifyDenied(User user, Class<T> exception, AccessTestAction... actions) throws Exception { + private <T> void verifyDenied(User user, Class<T> exception, AccessTestAction... actions) throws Exception { for (AccessTestAction action : actions) { try { user.runAs(action); @@ -755,11 +755,11 @@ public abstract class BasePermissionsIT extends BaseTest { } } - String surroundWithDoubleQuotes(String input) { + private String surroundWithDoubleQuotes(String input) { return "\"" + input + "\""; } - void validateAccessDeniedException(AccessDeniedException ade) { + private void validateAccessDeniedException(AccessDeniedException ade) { String msg = ade.getMessage(); assertTrue("Exception contained unexpected message: '" + msg + "'", !msg.contains("is not the scanner owner")); diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/PermissionNSEnabledIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/PermissionNSEnabledIT.java index 30f3a08..fffa536 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/PermissionNSEnabledIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/PermissionNSEnabledIT.java @@ -29,8 +29,11 @@ import org.junit.Test; import java.security.PrivilegedExceptionAction; import java.sql.Connection; import java.sql.SQLException; +import java.util.Collections; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PK_NAME; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_TABLE; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_TABLE; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_SCHEMA_NAME; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -124,4 +127,73 @@ public class PermissionNSEnabledIT extends BasePermissionsIT { revokeAll(); } } + + // After PHOENIX-4810, a user requires Exec permissions on SYSTEM.CHILD_LINK to create views + // since the user must invoke the ChildLinkMetaDataEndpoint to create parent->child links + @Test + public void testViewCreationFailsWhenNoExecPermsOnSystemChildLink() throws Throwable { + try { + grantSystemTableAccess(); + final TableName systemChildLink = TableName.valueOf(SchemaUtil.getPhysicalHBaseTableName( + SYSTEM_SCHEMA_NAME, SYSTEM_CHILD_LINK_TABLE, true).getString()); + final String schemaName = "S_" + generateUniqueName(); + final String tableName = "T_" + generateUniqueName(); + final String fullTableName = schemaName + "." + tableName; + final String viewName = "V_" + generateUniqueName(); + verifyAllowed(createSchema(schemaName), superUser1); + verifyAllowed(createTable(fullTableName), superUser1); + + superUser1.runAs(new PrivilegedExceptionAction<Object>() { + @Override public Object run() throws Exception { + try { + // Revoke Exec permissions for SYSTEM CHILD_LINK for the unprivileged user + AccessControlClient.revoke(getUtility().getConnection(), systemChildLink, + unprivilegedUser.getShortName(), null, null, + Permission.Action.EXEC); + + // Grant read and exec permissions to the user on the parent table so it + // doesn't fail to getTable when resolving the parent + PermissionNSEnabledIT.this.grantPermissions(unprivilegedUser.getShortName(), + Collections.singleton(SchemaUtil + .getPhysicalHBaseTableName(schemaName, tableName, true) + .getString()), Permission.Action.READ, + Permission.Action.EXEC); + } catch (Throwable t) { + if (t instanceof Exception) { + throw (Exception) t; + } else { + throw new Exception(t); + } + } + return null; + } + }); + + // Adding parent->child links fails for the unprivileged user thus failing view creation + verifyDenied(createView(viewName, fullTableName), AccessDeniedException.class, + unprivilegedUser); + + superUser1.runAs(new PrivilegedExceptionAction<Object>() { + @Override public Object run() throws Exception { + try { + // Grant Exec permissions for SYSTEM CHILD_LINK for the unprivileged user + PermissionNSEnabledIT.this.grantPermissions(unprivilegedUser.getShortName(), + Collections.singleton(systemChildLink.getNameAsString()), + Permission.Action.EXEC); + } catch (Throwable t) { + if (t instanceof Exception) { + throw (Exception) t; + } else { + throw new Exception(t); + } + } + return null; + } + }); + verifyAllowed(createView(viewName, fullTableName), unprivilegedUser); + } finally { + revokeAll(); + } + } + } diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java index 9ab7bb3..1ca6e07 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewIT.java @@ -81,6 +81,7 @@ import org.apache.phoenix.util.QueryUtil; import org.apache.phoenix.util.ReadOnlyProps; import org.apache.phoenix.util.SchemaUtil; import org.apache.phoenix.util.TestUtil; +import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -100,6 +101,8 @@ public class ViewIT extends SplitSystemCatalogIT { private static volatile CountDownLatch latch1 = null; private static volatile CountDownLatch latch2 = null; + private static volatile boolean throwExceptionInChildLinkPreHook = false; + private static volatile boolean slowDownAddingChildLink = false; public ViewIT(String transactionProvider, boolean columnEncoded) { StringBuilder optionBuilder = new StringBuilder(); @@ -140,7 +143,15 @@ public class ViewIT extends SplitSystemCatalogIT { splitSystemCatalog(); } } - + + @After + public void cleanup() { + latch1 = null; + latch2 = null; + throwExceptionInChildLinkPreHook = false; + slowDownAddingChildLink = false; + } + public static class TestMetaDataRegionObserver extends BaseMetaDataEndpointObserver { @Override @@ -163,6 +174,16 @@ public class ViewIT extends SplitSystemCatalogIT { processTable(tableName); } + @Override + public void preCreateViewAddChildLink( + final ObserverContext<PhoenixMetaDataControllerEnvironment> ctx, + final String tableName) throws IOException { + if (throwExceptionInChildLinkPreHook) { + throw new IOException(); + } + processTable(tableName); + } + private void processTable(String tableName) throws DoNotRetryIOException { if (tableName.equals(FAILED_VIEWNAME)) { // throwing anything other than instances of IOException result @@ -170,8 +191,8 @@ public class ViewIT extends SplitSystemCatalogIT { // DoNotRetryIOException tells HBase not to retry this mutation // multiple times throw new DoNotRetryIOException(); - } else if (tableName.startsWith(SLOW_VIEWNAME_PREFIX)) { - // simulate a slow write to SYSTEM.CATALOG + } else if (tableName.startsWith(SLOW_VIEWNAME_PREFIX) || slowDownAddingChildLink) { + // simulate a slow write to SYSTEM.CATALOG or SYSTEM.CHILD_LINK if (latch1 != null) { latch1.countDown(); } @@ -801,6 +822,12 @@ public class ViewIT extends SplitSystemCatalogIT { } }); + // When dropping a table, we check the parent->child links in the SYSTEM.CHILD_LINK + // table and check that cascade is set, if it isn't, we throw an exception (see + // ViewUtil.hasChildViews). After PHOENIX-4810, we first send a client-server RPC to add + // parent->child links to SYSTEM.CHILD_LINK and then add metadata for the view in + // SYSTEM.CATALOG, so we must delay link creation so that the drop table does not fail + slowDownAddingChildLink = true; // create the view in a separate thread (which will take some time // to complete) Future<Exception> future = @@ -808,6 +835,9 @@ public class ViewIT extends SplitSystemCatalogIT { // wait till the thread makes the rpc to create the view latch1.await(); tableDdl = "DROP TABLE " + fullTableName; + + // Revert this flag since we don't want to wait in preDropTable + slowDownAddingChildLink = false; // drop table goes through first and so the view creation should fail conn.createStatement().execute(tableDdl); latch2.countDown(); @@ -821,10 +851,35 @@ public class ViewIT extends SplitSystemCatalogIT { } @Test + public void testChildLinkCreationFailThrowsException() throws Exception { + try (Connection conn = DriverManager.getConnection(getUrl())) { + String fullTableName = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); + String fullViewName1 = SchemaUtil.getTableName(SCHEMA3, generateUniqueName()); + // create base table + String tableDdl = "CREATE TABLE " + fullTableName + + " (k INTEGER NOT NULL PRIMARY KEY, v1 DATE)" + tableDDLOptions; + conn.createStatement().execute(tableDdl); + + // Throw an exception in ChildLinkMetaDataEndpoint while adding parent->child links + // to simulate a failure + throwExceptionInChildLinkPreHook = true; + // create a view + String ddl = "CREATE VIEW " + fullViewName1 + " (v2 VARCHAR) AS SELECT * FROM " + + fullTableName + " WHERE k = 6"; + try { + conn.createStatement().execute(ddl); + fail("Should have thrown an exception"); + } catch(SQLException sqlE) { + assertEquals("Expected a different Error code", + SQLExceptionCode.UNABLE_TO_CREATE_CHILD_LINK.getErrorCode(), + sqlE.getErrorCode()); + } + } + } + + @Test public void testConcurrentAddSameColumnDifferentType() throws Exception { try (Connection conn = DriverManager.getConnection(getUrl())) { - latch1 = null; - latch2 = null; String fullTableName = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); String fullViewName1 = SLOW_VIEWNAME_PREFIX + "_" + generateUniqueName(); String fullViewName2 = SchemaUtil.getTableName(SCHEMA3, generateUniqueName()); @@ -884,8 +939,6 @@ public class ViewIT extends SplitSystemCatalogIT { @Test public void testConcurrentAddDifferentColumn() throws Exception { try (Connection conn = DriverManager.getConnection(getUrl())) { - latch1 = null; - latch2 = null; String fullTableName = SchemaUtil.getTableName(SCHEMA1, generateUniqueName()); String fullViewName1 = SLOW_VIEWNAME_PREFIX + "_" + generateUniqueName(); String fullViewName2 = SchemaUtil.getTableName(SCHEMA3, generateUniqueName()); diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/BaseMetaDataEndpointObserver.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/BaseMetaDataEndpointObserver.java index 8decc8c..1f9e29b 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/BaseMetaDataEndpointObserver.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/BaseMetaDataEndpointObserver.java @@ -108,4 +108,9 @@ public class BaseMetaDataEndpointObserver implements MetaDataEndpointObserver{ throws IOException { } + + @Override + public void preCreateViewAddChildLink( + final ObserverContext<PhoenixMetaDataControllerEnvironment> ctx, + final String tableName) throws IOException {} } diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/ChildLinkMetaDataEndpoint.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/ChildLinkMetaDataEndpoint.java new file mode 100644 index 0000000..873a1e3 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/ChildLinkMetaDataEndpoint.java @@ -0,0 +1,121 @@ +/* + * 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.coprocessor; + +import com.google.protobuf.RpcCallback; +import com.google.protobuf.RpcController; +import com.google.protobuf.Service; +import org.apache.hadoop.hbase.Coprocessor; +import org.apache.hadoop.hbase.CoprocessorEnvironment; +import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.client.Mutation; +import org.apache.hadoop.hbase.coprocessor.CoprocessorException; +import org.apache.hadoop.hbase.coprocessor.CoprocessorService; +import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; +import org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest; +import org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.ChildLinkMetaDataService; +import org.apache.phoenix.coprocessor.generated.MetaDataProtos; +import org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse; +import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData; +import org.apache.phoenix.protobuf.ProtobufUtil; +import org.apache.phoenix.query.QueryServices; +import org.apache.phoenix.query.QueryServicesOptions; +import org.apache.phoenix.util.EnvironmentEdgeManager; +import org.apache.phoenix.util.MetaDataUtil; +import org.apache.phoenix.util.SchemaUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +import static org.apache.phoenix.coprocessor.MetaDataEndpointImpl.mutateRowsWithLocks; + +/** + * Endpoint co-processor through which Phoenix metadata mutations for SYSTEM.CHILD_LINK flow. + * The parent->child links ({@link org.apache.phoenix.schema.PTable.LinkType#CHILD_TABLE}) + * are stored in the SYSTEM.CHILD_LINK table. + */ +public class ChildLinkMetaDataEndpoint extends ChildLinkMetaDataService implements + CoprocessorService, Coprocessor { + + private static final Logger LOGGER = LoggerFactory.getLogger(ChildLinkMetaDataEndpoint.class); + private RegionCoprocessorEnvironment env; + private PhoenixMetaDataCoprocessorHost phoenixAccessCoprocessorHost; + private boolean accessCheckEnabled; + + @Override + public void start(CoprocessorEnvironment env) throws IOException { + if (env instanceof RegionCoprocessorEnvironment) { + this.env = (RegionCoprocessorEnvironment) env; + } else { + throw new CoprocessorException("Must be loaded on a table region!"); + } + this.phoenixAccessCoprocessorHost = new PhoenixMetaDataCoprocessorHost(this.env); + this.accessCheckEnabled = env.getConfiguration().getBoolean(QueryServices.PHOENIX_ACLS_ENABLED, + QueryServicesOptions.DEFAULT_PHOENIX_ACLS_ENABLED); + } + + @Override + public void stop(CoprocessorEnvironment env) throws IOException { + // Do nothing + } + + @Override + public Service getService() { + return this; + } + + @Override + public void createViewAddChildLink(RpcController controller, + CreateViewAddChildLinkRequest request, RpcCallback<MetaDataResponse> done) { + + MetaDataResponse.Builder builder = MetaDataResponse.newBuilder(); + try { + List<Mutation> childLinkMutations = ProtobufUtil.getMutations(request); + if (childLinkMutations.isEmpty()) { + done.run(builder.build()); + return; + } + byte[][] rowKeyMetaData = new byte[3][]; + MetaDataUtil.getTenantIdAndSchemaAndTableName(childLinkMutations, rowKeyMetaData); + byte[] parentSchemaName = rowKeyMetaData[PhoenixDatabaseMetaData.SCHEMA_NAME_INDEX]; + byte[] parentTableName = rowKeyMetaData[PhoenixDatabaseMetaData.TABLE_NAME_INDEX]; + String fullparentTableName = SchemaUtil.getTableName(parentSchemaName, parentTableName); + + getCoprocessorHost().preCreateViewAddChildLink(fullparentTableName); + + // From 4.15 the parent->child links are stored in a separate table SYSTEM.CHILD_LINK + mutateRowsWithLocks(this.accessCheckEnabled, this.env.getRegion(), childLinkMutations, + Collections.<byte[]>emptySet(), HConstants.NO_NONCE, HConstants.NO_NONCE); + + } catch (Throwable t) { + LOGGER.error("Unable to write mutations to " + + PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME, t); + builder.setReturnCode(MetaDataProtos.MutationCode.UNABLE_TO_CREATE_CHILD_LINK); + builder.setMutationTime(EnvironmentEdgeManager.currentTimeMillis()); + done.run(builder.build()); + } + } + + private PhoenixMetaDataCoprocessorHost getCoprocessorHost() { + return phoenixAccessCoprocessorHost; + } + +} 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 679c6b0..6df5bf8 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 @@ -1912,23 +1912,13 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso // The mutations to create a table are written in the following order: // 1. Write the child link as if the next two steps fail we // ignore missing children while processing a parent + // (this is already done at this point, as a separate client-server RPC + // to the ChildLinkMetaDataEndpoint coprocessor) // 2. Update the encoded column qualifier for the parent table if its on a // different region server (for tables that use column qualifier encoding) // if the next step fails we end up wasting a few col qualifiers // 3. Finally write the mutations to create the table - // From 4.15 the parent->child links are stored in a separate table SYSTEM.CHILD_LINK - // TODO remove this after PHOENIX-4810 is implemented - List<Mutation> childLinkMutations = MetaDataUtil.removeChildLinks(tableMetadata); - MetaDataResponse response = - processRemoteRegionMutations( - PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME_BYTES, - childLinkMutations, MetaDataProtos.MutationCode.UNABLE_TO_CREATE_CHILD_LINK); - if (response != null) { - done.run(response); - return; - } - if (tableType == PTableType.VIEW) { // 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 @@ -1947,7 +1937,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso // column qualifier counter on the parent table) if (parentTable != null && tableType == PTableType.VIEW && parentTable .getEncodingScheme() != QualifierEncodingScheme.NON_ENCODED_QUALIFIERS) { - response = + // TODO: Avoid doing server-server RPC when we have held row locks + MetaDataResponse response = processRemoteRegionMutations( PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME_BYTES, remoteMutations, MetaDataProtos.MutationCode.UNABLE_TO_UPDATE_PARENT_TABLE); @@ -1977,7 +1968,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso // primary and then index table locks are held, in that order). For now, we just don't support // indexing on the system table. This is an issue because of the way we manage batch mutation // in the Indexer. - mutateRowsWithLocks(region, localMutations, Collections.<byte[]>emptySet(), HConstants.NO_NONCE, HConstants.NO_NONCE); + mutateRowsWithLocks(this.accessCheckEnabled, region, localMutations, Collections.<byte[]>emptySet(), + HConstants.NO_NONCE, HConstants.NO_NONCE); // Invalidate the cache - the next getTable call will add it // TODO: consider loading the table that was just created here, patching up the parent table, and updating the cache @@ -2184,8 +2176,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso } // drop rows from catalog on this region - mutateRowsWithLocks(region, localMutations, Collections.<byte[]>emptySet(), HConstants.NO_NONCE, - HConstants.NO_NONCE); + mutateRowsWithLocks(this.accessCheckEnabled, region, localMutations, Collections.<byte[]>emptySet(), + HConstants.NO_NONCE, HConstants.NO_NONCE); long currentTime = MetaDataUtil.getClientTimeStamp(tableMetadata); for (ImmutableBytesPtr ckey : invalidateList) { @@ -2196,18 +2188,17 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso metaDataCache.invalidate(parentCacheKey); } - // after the view metadata is dropped drop parent->child link + // after the view metadata is dropped, drop parent->child link MetaDataResponse response = processRemoteRegionMutations( PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME_BYTES, - childLinkMutations, MetaDataProtos.MutationCode.UNABLE_TO_CREATE_CHILD_LINK); + childLinkMutations, MetaDataProtos.MutationCode.UNABLE_TO_DELETE_CHILD_LINK); if (response != null) { done.run(response); return; } done.run(MetaDataMutationResult.toProto(result)); - return; } finally { releaseRowLocks(region, locks); } @@ -2347,7 +2338,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso if (rowKeyMetaData[PhoenixDatabaseMetaData.COLUMN_NAME_INDEX].length == 0 && linkType == LinkType.INDEX_TABLE) { indexNames.add(rowKeyMetaData[PhoenixDatabaseMetaData.FAMILY_NAME_INDEX]); } else if (tableType == PTableType.VIEW && (linkType == LinkType.PARENT_TABLE || linkType == LinkType.PHYSICAL_TABLE)) { - // delete parent->child link for views + // Populate the delete mutations for parent->child link for the child view in question, + // which we issue to SYSTEM.CHILD_LINK later Cell parentTenantIdCell = MetaDataUtil.getCell(results, PhoenixDatabaseMetaData.PARENT_TENANT_ID_BYTES); PName parentTenantId = parentTenantIdCell != null ? PNameFactory.newName(parentTenantIdCell.getValueArray(), parentTenantIdCell.getValueOffset(), parentTenantIdCell.getValueLength()) : null; byte[] linkKey = MetaDataUtil.getChildLinkKey(parentTenantId, table.getParentSchemaName(), table.getParentTableName(), table.getTenantId(), table.getName()); @@ -2604,7 +2596,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso throw new IllegalStateException(msg); } } - mutateRowsWithLocks(region, localMutations, Collections.<byte[]>emptySet(), HConstants.NO_NONCE, HConstants.NO_NONCE); + mutateRowsWithLocks(this.accessCheckEnabled, region, localMutations, Collections.<byte[]>emptySet(), + HConstants.NO_NONCE, HConstants.NO_NONCE); // Invalidate from cache for (ImmutableBytesPtr invalidateKey : invalidateList) { metaDataCache.invalidate(invalidateKey); @@ -3282,8 +3275,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso if (setRowKeyOrderOptimizableCell) { UpgradeUtil.addRowKeyOrderOptimizableCell(tableMetadata, key, timeStamp); } - mutateRowsWithLocks(region, tableMetadata, Collections.<byte[]>emptySet(), HConstants.NO_NONCE, - HConstants.NO_NONCE); + mutateRowsWithLocks(this.accessCheckEnabled, region, tableMetadata, Collections.<byte[]>emptySet(), + HConstants.NO_NONCE, HConstants.NO_NONCE); // Invalidate from cache Cache<ImmutableBytesPtr, PMetaDataEntity> metaDataCache = GlobalCache.getInstance(this.env).getMetaDataCache(); @@ -3533,7 +3526,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso } // Don't store function info for temporary functions. if (!temporaryFunction) { - mutateRowsWithLocks(region, functionMetaData, Collections.<byte[]>emptySet(), HConstants.NO_NONCE, HConstants.NO_NONCE); + mutateRowsWithLocks(this.accessCheckEnabled, region, functionMetaData, + Collections.<byte[]>emptySet(), HConstants.NO_NONCE, HConstants.NO_NONCE); } // Invalidate the cache - the next getFunction call will add it @@ -3586,7 +3580,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso done.run(MetaDataMutationResult.toProto(result)); return; } - mutateRowsWithLocks(region, functionMetaData, Collections.<byte[]>emptySet(), HConstants.NO_NONCE, HConstants.NO_NONCE); + mutateRowsWithLocks(this.accessCheckEnabled, region, functionMetaData, Collections.<byte[]>emptySet(), + HConstants.NO_NONCE, HConstants.NO_NONCE); Cache<ImmutableBytesPtr, PMetaDataEntity> metaDataCache = GlobalCache.getInstance(this.env).getMetaDataCache(); long currentTime = MetaDataUtil.getClientTimeStamp(functionMetaData); @@ -3696,8 +3691,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso return; } } - mutateRowsWithLocks(region, schemaMutations, Collections.<byte[]>emptySet(), HConstants.NO_NONCE, - HConstants.NO_NONCE); + mutateRowsWithLocks(this.accessCheckEnabled, region, schemaMutations, Collections.<byte[]>emptySet(), + HConstants.NO_NONCE, HConstants.NO_NONCE); // Invalidate the cache - the next getSchema call will add it Cache<ImmutableBytesPtr, PMetaDataEntity> metaDataCache = @@ -3746,8 +3741,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso done.run(MetaDataMutationResult.toProto(result)); return; } - mutateRowsWithLocks(region, schemaMetaData, Collections.<byte[]>emptySet(), HConstants.NO_NONCE, - HConstants.NO_NONCE); + mutateRowsWithLocks(this.accessCheckEnabled, region, schemaMetaData, Collections.<byte[]>emptySet(), + HConstants.NO_NONCE, HConstants.NO_NONCE); Cache<ImmutableBytesPtr, PMetaDataEntity> metaDataCache = GlobalCache.getInstance(this.env) .getMetaDataCache(); long currentTime = MetaDataUtil.getClientTimeStamp(schemaMetaData); @@ -3809,10 +3804,23 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso } - private void mutateRowsWithLocks(final Region region, final List<Mutation> mutations, final Set<byte[]> rowsToLock, - final long nonceGroup, final long nonce) throws IOException { - // we need to mutate SYSTEM.CATALOG with HBase/login user if access is enabled. - if (this.accessCheckEnabled) { + /** + * Perform atomic mutations on rows within a region + * + * @param accessCheckEnabled Use the login user to mutate rows if enabled + * @param region Region containing rows to be mutated + * @param mutations List of mutations for rows that must be contained within the region + * @param rowsToLock Rows to lock + * @param nonceGroup Optional nonce group of the operation + * @param nonce Optional nonce of the operation + * @throws IOException + */ + static void mutateRowsWithLocks(final boolean accessCheckEnabled, final Region region, + final List<Mutation> mutations, final Set<byte[]> rowsToLock, final long nonceGroup, + final long nonce) throws IOException { + // We need to mutate SYSTEM.CATALOG or SYSTEM.CHILD_LINK with HBase/login user + // if access is enabled. + if (accessCheckEnabled) { User.runAsLoginUser(new PrivilegedExceptionAction<Void>() { @Override public Void run() throws Exception { diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointObserver.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointObserver.java index 86b8bf1..629f00b 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointObserver.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointObserver.java @@ -65,4 +65,7 @@ public interface MetaDataEndpointObserver extends Coprocessor { void preIndexUpdate(ObserverContext<PhoenixMetaDataControllerEnvironment> ctx, String tenantId, String indexName, TableName physicalTableName, TableName parentPhysicalTableName, PIndexState newState) throws IOException; + void preCreateViewAddChildLink(final ObserverContext<PhoenixMetaDataControllerEnvironment> ctx, + final String tableName) throws IOException; + } 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 5b4db91..e217a3b 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 @@ -173,6 +173,9 @@ public abstract class MetaDataProtocol extends MetaDataService { AUTO_PARTITION_SEQUENCE_NOT_FOUND, CANNOT_COERCE_AUTO_PARTITION_ID, TOO_MANY_INDEXES, + UNABLE_TO_CREATE_CHILD_LINK, + UNABLE_TO_UPDATE_PARENT_TABLE, + UNABLE_TO_DELETE_CHILD_LINK, NO_OP }; diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/PhoenixMetaDataCoprocessorHost.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/PhoenixMetaDataCoprocessorHost.java index e089308..e4ee557 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/PhoenixMetaDataCoprocessorHost.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/PhoenixMetaDataCoprocessorHost.java @@ -50,9 +50,10 @@ public class PhoenixMetaDataCoprocessorHost private UserProvider userProvider; public static final String PHOENIX_META_DATA_COPROCESSOR_CONF_KEY = "hbase.coprocessor.phoenix.classes"; - public static final String DEFAULT_PHOENIX_META_DATA_COPROCESSOR_CONF_KEY="org.apache.phoenix.coprocessor.PhoenixAccessController"; + private static final String DEFAULT_PHOENIX_META_DATA_COPROCESSOR_CONF_KEY = + "org.apache.phoenix.coprocessor.PhoenixAccessController"; - public PhoenixMetaDataCoprocessorHost(RegionCoprocessorEnvironment env) { + PhoenixMetaDataCoprocessorHost(RegionCoprocessorEnvironment env) throws IOException { super(null); this.env = env; this.conf = env.getConfiguration(); @@ -72,7 +73,7 @@ public class PhoenixMetaDataCoprocessorHost super(user); } - public void postEnvCall(T env) {} + void postEnvCall(T env) {} } private boolean execOperation( @@ -119,7 +120,7 @@ public class PhoenixMetaDataCoprocessorHost private RegionCoprocessorEnvironment env; - public PhoenixMetaDataControllerEnvironment(RegionCoprocessorEnvironment env, Coprocessor instance, + PhoenixMetaDataControllerEnvironment(RegionCoprocessorEnvironment env, Coprocessor instance, int priority, int sequence, Configuration conf) { super(instance, priority, sequence, conf); this.env = env; @@ -161,7 +162,7 @@ public class PhoenixMetaDataCoprocessorHost return new PhoenixMetaDataControllerEnvironment(env, instance, priority, sequence, conf); } - public void preGetTable(final String tenantId, final String tableName, final TableName physicalTableName) + void preGetTable(final String tenantId, final String tableName, final TableName physicalTableName) throws IOException { execOperation(new CoprocessorOperation<PhoenixMetaDataControllerEnvironment>(getActiveUser()) { @Override @@ -172,7 +173,7 @@ public class PhoenixMetaDataCoprocessorHost }); } - public void preCreateTable(final String tenantId, final String tableName, final TableName physicalTableName, + void preCreateTable(final String tenantId, final String tableName, final TableName physicalTableName, final TableName parentPhysicalTableName, final PTableType tableType, final Set<byte[]> familySet, final Set<TableName> indexes) throws IOException { execOperation(new CoprocessorOperation<PhoenixMetaDataControllerEnvironment>(getActiveUser()) { @@ -185,7 +186,17 @@ public class PhoenixMetaDataCoprocessorHost }); } - public void preDropTable(final String tenantId, final String tableName, final TableName physicalTableName, + void preCreateViewAddChildLink(final String tableName) throws IOException { + execOperation(new CoprocessorOperation<PhoenixMetaDataControllerEnvironment>(getActiveUser()) { + @Override + public void call(MetaDataEndpointObserver observer, + ObserverContext<PhoenixMetaDataControllerEnvironment> ctx) throws IOException { + observer.preCreateViewAddChildLink(this, tableName); + } + }); + } + + void preDropTable(final String tenantId, final String tableName, final TableName physicalTableName, final TableName parentPhysicalTableName, final PTableType tableType, final List<PTable> indexes) throws IOException { execOperation(new CoprocessorOperation<PhoenixMetaDataControllerEnvironment>(getActiveUser()) { @Override @@ -196,7 +207,7 @@ public class PhoenixMetaDataCoprocessorHost }); } - public void preAlterTable(final String tenantId, final String tableName, final TableName physicalTableName, + void preAlterTable(final String tenantId, final String tableName, final TableName physicalTableName, final TableName parentPhysicalTableName, final PTableType type) throws IOException { execOperation(new CoprocessorOperation<PhoenixMetaDataControllerEnvironment>(getActiveUser()) { @Override @@ -207,7 +218,7 @@ public class PhoenixMetaDataCoprocessorHost }); } - public void preGetSchema(final String schemaName) throws IOException { + void preGetSchema(final String schemaName) throws IOException { execOperation(new CoprocessorOperation<PhoenixMetaDataControllerEnvironment>(getActiveUser()) { @Override public void call(MetaDataEndpointObserver observer, @@ -228,7 +239,7 @@ public class PhoenixMetaDataCoprocessorHost }); } - public void preDropSchema(final String schemaName) throws IOException { + void preDropSchema(final String schemaName) throws IOException { execOperation(new CoprocessorOperation<PhoenixMetaDataControllerEnvironment>(getActiveUser()) { @Override public void call(MetaDataEndpointObserver observer, @@ -238,7 +249,7 @@ public class PhoenixMetaDataCoprocessorHost }); } - public void preIndexUpdate(final String tenantId, final String indexName, final TableName physicalTableName, + void preIndexUpdate(final String tenantId, final String indexName, final TableName physicalTableName, final TableName parentPhysicalTableName, final PIndexState newState) throws IOException { execOperation(new CoprocessorOperation<PhoenixMetaDataControllerEnvironment>(getActiveUser()) { @Override diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/generated/ChildLinkMetaDataProtos.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/generated/ChildLinkMetaDataProtos.java new file mode 100644 index 0000000..d3bc1e1 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/generated/ChildLinkMetaDataProtos.java @@ -0,0 +1,786 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: ChildLinkMetaDataService.proto + +package org.apache.phoenix.coprocessor.generated; + +public final class ChildLinkMetaDataProtos { + private ChildLinkMetaDataProtos() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + } + public interface CreateViewAddChildLinkRequestOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // repeated bytes tableMetadataMutations = 1; + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + java.util.List<com.google.protobuf.ByteString> getTableMetadataMutationsList(); + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + int getTableMetadataMutationsCount(); + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + com.google.protobuf.ByteString getTableMetadataMutations(int index); + } + /** + * Protobuf type {@code CreateViewAddChildLinkRequest} + */ + public static final class CreateViewAddChildLinkRequest extends + com.google.protobuf.GeneratedMessage + implements CreateViewAddChildLinkRequestOrBuilder { + // Use CreateViewAddChildLinkRequest.newBuilder() to construct. + private CreateViewAddChildLinkRequest(com.google.protobuf.GeneratedMessage.Builder<?> builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private CreateViewAddChildLinkRequest(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final CreateViewAddChildLinkRequest defaultInstance; + public static CreateViewAddChildLinkRequest getDefaultInstance() { + return defaultInstance; + } + + public CreateViewAddChildLinkRequest getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private CreateViewAddChildLinkRequest( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + tableMetadataMutations_ = new java.util.ArrayList<com.google.protobuf.ByteString>(); + mutable_bitField0_ |= 0x00000001; + } + tableMetadataMutations_.add(input.readBytes()); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + tableMetadataMutations_ = java.util.Collections.unmodifiableList(tableMetadataMutations_); + } + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.internal_static_CreateViewAddChildLinkRequest_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.internal_static_CreateViewAddChildLinkRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest.class, org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest.Builder.class); + } + + public static com.google.protobuf.Parser<CreateViewAddChildLinkRequest> PARSER = + new com.google.protobuf.AbstractParser<CreateViewAddChildLinkRequest>() { + public CreateViewAddChildLinkRequest parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new CreateViewAddChildLinkRequest(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser<CreateViewAddChildLinkRequest> getParserForType() { + return PARSER; + } + + // repeated bytes tableMetadataMutations = 1; + public static final int TABLEMETADATAMUTATIONS_FIELD_NUMBER = 1; + private java.util.List<com.google.protobuf.ByteString> tableMetadataMutations_; + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + public java.util.List<com.google.protobuf.ByteString> + getTableMetadataMutationsList() { + return tableMetadataMutations_; + } + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + public int getTableMetadataMutationsCount() { + return tableMetadataMutations_.size(); + } + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + public com.google.protobuf.ByteString getTableMetadataMutations(int index) { + return tableMetadataMutations_.get(index); + } + + private void initFields() { + tableMetadataMutations_ = java.util.Collections.emptyList(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + for (int i = 0; i < tableMetadataMutations_.size(); i++) { + output.writeBytes(1, tableMetadataMutations_.get(i)); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + { + int dataSize = 0; + for (int i = 0; i < tableMetadataMutations_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeBytesSizeNoTag(tableMetadataMutations_.get(i)); + } + size += dataSize; + size += 1 * getTableMetadataMutationsList().size(); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest)) { + return super.equals(obj); + } + org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest other = (org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest) obj; + + boolean result = true; + result = result && getTableMetadataMutationsList() + .equals(other.getTableMetadataMutationsList()); + result = result && + getUnknownFields().equals(other.getUnknownFields()); + return result; + } + + private int memoizedHashCode = 0; + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + if (getTableMetadataMutationsCount() > 0) { + hash = (37 * hash) + TABLEMETADATAMUTATIONS_FIELD_NUMBER; + hash = (53 * hash) + getTableMetadataMutationsList().hashCode(); + } + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code CreateViewAddChildLinkRequest} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder<Builder> + implements org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.internal_static_CreateViewAddChildLinkRequest_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.internal_static_CreateViewAddChildLinkRequest_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest.class, org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest.Builder.class); + } + + // Construct using org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + tableMetadataMutations_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.internal_static_CreateViewAddChildLinkRequest_descriptor; + } + + public org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest getDefaultInstanceForType() { + return org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest.getDefaultInstance(); + } + + public org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest build() { + org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest buildPartial() { + org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest result = new org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest(this); + int from_bitField0_ = bitField0_; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + tableMetadataMutations_ = java.util.Collections.unmodifiableList(tableMetadataMutations_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.tableMetadataMutations_ = tableMetadataMutations_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest) { + return mergeFrom((org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest other) { + if (other == org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest.getDefaultInstance()) return this; + if (!other.tableMetadataMutations_.isEmpty()) { + if (tableMetadataMutations_.isEmpty()) { + tableMetadataMutations_ = other.tableMetadataMutations_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureTableMetadataMutationsIsMutable(); + tableMetadataMutations_.addAll(other.tableMetadataMutations_); + } + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // repeated bytes tableMetadataMutations = 1; + private java.util.List<com.google.protobuf.ByteString> tableMetadataMutations_ = java.util.Collections.emptyList(); + private void ensureTableMetadataMutationsIsMutable() { + if (!((bitField0_ & 0x00000001) == 0x00000001)) { + tableMetadataMutations_ = new java.util.ArrayList<com.google.protobuf.ByteString>(tableMetadataMutations_); + bitField0_ |= 0x00000001; + } + } + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + public java.util.List<com.google.protobuf.ByteString> + getTableMetadataMutationsList() { + return java.util.Collections.unmodifiableList(tableMetadataMutations_); + } + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + public int getTableMetadataMutationsCount() { + return tableMetadataMutations_.size(); + } + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + public com.google.protobuf.ByteString getTableMetadataMutations(int index) { + return tableMetadataMutations_.get(index); + } + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + public Builder setTableMetadataMutations( + int index, com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + ensureTableMetadataMutationsIsMutable(); + tableMetadataMutations_.set(index, value); + onChanged(); + return this; + } + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + public Builder addTableMetadataMutations(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + ensureTableMetadataMutationsIsMutable(); + tableMetadataMutations_.add(value); + onChanged(); + return this; + } + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + public Builder addAllTableMetadataMutations( + java.lang.Iterable<? extends com.google.protobuf.ByteString> values) { + ensureTableMetadataMutationsIsMutable(); + super.addAll(values, tableMetadataMutations_); + onChanged(); + return this; + } + /** + * <code>repeated bytes tableMetadataMutations = 1;</code> + */ + public Builder clearTableMetadataMutations() { + tableMetadataMutations_ = java.util.Collections.emptyList(); + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:CreateViewAddChildLinkRequest) + } + + static { + defaultInstance = new CreateViewAddChildLinkRequest(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:CreateViewAddChildLinkRequest) + } + + /** + * Protobuf service {@code ChildLinkMetaDataService} + */ + public static abstract class ChildLinkMetaDataService + implements com.google.protobuf.Service { + protected ChildLinkMetaDataService() {} + + public interface Interface { + /** + * <code>rpc createViewAddChildLink(.CreateViewAddChildLinkRequest) returns (.MetaDataResponse);</code> + */ + public abstract void createViewAddChildLink( + com.google.protobuf.RpcController controller, + org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest request, + com.google.protobuf.RpcCallback<org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse> done); + + } + + public static com.google.protobuf.Service newReflectiveService( + final Interface impl) { + return new ChildLinkMetaDataService() { + @java.lang.Override + public void createViewAddChildLink( + com.google.protobuf.RpcController controller, + org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest request, + com.google.protobuf.RpcCallback<org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse> done) { + impl.createViewAddChildLink(controller, request, done); + } + + }; + } + + public static com.google.protobuf.BlockingService + newReflectiveBlockingService(final BlockingInterface impl) { + return new com.google.protobuf.BlockingService() { + public final com.google.protobuf.Descriptors.ServiceDescriptor + getDescriptorForType() { + return getDescriptor(); + } + + public final com.google.protobuf.Message callBlockingMethod( + com.google.protobuf.Descriptors.MethodDescriptor method, + com.google.protobuf.RpcController controller, + com.google.protobuf.Message request) + throws com.google.protobuf.ServiceException { + if (method.getService() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "Service.callBlockingMethod() given method descriptor for " + + "wrong service type."); + } + switch(method.getIndex()) { + case 0: + return impl.createViewAddChildLink(controller, (org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest)request); + default: + throw new java.lang.AssertionError("Can't get here."); + } + } + + public final com.google.protobuf.Message + getRequestPrototype( + com.google.protobuf.Descriptors.MethodDescriptor method) { + if (method.getService() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "Service.getRequestPrototype() given method " + + "descriptor for wrong service type."); + } + switch(method.getIndex()) { + case 0: + return org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest.getDefaultInstance(); + default: + throw new java.lang.AssertionError("Can't get here."); + } + } + + public final com.google.protobuf.Message + getResponsePrototype( + com.google.protobuf.Descriptors.MethodDescriptor method) { + if (method.getService() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "Service.getResponsePrototype() given method " + + "descriptor for wrong service type."); + } + switch(method.getIndex()) { + case 0: + return org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse.getDefaultInstance(); + default: + throw new java.lang.AssertionError("Can't get here."); + } + } + + }; + } + + /** + * <code>rpc createViewAddChildLink(.CreateViewAddChildLinkRequest) returns (.MetaDataResponse);</code> + */ + public abstract void createViewAddChildLink( + com.google.protobuf.RpcController controller, + org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest request, + com.google.protobuf.RpcCallback<org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse> done); + + public static final + com.google.protobuf.Descriptors.ServiceDescriptor + getDescriptor() { + return org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.getDescriptor().getServices().get(0); + } + public final com.google.protobuf.Descriptors.ServiceDescriptor + getDescriptorForType() { + return getDescriptor(); + } + + public final void callMethod( + com.google.protobuf.Descriptors.MethodDescriptor method, + com.google.protobuf.RpcController controller, + com.google.protobuf.Message request, + com.google.protobuf.RpcCallback< + com.google.protobuf.Message> done) { + if (method.getService() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "Service.callMethod() given method descriptor for wrong " + + "service type."); + } + switch(method.getIndex()) { + case 0: + this.createViewAddChildLink(controller, (org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest)request, + com.google.protobuf.RpcUtil.<org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse>specializeCallback( + done)); + return; + default: + throw new java.lang.AssertionError("Can't get here."); + } + } + + public final com.google.protobuf.Message + getRequestPrototype( + com.google.protobuf.Descriptors.MethodDescriptor method) { + if (method.getService() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "Service.getRequestPrototype() given method " + + "descriptor for wrong service type."); + } + switch(method.getIndex()) { + case 0: + return org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest.getDefaultInstance(); + default: + throw new java.lang.AssertionError("Can't get here."); + } + } + + public final com.google.protobuf.Message + getResponsePrototype( + com.google.protobuf.Descriptors.MethodDescriptor method) { + if (method.getService() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "Service.getResponsePrototype() given method " + + "descriptor for wrong service type."); + } + switch(method.getIndex()) { + case 0: + return org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse.getDefaultInstance(); + default: + throw new java.lang.AssertionError("Can't get here."); + } + } + + public static Stub newStub( + com.google.protobuf.RpcChannel channel) { + return new Stub(channel); + } + + public static final class Stub extends org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.ChildLinkMetaDataService implements Interface { + private Stub(com.google.protobuf.RpcChannel channel) { + this.channel = channel; + } + + private final com.google.protobuf.RpcChannel channel; + + public com.google.protobuf.RpcChannel getChannel() { + return channel; + } + + public void createViewAddChildLink( + com.google.protobuf.RpcController controller, + org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest request, + com.google.protobuf.RpcCallback<org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse> done) { + channel.callMethod( + getDescriptor().getMethods().get(0), + controller, + request, + org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse.getDefaultInstance(), + com.google.protobuf.RpcUtil.generalizeCallback( + done, + org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse.class, + org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse.getDefaultInstance())); + } + } + + public static BlockingInterface newBlockingStub( + com.google.protobuf.BlockingRpcChannel channel) { + return new BlockingStub(channel); + } + + public interface BlockingInterface { + public org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse createViewAddChildLink( + com.google.protobuf.RpcController controller, + org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest request) + throws com.google.protobuf.ServiceException; + } + + private static final class BlockingStub implements BlockingInterface { + private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) { + this.channel = channel; + } + + private final com.google.protobuf.BlockingRpcChannel channel; + + public org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse createViewAddChildLink( + com.google.protobuf.RpcController controller, + org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest request) + throws com.google.protobuf.ServiceException { + return (org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse) channel.callBlockingMethod( + getDescriptor().getMethods().get(0), + controller, + request, + org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataResponse.getDefaultInstance()); + } + + } + + // @@protoc_insertion_point(class_scope:ChildLinkMetaDataService) + } + + private static com.google.protobuf.Descriptors.Descriptor + internal_static_CreateViewAddChildLinkRequest_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_CreateViewAddChildLinkRequest_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\036ChildLinkMetaDataService.proto\032\025MetaDa" + + "taService.proto\032\014PTable.proto\"?\n\035CreateV" + + "iewAddChildLinkRequest\022\036\n\026tableMetadataM" + + "utations\030\001 \003(\0142g\n\030ChildLinkMetaDataServi" + + "ce\022K\n\026createViewAddChildLink\022\036.CreateVie" + + "wAddChildLinkRequest\032\021.MetaDataResponseB" + + "K\n(org.apache.phoenix.coprocessor.genera" + + "tedB\027ChildLinkMetaDataProtosH\001\210\001\001\240\001\001" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + internal_static_CreateViewAddChildLinkRequest_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_CreateViewAddChildLinkRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_CreateViewAddChildLinkRequest_descriptor, + new java.lang.String[] { "TableMetadataMutations", }); + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + org.apache.phoenix.coprocessor.generated.MetaDataProtos.getDescriptor(), + org.apache.phoenix.coprocessor.generated.PTableProtos.getDescriptor(), + }, assigner); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/generated/MetaDataProtos.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/generated/MetaDataProtos.java index ca8b20c..28b58c6 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/generated/MetaDataProtos.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/generated/MetaDataProtos.java @@ -113,6 +113,10 @@ public final class MetaDataProtos { * <code>UNABLE_TO_UPDATE_PARENT_TABLE = 24;</code> */ UNABLE_TO_UPDATE_PARENT_TABLE(24, 24), + /** + * <code>UNABLE_TO_DELETE_CHILD_LINK = 25;</code> + */ + UNABLE_TO_DELETE_CHILD_LINK(25, 25), ; /** @@ -215,6 +219,10 @@ public final class MetaDataProtos { * <code>UNABLE_TO_UPDATE_PARENT_TABLE = 24;</code> */ public static final int UNABLE_TO_UPDATE_PARENT_TABLE_VALUE = 24; + /** + * <code>UNABLE_TO_DELETE_CHILD_LINK = 25;</code> + */ + public static final int UNABLE_TO_DELETE_CHILD_LINK_VALUE = 25; public final int getNumber() { return value; } @@ -246,6 +254,7 @@ public final class MetaDataProtos { case 22: return TOO_MANY_INDEXES; case 23: return UNABLE_TO_CREATE_CHILD_LINK; case 24: return UNABLE_TO_UPDATE_PARENT_TABLE; + case 25: return UNABLE_TO_DELETE_CHILD_LINK; default: return null; } } @@ -18039,7 +18048,7 @@ public final class MetaDataProtos { "cheRequest\022\020\n\010tenantId\030\001 \002(\014\022\022\n\nschemaNa" + "me\030\002 \002(\014\022\021\n\ttableName\030\003 \002(\014\022\027\n\017clientTim" + "estamp\030\004 \002(\003\022\025\n\rclientVersion\030\005 \001(\005\"\035\n\033C" + - "learTableFromCacheResponse*\271\005\n\014MutationC" + + "learTableFromCacheResponse*\332\005\n\014MutationC" + "ode\022\030\n\024TABLE_ALREADY_EXISTS\020\000\022\023\n\017TABLE_N" + "OT_FOUND\020\001\022\024\n\020COLUMN_NOT_FOUND\020\002\022\031\n\025COLU", "MN_ALREADY_EXISTS\020\003\022\035\n\031CONCURRENT_TABLE_" + @@ -18057,30 +18066,31 @@ public final class MetaDataProtos { "#\n\037CANNOT_COERCE_AUTO_PARTITION_ID\020\025\022\024\n\020" + "TOO_MANY_INDEXES\020\026\022\037\n\033UNABLE_TO_CREATE_C" + "HILD_LINK\020\027\022!\n\035UNABLE_TO_UPDATE_PARENT_T" + - "ABLE\020\0302\345\006\n\017MetaDataService\022/\n\010getTable\022\020" + - ".GetTableRequest\032\021.MetaDataResponse\0227\n\014g" + - "etFunctions\022\024.GetFunctionsRequest\032\021.Meta" + - "DataResponse\0221\n\tgetSchema\022\021.GetSchemaReq" + - "uest\032\021.MetaDataResponse\0225\n\013createTable\022\023", - ".CreateTableRequest\032\021.MetaDataResponse\022;" + - "\n\016createFunction\022\026.CreateFunctionRequest" + - "\032\021.MetaDataResponse\0227\n\014createSchema\022\024.Cr" + - "eateSchemaRequest\032\021.MetaDataResponse\0221\n\t" + - "dropTable\022\021.DropTableRequest\032\021.MetaDataR" + - "esponse\0223\n\ndropSchema\022\022.DropSchemaReques" + - "t\032\021.MetaDataResponse\0227\n\014dropFunction\022\024.D" + - "ropFunctionRequest\032\021.MetaDataResponse\0221\n" + - "\taddColumn\022\021.AddColumnRequest\032\021.MetaData" + - "Response\0223\n\ndropColumn\022\022.DropColumnReque", - "st\032\021.MetaDataResponse\022?\n\020updateIndexStat" + - "e\022\030.UpdateIndexStateRequest\032\021.MetaDataRe" + - "sponse\0225\n\nclearCache\022\022.ClearCacheRequest" + - "\032\023.ClearCacheResponse\0225\n\ngetVersion\022\022.Ge" + - "tVersionRequest\032\023.GetVersionResponse\022P\n\023" + - "clearTableFromCache\022\033.ClearTableFromCach" + - "eRequest\032\034.ClearTableFromCacheResponseBB" + - "\n(org.apache.phoenix.coprocessor.generat" + - "edB\016MetaDataProtosH\001\210\001\001\240\001\001" + "ABLE\020\030\022\037\n\033UNABLE_TO_DELETE_CHILD_LINK\020\0312" + + "\345\006\n\017MetaDataService\022/\n\010getTable\022\020.GetTab" + + "leRequest\032\021.MetaDataResponse\0227\n\014getFunct" + + "ions\022\024.GetFunctionsRequest\032\021.MetaDataRes" + + "ponse\0221\n\tgetSchema\022\021.GetSchemaRequest\032\021.", + "MetaDataResponse\0225\n\013createTable\022\023.Create" + + "TableRequest\032\021.MetaDataResponse\022;\n\016creat" + + "eFunction\022\026.CreateFunctionRequest\032\021.Meta" + + "DataResponse\0227\n\014createSchema\022\024.CreateSch" + + "emaRequest\032\021.MetaDataResponse\0221\n\tdropTab" + + "le\022\021.DropTableRequest\032\021.MetaDataResponse" + + "\0223\n\ndropSchema\022\022.DropSchemaRequest\032\021.Met" + + "aDataResponse\0227\n\014dropFunction\022\024.DropFunc" + + "tionRequest\032\021.MetaDataResponse\0221\n\taddCol" + + "umn\022\021.AddColumnRequest\032\021.MetaDataRespons", + "e\0223\n\ndropColumn\022\022.DropColumnRequest\032\021.Me" + + "taDataResponse\022?\n\020updateIndexState\022\030.Upd" + + "ateIndexStateRequest\032\021.MetaDataResponse\022" + + "5\n\nclearCache\022\022.ClearCacheRequest\032\023.Clea" + + "rCacheResponse\0225\n\ngetVersion\022\022.GetVersio" + + "nRequest\032\023.GetVersionResponse\022P\n\023clearTa" + + "bleFromCache\022\033.ClearTableFromCacheReques" + + "t\032\034.ClearTableFromCacheResponseBB\n(org.a" + + "pache.phoenix.coprocessor.generatedB\016Met" + + "aDataProtosH\001\210\001\001\240\001\001" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { diff --git a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java index af97d92..878f442 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java @@ -35,6 +35,7 @@ import org.apache.phoenix.schema.ConcurrentTableMutationException; import org.apache.phoenix.schema.FunctionAlreadyExistsException; import org.apache.phoenix.schema.FunctionNotFoundException; import org.apache.phoenix.schema.IndexNotFoundException; +import org.apache.phoenix.schema.PTable; import org.apache.phoenix.schema.PTableType; import org.apache.phoenix.schema.ReadOnlyTableException; import org.apache.phoenix.schema.SchemaAlreadyExistsException; @@ -410,6 +411,12 @@ public enum SQLExceptionCode { CANNOT_SET_GUIDE_POST_WIDTH(1139, "XCL39", "Guide post width can only be set on base data tables"), CANNOT_CREATE_VIEWS_ON_SYSTEM_TABLES(1141, "XCL41", "Cannot create views on tables of type" + PTableType.SYSTEM), + UNABLE_TO_CREATE_CHILD_LINK(1142, "XCL42", "Error creating parent-child link (Link type=" + + PTable.LinkType.CHILD_TABLE + ") for view"), + UNABLE_TO_UPDATE_PARENT_TABLE(1143, "XCL43", "Error Updating the parent table"), + UNABLE_TO_DELETE_CHILD_LINK(1144, "XCL44", "Error deleting parent-child link (Link type=" + + PTable.LinkType.CHILD_TABLE + ") for view"), + /** * Implementation defined class. Phoenix internal error. (errorcode 20, sqlstate INT). */ diff --git a/phoenix-core/src/main/java/org/apache/phoenix/protobuf/ProtobufUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/protobuf/ProtobufUtil.java index d15749d..45f43e1 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/protobuf/ProtobufUtil.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/protobuf/ProtobufUtil.java @@ -30,6 +30,7 @@ import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto; import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType; import org.apache.hadoop.hbase.util.ByteStringer; import org.apache.hadoop.util.StringUtils; +import org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest; import org.apache.phoenix.coprocessor.generated.MetaDataProtos; import org.apache.phoenix.coprocessor.generated.PTableProtos; import org.apache.phoenix.coprocessor.generated.ServerCachingProtos; @@ -107,6 +108,11 @@ public class ProtobufUtil { return getMutations(request.getTableMetadataMutationsList()); } + public static List<Mutation> getMutations(CreateViewAddChildLinkRequest request) + throws IOException { + return getMutations(request.getTableMetadataMutationsList()); + } + /** * Each ByteString entry is a byte array serialized from MutationProto instance * @param mutations 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 fd9092f..a932d59 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 @@ -127,6 +127,7 @@ import org.apache.hadoop.hbase.client.Increment; import org.apache.hadoop.hbase.client.Mutation; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.client.coprocessor.Batch; import org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint; import org.apache.hadoop.hbase.coprocessor.RegionObserver; @@ -146,6 +147,7 @@ import org.apache.hadoop.hbase.util.VersionInfo; import org.apache.hadoop.hbase.zookeeper.ZKConfig; import org.apache.hadoop.ipc.RemoteException; import org.apache.phoenix.compile.MutationPlan; +import org.apache.phoenix.coprocessor.ChildLinkMetaDataEndpoint; import org.apache.phoenix.coprocessor.GroupedAggregateRegionObserver; import org.apache.phoenix.coprocessor.MetaDataEndpointImpl; import org.apache.phoenix.coprocessor.MetaDataProtocol; @@ -157,6 +159,8 @@ import org.apache.phoenix.coprocessor.SequenceRegionObserver; import org.apache.phoenix.coprocessor.ServerCachingEndpointImpl; import org.apache.phoenix.coprocessor.TaskRegionObserver; import org.apache.phoenix.coprocessor.UngroupedAggregateRegionObserver; +import org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.CreateViewAddChildLinkRequest; +import org.apache.phoenix.coprocessor.generated.ChildLinkMetaDataProtos.ChildLinkMetaDataService; import org.apache.phoenix.coprocessor.generated.MetaDataProtos; import org.apache.phoenix.coprocessor.generated.MetaDataProtos.AddColumnRequest; import org.apache.phoenix.coprocessor.generated.MetaDataProtos.ClearCacheRequest; @@ -1018,8 +1022,12 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement } else if (SchemaUtil.isTaskTable(tableName)) { if(!descriptor.hasCoprocessor(TaskRegionObserver.class.getName())) { descriptor.addCoprocessor(TaskRegionObserver.class.getName(), null, priority, null); + } + } else if (SchemaUtil.isChildLinkTable(tableName)) { + if (!descriptor.hasCoprocessor(ChildLinkMetaDataEndpoint.class.getName())) { + descriptor.addCoprocessor(ChildLinkMetaDataEndpoint.class.getName(), null, priority, null); + } } - } if (isTransactional) { Class<? extends RegionObserver> coprocessorClass = provider.getTransactionProvider().getCoprocessor(); @@ -1524,6 +1532,30 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement } /** + * Invoke the SYSTEM.CHILD_LINK metadata coprocessor endpoint + * @param parentTableKey key corresponding to the parent of the view + * @param callable used to invoke the coprocessor endpoint to write links from a parent to its child view + * @return result of invoking the coprocessor endpoint + * @throws SQLException + */ + private MetaDataMutationResult childLinkMetaDataCoprocessorExec(byte[] parentTableKey, + Batch.Call<ChildLinkMetaDataService, MetaDataResponse> callable) throws SQLException { + try (Table htable = this.getTable(SchemaUtil.getPhysicalName( + PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_NAME_BYTES, this.getProps()).getName())) + { + final Map<byte[], MetaDataResponse> results = + htable.coprocessorService(ChildLinkMetaDataService.class, parentTableKey, parentTableKey, callable); + assert(results.size() == 1); + MetaDataResponse result = results.values().iterator().next(); + return MetaDataMutationResult.constructFromProto(result); + } catch (IOException e) { + throw ServerUtil.parseServerException(e); + } catch (Throwable t) { + throw new SQLException(t); + } + } + + /** * Invoke meta data coprocessor with one retry if the key was found to not be in the regions * (due to a table split) */ @@ -1660,6 +1692,7 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement byte[][] splits, boolean isNamespaceMapped, final boolean allocateIndexId, final boolean isDoNotUpgradePropSet, final PTable parentTable) throws SQLException { + final List<Mutation> childLinkMutations = MetaDataUtil.removeChildLinkMutations(tableMetaData); byte[][] rowKeyMetadata = new byte[3][]; Mutation m = MetaDataUtil.getPutOnlyTableHeaderRow(tableMetaData); byte[] key = m.getRow(); @@ -1667,7 +1700,7 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement byte[] tenantIdBytes = rowKeyMetadata[PhoenixDatabaseMetaData.TENANT_ID_INDEX]; byte[] schemaBytes = rowKeyMetadata[PhoenixDatabaseMetaData.SCHEMA_NAME_INDEX]; byte[] tableBytes = rowKeyMetadata[PhoenixDatabaseMetaData.TABLE_NAME_INDEX]; - byte[] tableName = physicalTableName != null ? physicalTableName : + byte[] physicalTableNameBytes = physicalTableName != null ? physicalTableName : SchemaUtil.getPhysicalHBaseTableName(schemaBytes, tableBytes, isNamespaceMapped).getBytes(); boolean localIndexTable = false; for(Pair<byte[], Map<String, Object>> family: families) { @@ -1676,10 +1709,12 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement break; } } - if ((tableType == PTableType.VIEW && physicalTableName != null) || (tableType != PTableType.VIEW && (physicalTableName == null || localIndexTable))) { + if ((tableType == PTableType.VIEW && physicalTableName != null) || + (tableType != PTableType.VIEW && (physicalTableName == null || localIndexTable))) { // For views this will ensure that metadata already exists // For tables and indexes, this will create the metadata if it doesn't already exist - ensureTableCreated(tableName, tableType, tableProps, families, splits, true, isNamespaceMapped, isDoNotUpgradePropSet); + ensureTableCreated(physicalTableNameBytes, tableType, tableProps, families, splits, true, + isNamespaceMapped, isDoNotUpgradePropSet); } ImmutableBytesWritable ptr = new ImmutableBytesWritable(); if (tableType == PTableType.INDEX) { // Index on view @@ -1711,18 +1746,56 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement familiesPlusDefault.add(new Pair<byte[],Map<String,Object>>(defaultCF,Collections.<String,Object>emptyMap())); } ensureViewIndexTableCreated( - tableName, tableProps, familiesPlusDefault, MetaDataUtil.isSalted(m, kvBuilder, ptr) ? splits : null, + physicalTableNameBytes, tableProps, familiesPlusDefault, + MetaDataUtil.isSalted(m, kvBuilder, ptr) ? splits : null, MetaDataUtil.getClientTimeStamp(m), isNamespaceMapped); } + // Avoid the client-server RPC if this is not a view creation + if (!childLinkMutations.isEmpty()) { + // Send mutations for parent-child links to SYSTEM.CHILD_LINK + // We invoke this using the parent table's key since child links are keyed by parent + final MetaDataMutationResult result = childLinkMetaDataCoprocessorExec(SchemaUtil.getTableKey(parentTable), + new Batch.Call<ChildLinkMetaDataService, MetaDataResponse>() { + @Override + public MetaDataResponse call(ChildLinkMetaDataService instance) throws IOException { + ServerRpcController controller = new ServerRpcController(); + BlockingRpcCallback<MetaDataResponse> rpcCallback = + new BlockingRpcCallback<>(); + CreateViewAddChildLinkRequest.Builder builder = + CreateViewAddChildLinkRequest.newBuilder(); + for (Mutation m: childLinkMutations) { + MutationProto mp = ProtobufUtil.toProto(m); + builder.addTableMetadataMutations(mp.toByteString()); + } + CreateViewAddChildLinkRequest build = builder.build(); + instance.createViewAddChildLink(controller, build, rpcCallback); + if (controller.getFailedOn() != null) { + throw controller.getFailedOn(); + } + return rpcCallback.get(); + } + } ); + + switch (result.getMutationCode()) { + case UNABLE_TO_CREATE_CHILD_LINK: + throw new SQLExceptionInfo.Builder(SQLExceptionCode.UNABLE_TO_CREATE_CHILD_LINK) + .setSchemaName(Bytes.toString(schemaBytes)) + .setTableName(Bytes.toString(physicalTableNameBytes)).build().buildException(); + default: + break; + } + } + + // Send the remaining metadata mutations to SYSTEM.CATALOG byte[] tableKey = SchemaUtil.getTableKey(tenantIdBytes, schemaBytes, tableBytes); - MetaDataMutationResult result = metaDataCoprocessorExec(tableKey, + return metaDataCoprocessorExec(tableKey, new Batch.Call<MetaDataService, MetaDataResponse>() { @Override public MetaDataResponse call(MetaDataService instance) throws IOException { ServerRpcController controller = new ServerRpcController(); BlockingRpcCallback<MetaDataResponse> rpcCallback = - new BlockingRpcCallback<MetaDataResponse>(); + new BlockingRpcCallback<>(); CreateTableRequest.Builder builder = CreateTableRequest.newBuilder(); for (Mutation m : tableMetaData) { MutationProto mp = ProtobufUtil.toProto(m); @@ -1743,7 +1816,6 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement return rpcCallback.get(); } }); - return result; } @Override diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java index 5ae53bb..d290333 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java @@ -78,6 +78,7 @@ import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.STORE_NULLS; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYNC_INDEX_CREATED_DATE; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_TABLE; +import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CHILD_LINK_TABLE; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_FUNCTION_TABLE; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_NAME; import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SCHEM; @@ -97,7 +98,6 @@ import static org.apache.phoenix.query.QueryConstants.BASE_TABLE_BASE_COLUMN_COU import static org.apache.phoenix.query.QueryConstants.DEFAULT_COLUMN_FAMILY; import static org.apache.phoenix.query.QueryConstants.ENCODED_CQ_COUNTER_INITIAL_VALUE; import static org.apache.phoenix.query.QueryServices.DROP_METADATA_ATTRIB; -import static org.apache.phoenix.query.QueryServices.LONG_VIEW_INDEX_ENABLED_ATTRIB; import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_DROP_METADATA; import static org.apache.phoenix.query.QueryServicesOptions.DEFAULT_RUN_UPDATE_STATS_ASYNC; import static org.apache.phoenix.schema.PTable.EncodedCQCounter.NULL_COUNTER; @@ -2896,6 +2896,11 @@ public class MetaDataClient { .setSchemaName(SchemaUtil.getSchemaNameFromFullName(parent.getPhysicalName().getString())) .setTableName(SchemaUtil.getTableNameFromFullName(parent.getPhysicalName().getString())).build() .buildException(); + case UNABLE_TO_UPDATE_PARENT_TABLE: + throw new SQLExceptionInfo.Builder(SQLExceptionCode.UNABLE_TO_UPDATE_PARENT_TABLE) + .setSchemaName(SchemaUtil.getSchemaNameFromFullName(parent.getPhysicalName().getString())) + .setTableName(SchemaUtil.getTableNameFromFullName(parent.getPhysicalName().getString())).build() + .buildException(); default: // If the parent table of the view has the auto partition sequence name attribute, // set the view statement and relevant partition column attributes correctly @@ -3141,8 +3146,10 @@ public class MetaDataClient { throw new NewerTableAlreadyExistsException(schemaName, tableName, result.getTable()); case UNALLOWED_TABLE_MUTATION: throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_MUTATE_TABLE) - - .setSchemaName(schemaName).setTableName(tableName).build().buildException(); + .setSchemaName(schemaName).setTableName(tableName).build().buildException(); + case UNABLE_TO_DELETE_CHILD_LINK: + throw new SQLExceptionInfo.Builder(SQLExceptionCode.UNABLE_TO_DELETE_CHILD_LINK) + .setSchemaName(schemaName).setTableName(tableName).build().buildException(); default: connection.removeTable(tenantId, SchemaUtil.getTableName(schemaName, tableName), parentTableName, result.getMutationTime()); diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java index 239018b..dd5ccda 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java @@ -906,10 +906,16 @@ public class MetaDataUtil { byte[] physicalTableName = Bytes.toBytes(SchemaUtil.getTableNameFromFullName(view.getPhysicalName().getString())); return SchemaUtil.getTableKey(ByteUtil.EMPTY_BYTE_ARRAY, physicalTableSchemaName, physicalTableName); } - - public static List<Mutation> removeChildLinks(List<Mutation> catalogMutations) { - List<Mutation> childLinks = Lists.newArrayList(); - Iterator<Mutation> iter = catalogMutations.iterator(); + + /** + * Extract mutations of link type {@link PTable.LinkType#CHILD_TABLE} from the list of mutations. + * The child link mutations will be sent to SYSTEM.CHILD_LINK and other mutations to SYSTEM.CATALOG + * @param metadataMutations total list of mutations + * @return list of mutations pertaining to parent-child links + */ + public static List<Mutation> removeChildLinkMutations(List<Mutation> metadataMutations) { + List<Mutation> childLinkMutations = Lists.newArrayList(); + Iterator<Mutation> iter = metadataMutations.iterator(); while (iter.hasNext()) { Mutation m = iter.next(); for (KeyValue kv : m.getFamilyMap().get(PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES)) { @@ -920,12 +926,12 @@ public class MetaDataUtil { && ((Bytes.compareTo(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength(), LinkType.CHILD_TABLE.getSerializedValueAsByteArray(), 0, LinkType.CHILD_TABLE.getSerializedValueAsByteArray().length) == 0))) { - childLinks.add(m); + childLinkMutations.add(m); iter.remove(); } } } - return childLinks; + return childLinkMutations; } public static IndexType getIndexType(List<Mutation> tableMetaData, KeyValueBuilder builder, diff --git a/phoenix-protocol/src/main/ChildLinkMetaDataService.proto b/phoenix-protocol/src/main/ChildLinkMetaDataService.proto new file mode 100644 index 0000000..046397c --- /dev/null +++ b/phoenix-protocol/src/main/ChildLinkMetaDataService.proto @@ -0,0 +1,36 @@ +/* + * 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. + */ + +option java_package = "org.apache.phoenix.coprocessor.generated"; +option java_outer_classname = "ChildLinkMetaDataProtos"; +option java_generic_services = true; +option java_generate_equals_and_hash = true; +option optimize_for = SPEED; + +import "MetaDataService.proto"; +import "PTable.proto"; + +message CreateViewAddChildLinkRequest { + repeated bytes tableMetadataMutations = 1; +} + +service ChildLinkMetaDataService { + + rpc createViewAddChildLink(CreateViewAddChildLinkRequest) + returns (MetaDataResponse); +} \ No newline at end of file diff --git a/phoenix-protocol/src/main/MetaDataService.proto b/phoenix-protocol/src/main/MetaDataService.proto index 1227ad6..a30fad7 100644 --- a/phoenix-protocol/src/main/MetaDataService.proto +++ b/phoenix-protocol/src/main/MetaDataService.proto @@ -52,6 +52,7 @@ enum MutationCode { TOO_MANY_INDEXES = 22; UNABLE_TO_CREATE_CHILD_LINK = 23; UNABLE_TO_UPDATE_PARENT_TABLE = 24; + UNABLE_TO_DELETE_CHILD_LINK = 25; }; message SharedTableState {