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.Assert.assertEquals;
021import static org.junit.Assert.assertTrue;
022import static org.junit.Assert.fail;
023
024import java.io.IOException;
025import java.util.Collections;
026import org.apache.hadoop.hbase.client.Admin;
027import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
028import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
029import org.apache.hadoop.hbase.client.RegionInfoBuilder;
030import org.apache.hadoop.hbase.client.TableDescriptor;
031import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
032import org.apache.hadoop.hbase.regionserver.Region;
033import org.apache.hadoop.hbase.testclassification.MediumTests;
034import org.apache.hadoop.hbase.testclassification.MiscTests;
035import org.apache.hadoop.hbase.util.Bytes;
036import org.junit.After;
037import org.junit.Before;
038import org.junit.ClassRule;
039import org.junit.Rule;
040import org.junit.Test;
041import org.junit.experimental.categories.Category;
042import org.junit.rules.TestName;
043
044/**
045 * Test being able to edit hbase:meta.
046 */
047@Category({ MiscTests.class, MediumTests.class })
048public class TestHBaseMetaEdit {
049  @ClassRule
050  public static final HBaseClassTestRule CLASS_RULE =
051      HBaseClassTestRule.forClass(TestHBaseMetaEdit.class);
052  @Rule
053  public TestName name = new TestName();
054  private final static HBaseTestingUtility UTIL = new HBaseTestingUtility();
055
056  @Before
057  public void before() throws Exception {
058    UTIL.startMiniCluster();
059  }
060
061  @After
062  public void after() throws Exception {
063    UTIL.shutdownMiniCluster();
064  }
065
066  // make sure that with every possible way, we get the same meta table descriptor.
067  private TableDescriptor getMetaDescriptor() throws TableNotFoundException, IOException {
068    Admin admin = UTIL.getAdmin();
069    TableDescriptor get = admin.getDescriptor(TableName.META_TABLE_NAME);
070    TableDescriptor list = admin.listTableDescriptors(null, true).stream()
071      .filter(td -> td.isMetaTable()).findAny().get();
072    TableDescriptor listByName =
073      admin.listTableDescriptors(Collections.singletonList(TableName.META_TABLE_NAME)).get(0);
074    TableDescriptor listByNs =
075      admin.listTableDescriptorsByNamespace(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME).stream()
076        .filter(td -> td.isMetaTable()).findAny().get();
077    assertEquals(get, list);
078    assertEquals(get, listByName);
079    assertEquals(get, listByNs);
080    return get;
081  }
082
083  /**
084   * Set versions, set HBASE-16213 indexed block encoding, and add a column family.
085   * Delete the column family. Then try to delete a core hbase:meta family (should fail).
086   * Verify they are all in place by looking at TableDescriptor AND by checking
087   * what the RegionServer sees after opening Region.
088   */
089  @Test
090  public void testEditMeta() throws IOException {
091    Admin admin = UTIL.getAdmin();
092    admin.tableExists(TableName.META_TABLE_NAME);
093    TableDescriptor originalDescriptor = getMetaDescriptor();
094    ColumnFamilyDescriptor cfd = originalDescriptor.getColumnFamily(HConstants.CATALOG_FAMILY);
095    int oldVersions = cfd.getMaxVersions();
096    // Add '1' to current versions count. Set encoding too.
097    cfd = ColumnFamilyDescriptorBuilder.newBuilder(cfd).setMaxVersions(oldVersions + 1).
098        setConfiguration(ColumnFamilyDescriptorBuilder.DATA_BLOCK_ENCODING,
099            DataBlockEncoding.ROW_INDEX_V1.toString()).build();
100    admin.modifyColumnFamily(TableName.META_TABLE_NAME, cfd);
101    byte [] extraColumnFamilyName = Bytes.toBytes("xtra");
102    ColumnFamilyDescriptor newCfd =
103      ColumnFamilyDescriptorBuilder.newBuilder(extraColumnFamilyName).build();
104    admin.addColumnFamily(TableName.META_TABLE_NAME, newCfd);
105    TableDescriptor descriptor = getMetaDescriptor();
106    // Assert new max versions is == old versions plus 1.
107    assertEquals(oldVersions + 1,
108        descriptor.getColumnFamily(HConstants.CATALOG_FAMILY).getMaxVersions());
109    descriptor = getMetaDescriptor();
110    // Assert new max versions is == old versions plus 1.
111    assertEquals(oldVersions + 1,
112        descriptor.getColumnFamily(HConstants.CATALOG_FAMILY).getMaxVersions());
113    assertTrue(descriptor.getColumnFamily(newCfd.getName()) != null);
114    String encoding = descriptor.getColumnFamily(HConstants.CATALOG_FAMILY).getConfiguration().
115        get(ColumnFamilyDescriptorBuilder.DATA_BLOCK_ENCODING);
116    assertEquals(encoding, DataBlockEncoding.ROW_INDEX_V1.toString());
117    Region r = UTIL.getHBaseCluster().getRegionServer(0).
118        getRegion(RegionInfoBuilder.FIRST_META_REGIONINFO.getEncodedName());
119    assertEquals(oldVersions + 1,
120        r.getStore(HConstants.CATALOG_FAMILY).getColumnFamilyDescriptor().getMaxVersions());
121    encoding = r.getStore(HConstants.CATALOG_FAMILY).getColumnFamilyDescriptor().
122        getConfigurationValue(ColumnFamilyDescriptorBuilder.DATA_BLOCK_ENCODING);
123    assertEquals(encoding, DataBlockEncoding.ROW_INDEX_V1.toString());
124    assertTrue(r.getStore(extraColumnFamilyName) != null);
125    // Assert we can't drop critical hbase:meta column family but we can drop any other.
126    admin.deleteColumnFamily(TableName.META_TABLE_NAME, newCfd.getName());
127    descriptor = getMetaDescriptor();
128    assertTrue(descriptor.getColumnFamily(newCfd.getName()) == null);
129    try {
130      admin.deleteColumnFamily(TableName.META_TABLE_NAME, HConstants.CATALOG_FAMILY);
131      fail("Should not reach here");
132    } catch (HBaseIOException hioe) {
133      assertTrue(hioe.getMessage().contains("Delete of hbase:meta"));
134    }
135  }
136}