001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertFalse; 022import static org.junit.jupiter.api.Assertions.assertTrue; 023import static org.junit.jupiter.api.Assertions.fail; 024 025import java.io.IOException; 026import java.util.Collections; 027import org.apache.hadoop.hbase.client.Admin; 028import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 029import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder; 030import org.apache.hadoop.hbase.client.RegionInfoBuilder; 031import org.apache.hadoop.hbase.client.TableDescriptor; 032import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 033import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; 034import org.apache.hadoop.hbase.regionserver.Region; 035import org.apache.hadoop.hbase.testclassification.MediumTests; 036import org.apache.hadoop.hbase.testclassification.MiscTests; 037import org.apache.hadoop.hbase.util.Bytes; 038import org.junit.jupiter.api.AfterEach; 039import org.junit.jupiter.api.BeforeEach; 040import org.junit.jupiter.api.Tag; 041import org.junit.jupiter.api.Test; 042 043/** 044 * Test being able to edit hbase:meta. 045 */ 046@Tag(MiscTests.TAG) 047@Tag(MediumTests.TAG) 048public class TestHBaseMetaEdit { 049 050 private final static HBaseTestingUtil UTIL = new HBaseTestingUtil(); 051 052 @BeforeEach 053 public void before() throws Exception { 054 UTIL.startMiniCluster(); 055 } 056 057 @AfterEach 058 public void after() throws Exception { 059 UTIL.shutdownMiniCluster(); 060 } 061 062 // make sure that with every possible way, we get the same meta table descriptor. 063 private TableDescriptor getMetaDescriptor() throws TableNotFoundException, IOException { 064 Admin admin = UTIL.getAdmin(); 065 TableDescriptor get = admin.getDescriptor(TableName.META_TABLE_NAME); 066 TableDescriptor list = 067 admin.listTableDescriptors(true).stream().filter(td -> td.isMetaTable()).findAny().get(); 068 TableDescriptor listByName = 069 admin.listTableDescriptors(Collections.singletonList(TableName.META_TABLE_NAME)).get(0); 070 TableDescriptor listByNs = 071 admin.listTableDescriptorsByNamespace(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME).stream() 072 .filter(td -> td.isMetaTable()).findAny().get(); 073 assertEquals(get, list); 074 assertEquals(get, listByName); 075 assertEquals(get, listByNs); 076 return get; 077 } 078 079 /** 080 * Set versions, set HBASE-16213 indexed block encoding, and add a column family. Delete the 081 * column family. Then try to delete a core hbase:meta family (should fail). Verify they are all 082 * in place by looking at TableDescriptor AND by checking what the RegionServer sees after opening 083 * Region. 084 */ 085 @Test 086 public void testEditMeta() throws IOException { 087 Admin admin = UTIL.getAdmin(); 088 admin.tableExists(TableName.META_TABLE_NAME); 089 TableDescriptor originalDescriptor = getMetaDescriptor(); 090 ColumnFamilyDescriptor cfd = originalDescriptor.getColumnFamily(HConstants.CATALOG_FAMILY); 091 int oldVersions = cfd.getMaxVersions(); 092 // Add '1' to current versions count. Set encoding too. 093 cfd = ColumnFamilyDescriptorBuilder.newBuilder(cfd).setMaxVersions(oldVersions + 1) 094 .setConfiguration(ColumnFamilyDescriptorBuilder.DATA_BLOCK_ENCODING, 095 DataBlockEncoding.ROW_INDEX_V1.toString()) 096 .build(); 097 admin.modifyColumnFamily(TableName.META_TABLE_NAME, cfd); 098 byte[] extraColumnFamilyName = Bytes.toBytes("xtra"); 099 ColumnFamilyDescriptor newCfd = 100 ColumnFamilyDescriptorBuilder.newBuilder(extraColumnFamilyName).build(); 101 admin.addColumnFamily(TableName.META_TABLE_NAME, newCfd); 102 TableDescriptor descriptor = getMetaDescriptor(); 103 // Assert new max versions is == old versions plus 1. 104 assertEquals(oldVersions + 1, 105 descriptor.getColumnFamily(HConstants.CATALOG_FAMILY).getMaxVersions()); 106 descriptor = getMetaDescriptor(); 107 // Assert new max versions is == old versions plus 1. 108 assertEquals(oldVersions + 1, 109 descriptor.getColumnFamily(HConstants.CATALOG_FAMILY).getMaxVersions()); 110 assertTrue(descriptor.getColumnFamily(newCfd.getName()) != null); 111 String encoding = descriptor.getColumnFamily(HConstants.CATALOG_FAMILY).getConfiguration() 112 .get(ColumnFamilyDescriptorBuilder.DATA_BLOCK_ENCODING); 113 assertEquals(encoding, DataBlockEncoding.ROW_INDEX_V1.toString()); 114 Region r = UTIL.getHBaseCluster().getRegionServer(0) 115 .getRegion(RegionInfoBuilder.FIRST_META_REGIONINFO.getEncodedName()); 116 assertEquals(oldVersions + 1, 117 r.getStore(HConstants.CATALOG_FAMILY).getColumnFamilyDescriptor().getMaxVersions()); 118 encoding = r.getStore(HConstants.CATALOG_FAMILY).getColumnFamilyDescriptor() 119 .getConfigurationValue(ColumnFamilyDescriptorBuilder.DATA_BLOCK_ENCODING); 120 assertEquals(encoding, DataBlockEncoding.ROW_INDEX_V1.toString()); 121 assertTrue(r.getStore(extraColumnFamilyName) != null); 122 // Assert we can't drop critical hbase:meta column family but we can drop any other. 123 admin.deleteColumnFamily(TableName.META_TABLE_NAME, newCfd.getName()); 124 descriptor = getMetaDescriptor(); 125 assertTrue(descriptor.getColumnFamily(newCfd.getName()) == null); 126 try { 127 admin.deleteColumnFamily(TableName.META_TABLE_NAME, HConstants.CATALOG_FAMILY); 128 fail("Should not reach here"); 129 } catch (HBaseIOException hioe) { 130 assertTrue(hioe.getMessage().contains("Delete of hbase:meta")); 131 } 132 } 133 134 /** 135 * Validate whether meta table can be altered as READ only, shouldn't be allowed otherwise it will 136 * break assignment functionalities. See HBASE-24977. 137 */ 138 @Test 139 public void testAlterMetaWithReadOnly() throws IOException { 140 Admin admin = UTIL.getAdmin(); 141 TableDescriptor origMetaTableDesc = admin.getDescriptor(TableName.META_TABLE_NAME); 142 assertFalse(origMetaTableDesc.isReadOnly()); 143 TableDescriptor newTD = 144 TableDescriptorBuilder.newBuilder(origMetaTableDesc).setReadOnly(true).build(); 145 try { 146 admin.modifyTable(newTD); 147 fail("Meta table can't be set as read only"); 148 } catch (Exception e) { 149 assertFalse(admin.getDescriptor(TableName.META_TABLE_NAME).isReadOnly()); 150 } 151 152 // Create a table to check region assignment & meta operation 153 TableName tableName = TableName.valueOf("tempTable"); 154 TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName).setReadOnly(true) 155 .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("f1")).build()) 156 .build(); 157 UTIL.getAdmin().createTable(td); 158 UTIL.deleteTable(tableName); 159 } 160}