| /* |
| * 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.hadoop.hbase; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.io.IOException; |
| import java.util.Collections; |
| import org.apache.hadoop.hbase.client.Admin; |
| import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; |
| import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; |
| import org.apache.hadoop.hbase.client.RegionInfoBuilder; |
| import org.apache.hadoop.hbase.client.TableDescriptor; |
| import org.apache.hadoop.hbase.client.TableDescriptorBuilder; |
| import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; |
| import org.apache.hadoop.hbase.regionserver.Region; |
| import org.apache.hadoop.hbase.testclassification.MediumTests; |
| import org.apache.hadoop.hbase.testclassification.MiscTests; |
| import org.apache.hadoop.hbase.util.Bytes; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.ClassRule; |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| import org.junit.rules.TestName; |
| |
| /** |
| * Test being able to edit hbase:meta. |
| */ |
| @Category({ MiscTests.class, MediumTests.class }) |
| public class TestHBaseMetaEdit { |
| @ClassRule |
| public static final HBaseClassTestRule CLASS_RULE = |
| HBaseClassTestRule.forClass(TestHBaseMetaEdit.class); |
| @Rule |
| public TestName name = new TestName(); |
| private final static HBaseTestingUtility UTIL = new HBaseTestingUtility(); |
| |
| @Before |
| public void before() throws Exception { |
| UTIL.startMiniCluster(); |
| } |
| |
| @After |
| public void after() throws Exception { |
| UTIL.shutdownMiniCluster(); |
| } |
| |
| // make sure that with every possible way, we get the same meta table descriptor. |
| private TableDescriptor getMetaDescriptor() throws TableNotFoundException, IOException { |
| Admin admin = UTIL.getAdmin(); |
| TableDescriptor get = admin.getDescriptor(TableName.META_TABLE_NAME); |
| TableDescriptor list = |
| admin.listTableDescriptors(true).stream().filter(td -> td.isMetaTable()).findAny().get(); |
| TableDescriptor listByName = |
| admin.listTableDescriptors(Collections.singletonList(TableName.META_TABLE_NAME)).get(0); |
| TableDescriptor listByNs = |
| admin.listTableDescriptorsByNamespace(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME).stream() |
| .filter(td -> td.isMetaTable()).findAny().get(); |
| assertEquals(get, list); |
| assertEquals(get, listByName); |
| assertEquals(get, listByNs); |
| return get; |
| } |
| |
| /** |
| * Set versions, set HBASE-16213 indexed block encoding, and add a column family. |
| * Delete the column family. Then try to delete a core hbase:meta family (should fail). |
| * Verify they are all in place by looking at TableDescriptor AND by checking |
| * what the RegionServer sees after opening Region. |
| */ |
| @Test |
| public void testEditMeta() throws IOException { |
| Admin admin = UTIL.getAdmin(); |
| admin.tableExists(TableName.META_TABLE_NAME); |
| TableDescriptor originalDescriptor = getMetaDescriptor(); |
| ColumnFamilyDescriptor cfd = originalDescriptor.getColumnFamily(HConstants.CATALOG_FAMILY); |
| int oldVersions = cfd.getMaxVersions(); |
| // Add '1' to current versions count. Set encoding too. |
| cfd = ColumnFamilyDescriptorBuilder.newBuilder(cfd).setMaxVersions(oldVersions + 1). |
| setConfiguration(ColumnFamilyDescriptorBuilder.DATA_BLOCK_ENCODING, |
| DataBlockEncoding.ROW_INDEX_V1.toString()).build(); |
| admin.modifyColumnFamily(TableName.META_TABLE_NAME, cfd); |
| byte [] extraColumnFamilyName = Bytes.toBytes("xtra"); |
| ColumnFamilyDescriptor newCfd = |
| ColumnFamilyDescriptorBuilder.newBuilder(extraColumnFamilyName).build(); |
| admin.addColumnFamily(TableName.META_TABLE_NAME, newCfd); |
| TableDescriptor descriptor = getMetaDescriptor(); |
| // Assert new max versions is == old versions plus 1. |
| assertEquals(oldVersions + 1, |
| descriptor.getColumnFamily(HConstants.CATALOG_FAMILY).getMaxVersions()); |
| descriptor = getMetaDescriptor(); |
| // Assert new max versions is == old versions plus 1. |
| assertEquals(oldVersions + 1, |
| descriptor.getColumnFamily(HConstants.CATALOG_FAMILY).getMaxVersions()); |
| assertTrue(descriptor.getColumnFamily(newCfd.getName()) != null); |
| String encoding = descriptor.getColumnFamily(HConstants.CATALOG_FAMILY).getConfiguration(). |
| get(ColumnFamilyDescriptorBuilder.DATA_BLOCK_ENCODING); |
| assertEquals(encoding, DataBlockEncoding.ROW_INDEX_V1.toString()); |
| Region r = UTIL.getHBaseCluster().getRegionServer(0). |
| getRegion(RegionInfoBuilder.FIRST_META_REGIONINFO.getEncodedName()); |
| assertEquals(oldVersions + 1, |
| r.getStore(HConstants.CATALOG_FAMILY).getColumnFamilyDescriptor().getMaxVersions()); |
| encoding = r.getStore(HConstants.CATALOG_FAMILY).getColumnFamilyDescriptor(). |
| getConfigurationValue(ColumnFamilyDescriptorBuilder.DATA_BLOCK_ENCODING); |
| assertEquals(encoding, DataBlockEncoding.ROW_INDEX_V1.toString()); |
| assertTrue(r.getStore(extraColumnFamilyName) != null); |
| // Assert we can't drop critical hbase:meta column family but we can drop any other. |
| admin.deleteColumnFamily(TableName.META_TABLE_NAME, newCfd.getName()); |
| descriptor = getMetaDescriptor(); |
| assertTrue(descriptor.getColumnFamily(newCfd.getName()) == null); |
| try { |
| admin.deleteColumnFamily(TableName.META_TABLE_NAME, HConstants.CATALOG_FAMILY); |
| fail("Should not reach here"); |
| } catch (HBaseIOException hioe) { |
| assertTrue(hioe.getMessage().contains("Delete of hbase:meta")); |
| } |
| } |
| |
| /** |
| * Validate whether meta table can be altered as READ only, shouldn't be allowed otherwise it will |
| * break assignment functionalities. See HBASE-24977. |
| */ |
| @Test |
| public void testAlterMetaWithReadOnly() throws IOException { |
| Admin admin = UTIL.getAdmin(); |
| TableDescriptor origMetaTableDesc = admin.getDescriptor(TableName.META_TABLE_NAME); |
| assertFalse(origMetaTableDesc.isReadOnly()); |
| TableDescriptor newTD = |
| TableDescriptorBuilder.newBuilder(origMetaTableDesc).setReadOnly(true).build(); |
| try { |
| admin.modifyTable(newTD); |
| fail("Meta table can't be set as read only"); |
| } catch (Exception e) { |
| assertFalse(admin.getDescriptor(TableName.META_TABLE_NAME).isReadOnly()); |
| } |
| |
| // Create a table to check region assignment & meta operation |
| TableName tableName = TableName.valueOf("tempTable"); |
| TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName).setReadOnly(true) |
| .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("f1")).build()) |
| .build(); |
| UTIL.getAdmin().createTable(td); |
| UTIL.deleteTable(tableName); |
| } |
| } |