Github user twdsilva commented on a diff in the pull request: https://github.com/apache/phoenix/pull/277#discussion_r146659434 --- Diff: phoenix-core/src/it/java/org/apache/phoenix/end2end/MigrateSystemTablesToSystemNamespaceIT.java --- @@ -0,0 +1,399 @@ +/* + * 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.end2end; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hbase.HBaseTestingUtility; +import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.security.UserGroupInformation; +import org.apache.phoenix.coprocessor.MetaDataProtocol; +import org.apache.phoenix.jdbc.PhoenixConnection; +import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData; +import org.apache.phoenix.query.BaseTest; +import org.apache.phoenix.query.ConnectionQueryServices; +import org.apache.phoenix.query.ConnectionQueryServicesImpl; +import org.apache.phoenix.query.QueryConstants; +import org.apache.phoenix.query.QueryServices; +import org.apache.phoenix.schema.PTableType; +import org.apache.phoenix.util.ReadOnlyProps; +import org.apache.phoenix.util.SchemaUtil; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import java.io.IOException; +import java.security.PrivilegedExceptionAction; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import static org.junit.Assert.*; + +@Category(NeedsOwnMiniClusterTest.class) +public class MigrateSystemTablesToSystemNamespaceIT extends BaseTest { + + private static final Set<String> PHOENIX_SYSTEM_TABLES = new HashSet<>(Arrays.asList( + "SYSTEM.CATALOG", "SYSTEM.SEQUENCE", "SYSTEM.STATS", "SYSTEM.FUNCTION", + "SYSTEM.MUTEX")); + private static final Set<String> PHOENIX_NAMESPACE_MAPPED_SYSTEM_TABLES = new HashSet<>( + Arrays.asList("SYSTEM:CATALOG", "SYSTEM:SEQUENCE", "SYSTEM:STATS", "SYSTEM:FUNCTION", + "SYSTEM:MUTEX")); + private static final String SCHEMA_NAME = "MIGRATETEST"; + private static final String TABLE_NAME = + SCHEMA_NAME + "." + MigrateSystemTablesToSystemNamespaceIT.class.getSimpleName().toUpperCase(); + private static final int NUM_RECORDS = 5; + + private HBaseTestingUtility testUtil = null; + private Set<String> hbaseTables; + + // Create Multiple users since Phoenix caches the connection per user + // Migration or upgrade code will run every time for each user. + final UserGroupInformation user1 = + UserGroupInformation.createUserForTesting("user1", new String[0]); + final UserGroupInformation user2 = + UserGroupInformation.createUserForTesting("user2", new String[0]); + final UserGroupInformation user3 = + UserGroupInformation.createUserForTesting("user3", new String[0]); + final UserGroupInformation user4 = + UserGroupInformation.createUserForTesting("user4", new String[0]); + + + @Before + public final void doSetup() throws Exception { + testUtil = new HBaseTestingUtility(); + Configuration conf = testUtil.getConfiguration(); + enableNamespacesOnServer(conf); + testUtil.startMiniCluster(1); + } + + @After + public void tearDownMiniCluster() { + try { + if (testUtil != null) { + testUtil.shutdownMiniCluster(); + testUtil = null; + } + } catch (Exception e) { + // ignore + } + } + + // Tests that client can create and read tables on a fresh HBase cluster with + // system namespace mapping enabled from the start + @Test + public void freshClientsCreateNamespaceMappedSystemTables() throws IOException, InterruptedException { + + user1.doAs(new PrivilegedExceptionAction<Void>() { + @Override + public Void run() throws Exception { + createConnection(getClientPropertiesWithSystemMappingEnabled()); + createTable(getClientPropertiesWithSystemMappingEnabled()); + return null; + } + }); + + hbaseTables = getHBaseTables(); + assertTrue(hbaseTables.containsAll(PHOENIX_NAMESPACE_MAPPED_SYSTEM_TABLES)); + + user1.doAs(new PrivilegedExceptionAction<Void>() { + @Override + public Void run() throws Exception { + createConnection(getClientPropertiesWithSystemMappingEnabled()); + readTable(getClientPropertiesWithSystemMappingEnabled()); + return null; + } + }); + + } + + // Tests that NEWER clients can read tables on HBase cluster after system tables are migrated + @Test + public void migrateSystemTablesInExistingCluster() throws IOException, InterruptedException { + + user1.doAs(new PrivilegedExceptionAction<Void>() { + @Override + public Void run() throws Exception { + createConnection(getClientPropertiesWithSystemMappingDisabled()); + createTable(getClientPropertiesWithSystemMappingDisabled()); + return null; + } + }); + + hbaseTables = getHBaseTables(); + assertTrue(hbaseTables.containsAll(PHOENIX_SYSTEM_TABLES)); + + user2.doAs(new PrivilegedExceptionAction<Void>() { + @Override + public Void run() throws Exception { + createConnection(getClientPropertiesWithSystemMappingEnabled()); + readTable(getClientPropertiesWithSystemMappingEnabled()); + return null; + } + }); + + hbaseTables = getHBaseTables(); + assertTrue(hbaseTables.containsAll(PHOENIX_NAMESPACE_MAPPED_SYSTEM_TABLES)); + } + + // Tests that OLDER clients fail after system tables are migrated + // Clients should be restarted with new properties which are consistent on both client and server + @Test + public void oldClientsAfterSystemTableMigrationShouldFail() throws IOException, InterruptedException { + + user1.doAs(new PrivilegedExceptionAction<Void>() { + @Override + public Void run() throws Exception { + createConnection(getClientPropertiesWithSystemMappingEnabled()); + return null; + } + }); + + hbaseTables = getHBaseTables(); + assertTrue(hbaseTables.size() == PHOENIX_NAMESPACE_MAPPED_SYSTEM_TABLES.size()); + assertTrue(hbaseTables.containsAll(PHOENIX_NAMESPACE_MAPPED_SYSTEM_TABLES)); + + try { + user2.doAs(new PrivilegedExceptionAction<Void>() { + @Override + public Void run() throws Exception { + createConnection(getClientPropertiesWithSystemMappingDisabled()); + return null; + } + }); + fail("Client should not be able to connect to cluster with inconsistent SYSTEM table namespace properties"); + } catch (Exception e) { + //ignore + } + + hbaseTables = getHBaseTables(); + assertTrue(hbaseTables.size() == PHOENIX_NAMESPACE_MAPPED_SYSTEM_TABLES.size()); + assertTrue(hbaseTables.containsAll(PHOENIX_NAMESPACE_MAPPED_SYSTEM_TABLES)); + } + + // Tests that only one client can migrate the system table to system namespace + // Migrate process acquires lock in SYSMUTEX table + @Test + public void onlyOneClientCanMigrate() throws IOException, InterruptedException, SQLException { + + user1.doAs(new PrivilegedExceptionAction<Void>() { + @Override + public Void run() throws Exception { + createConnection(getClientPropertiesWithSystemMappingDisabled()); + return null; + } + }); + + hbaseTables = getHBaseTables(); + assertTrue(hbaseTables.size() == PHOENIX_SYSTEM_TABLES.size()); + assertTrue(hbaseTables.containsAll(PHOENIX_SYSTEM_TABLES)); + + user2.doAs(new PrivilegedExceptionAction<Void>() { + @Override + public Void run() throws Exception { + // Acquire Mutex Lock + changeMutexLock(getClientPropertiesWithSystemMappingDisabled(), true); + return null; + } + }); + + hbaseTables = getHBaseTables(); + assertTrue(hbaseTables.size() == PHOENIX_SYSTEM_TABLES.size()); + assertTrue(hbaseTables.containsAll(PHOENIX_SYSTEM_TABLES)); + + try { + user3.doAs(new PrivilegedExceptionAction<Void>() { + @Override + public Void run() throws Exception { + createConnection(getClientPropertiesWithSystemMappingEnabled()); --- End diff -- Can you verify you get a UpgradeInProgressException?
---