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.master; 019 020import static org.junit.Assert.assertEquals; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertTrue; 023 024import java.io.IOException; 025import java.util.Arrays; 026import java.util.List; 027 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HBaseTestingUtility; 030import org.apache.hadoop.hbase.HConstants; 031import org.apache.hadoop.hbase.MetaTableAccessor; 032import org.apache.hadoop.hbase.TableName; 033import org.apache.hadoop.hbase.client.Put; 034import org.apache.hadoop.hbase.client.RegionInfo; 035import org.apache.hadoop.hbase.client.RegionInfoBuilder; 036import org.apache.hadoop.hbase.testclassification.LargeTests; 037import org.apache.hadoop.hbase.testclassification.MasterTests; 038import org.apache.hadoop.hbase.util.Bytes; 039import org.junit.After; 040import org.junit.Before; 041import org.junit.ClassRule; 042import org.junit.Rule; 043import org.junit.Test; 044import org.junit.experimental.categories.Category; 045import org.junit.rules.TestName; 046import org.slf4j.Logger; 047import org.slf4j.LoggerFactory; 048 049@Category({MasterTests.class, LargeTests.class}) 050public class TestCatalogJanitorCluster { 051 private static final Logger LOG = LoggerFactory.getLogger(TestCatalogJanitorCluster.class); 052 @ClassRule 053 public static final HBaseClassTestRule CLASS_RULE = 054 HBaseClassTestRule.forClass(TestCatalogJanitorCluster.class); 055 056 @Rule 057 public final TestName name = new TestName(); 058 059 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 060 private static final TableName T1 = TableName.valueOf("t1"); 061 private static final TableName T2 = TableName.valueOf("t2"); 062 private static final TableName T3 = TableName.valueOf("t3"); 063 064 @Before 065 public void before() throws Exception { 066 TEST_UTIL.startMiniCluster(); 067 TEST_UTIL.createMultiRegionTable(T1, new byte [][] {HConstants.CATALOG_FAMILY}); 068 TEST_UTIL.createMultiRegionTable(T2, new byte [][] {HConstants.CATALOG_FAMILY}); 069 TEST_UTIL.createMultiRegionTable(T3, new byte [][] {HConstants.CATALOG_FAMILY}); 070 } 071 072 @After 073 public void after() throws Exception { 074 TEST_UTIL.shutdownMiniCluster(); 075 } 076 077 /** 078 * Fat method where we start with a fat hbase:meta and then gradually intro 079 * problems running catalogjanitor for each to ensure it triggers complaint. 080 * Do one big method because takes a while to build up the context we need. 081 * We create three tables and then make holes, overlaps, add unknown servers 082 * and empty out regioninfo columns. Each should up counts in the 083 * CatalogJanitor.Report produced. 084 */ 085 @Test 086 public void testConsistency() throws IOException { 087 CatalogJanitor janitor = TEST_UTIL.getHBaseCluster().getMaster().getCatalogJanitor(); 088 int gc = janitor.scan(); 089 CatalogJanitor.Report report = janitor.getLastReport(); 090 // Assert no problems. 091 assertTrue(report.isEmpty()); 092 // Now remove first region in table t2 to see if catalogjanitor scan notices. 093 List<RegionInfo> t2Ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), T2); 094 MetaTableAccessor.deleteRegionInfo(TEST_UTIL.getConnection(), t2Ris.get(0)); 095 gc = janitor.scan(); 096 report = janitor.getLastReport(); 097 assertFalse(report.isEmpty()); 098 assertEquals(1, report.getHoles().size()); 099 assertTrue(report.getHoles().get(0).getFirst().getTable().equals(T1)); 100 assertTrue(report.getHoles().get(0).getFirst().isLast()); 101 assertTrue(report.getHoles().get(0).getSecond().getTable().equals(T2)); 102 assertEquals(0, report.getOverlaps().size()); 103 // Next, add overlaps to first row in t3 104 List<RegionInfo> t3Ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), T3); 105 RegionInfo ri = t3Ris.get(0); 106 RegionInfo newRi1 = RegionInfoBuilder.newBuilder(ri.getTable()). 107 setStartKey(incrementRow(ri.getStartKey())). 108 setEndKey(incrementRow(ri.getEndKey())).build(); 109 Put p1 = MetaTableAccessor.makePutFromRegionInfo(newRi1, System.currentTimeMillis()); 110 RegionInfo newRi2 = RegionInfoBuilder.newBuilder(newRi1.getTable()). 111 setStartKey(incrementRow(newRi1.getStartKey())). 112 setEndKey(incrementRow(newRi1.getEndKey())).build(); 113 Put p2 = MetaTableAccessor.makePutFromRegionInfo(newRi2, System.currentTimeMillis()); 114 MetaTableAccessor.putsToMetaTable(TEST_UTIL.getConnection(), Arrays.asList(p1, p2)); 115 gc = janitor.scan(); 116 report = janitor.getLastReport(); 117 assertFalse(report.isEmpty()); 118 // We added two overlaps so total three. 119 assertEquals(3, report.getOverlaps().size()); 120 // Assert hole is still there. 121 assertEquals(1, report.getHoles().size()); 122 // Assert other attributes are empty still. 123 assertTrue(report.getEmptyRegionInfo().isEmpty()); 124 assertTrue(report.getUnknownServers().isEmpty()); 125 // Now make bad server in t1. 126 List<RegionInfo> t1Ris = MetaTableAccessor.getTableRegions(TEST_UTIL.getConnection(), T1); 127 RegionInfo t1Ri1 = t1Ris.get(1); 128 Put pServer = new Put(t1Ri1.getRegionName()); 129 pServer.addColumn(MetaTableAccessor.getCatalogFamily(), 130 MetaTableAccessor.getServerColumn(0), Bytes.toBytes("bad.server.example.org:1234")); 131 MetaTableAccessor.putsToMetaTable(TEST_UTIL.getConnection(), Arrays.asList(pServer)); 132 gc = janitor.scan(); 133 report = janitor.getLastReport(); 134 assertFalse(report.isEmpty()); 135 assertEquals(1, report.getUnknownServers().size()); 136 // Test what happens if we blow away an info:server row, if it is null. Should not kill CJ 137 // and we should log the row that had the problem. HBASE-23192. Just make sure we don't 138 // break if this happens. 139 LOG.info("Make null info:server"); 140 Put emptyInfoServerPut = new Put(t1Ri1.getRegionName()); 141 emptyInfoServerPut.addColumn(MetaTableAccessor.getCatalogFamily(), 142 MetaTableAccessor.getServerColumn(0), Bytes.toBytes("")); 143 MetaTableAccessor.putsToMetaTable(TEST_UTIL.getConnection(), Arrays.asList(emptyInfoServerPut)); 144 gc = janitor.scan(); 145 report = janitor.getLastReport(); 146 assertEquals(0, report.getUnknownServers().size()); 147 // Mke an empty regioninfo in t1. 148 RegionInfo t1Ri2 = t1Ris.get(2); 149 Put pEmptyRI = new Put(t1Ri2.getRegionName()); 150 pEmptyRI.addColumn(MetaTableAccessor.getCatalogFamily(), 151 MetaTableAccessor.getRegionInfoColumn(), HConstants.EMPTY_BYTE_ARRAY); 152 MetaTableAccessor.putsToMetaTable(TEST_UTIL.getConnection(), Arrays.asList(pEmptyRI)); 153 gc = janitor.scan(); 154 report = janitor.getLastReport(); 155 assertEquals(1, report.getEmptyRegionInfo().size()); 156 } 157 158 /** 159 * Take last byte and add one to it. 160 */ 161 private static byte [] incrementRow(byte [] row) { 162 if (row.length == 0) { 163 return new byte []{'0'}; 164 } 165 row[row.length - 1] = (byte)(((int)row[row.length - 1]) + 1); 166 return row; 167 } 168}