View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.master.normalizer;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.hadoop.hbase.HBaseIOException;
24  import org.apache.hadoop.hbase.HRegionInfo;
25  import org.apache.hadoop.hbase.RegionLoad;
26  import org.apache.hadoop.hbase.ServerName;
27  import org.apache.hadoop.hbase.TableName;
28  import org.apache.hadoop.hbase.master.MasterServices;
29  import org.apache.hadoop.hbase.testclassification.SmallTests;
30  import org.apache.hadoop.hbase.util.Bytes;
31  import org.junit.BeforeClass;
32  import org.junit.Test;
33  import org.junit.experimental.categories.Category;
34  import org.mockito.Mockito;
35  
36  import java.util.ArrayList;
37  import java.util.HashMap;
38  import java.util.List;
39  import java.util.Map;
40  
41  import static org.junit.Assert.assertEquals;
42  import static org.junit.Assert.assertTrue;
43  import static org.mockito.Matchers.any;
44  import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
45  import static org.mockito.Mockito.when;
46  
47  /**
48   * Tests logic of {@link SimpleRegionNormalizer}.
49   */
50  @Category(SmallTests.class)
51  public class TestSimpleRegionNormalizer {
52    private static final Log LOG = LogFactory.getLog(TestSimpleRegionNormalizer.class);
53  
54    private static RegionNormalizer normalizer;
55  
56    // mocks
57    private static MasterServices masterServices;
58  
59    @BeforeClass
60    public static void beforeAllTests() throws Exception {
61      normalizer = new SimpleRegionNormalizer();
62    }
63  
64    @Test
65    public void testNoNormalizationForMetaTable() throws HBaseIOException {
66      TableName testTable = TableName.META_TABLE_NAME;
67      List<HRegionInfo> hris = new ArrayList<>();
68      Map<byte[], Integer> regionSizes = new HashMap<>();
69  
70      setupMocksForNormalizer(regionSizes, hris);
71      List<NormalizationPlan> plans = normalizer.computePlanForTable(testTable);
72      assertTrue(plans == null);
73    }
74  
75    @Test
76    public void testNoNormalizationIfTooFewRegions() throws HBaseIOException {
77      TableName testTable = TableName.valueOf("testSplitOfSmallRegion");
78      List<HRegionInfo> hris = new ArrayList<>();
79      Map<byte[], Integer> regionSizes = new HashMap<>();
80  
81      HRegionInfo hri1 = new HRegionInfo(testTable, Bytes.toBytes("aaa"), Bytes.toBytes("bbb"));
82      hris.add(hri1);
83      regionSizes.put(hri1.getRegionName(), 10);
84  
85      HRegionInfo hri2 = new HRegionInfo(testTable, Bytes.toBytes("bbb"), Bytes.toBytes("ccc"));
86      hris.add(hri2);
87      regionSizes.put(hri2.getRegionName(), 15);
88  
89      setupMocksForNormalizer(regionSizes, hris);
90      List<NormalizationPlan> plans = normalizer.computePlanForTable(testTable);
91      assertTrue(plans == null);
92    }
93  
94    @Test
95    public void testNoNormalizationOnNormalizedCluster() throws HBaseIOException {
96      TableName testTable = TableName.valueOf("testSplitOfSmallRegion");
97      List<HRegionInfo> hris = new ArrayList<>();
98      Map<byte[], Integer> regionSizes = new HashMap<>();
99  
100     HRegionInfo hri1 = new HRegionInfo(testTable, Bytes.toBytes("aaa"), Bytes.toBytes("bbb"));
101     hris.add(hri1);
102     regionSizes.put(hri1.getRegionName(), 10);
103 
104     HRegionInfo hri2 = new HRegionInfo(testTable, Bytes.toBytes("bbb"), Bytes.toBytes("ccc"));
105     hris.add(hri2);
106     regionSizes.put(hri2.getRegionName(), 15);
107 
108     HRegionInfo hri3 = new HRegionInfo(testTable, Bytes.toBytes("ccc"), Bytes.toBytes("ddd"));
109     hris.add(hri3);
110     regionSizes.put(hri3.getRegionName(), 8);
111 
112     HRegionInfo hri4 = new HRegionInfo(testTable, Bytes.toBytes("ddd"), Bytes.toBytes("eee"));
113     hris.add(hri4);
114     regionSizes.put(hri4.getRegionName(), 10);
115 
116     setupMocksForNormalizer(regionSizes, hris);
117     List<NormalizationPlan> plans = normalizer.computePlanForTable(testTable);
118     assertTrue(plans == null);
119   }
120 
121   @Test
122   public void testMergeOfSmallRegions() throws HBaseIOException {
123     TableName testTable = TableName.valueOf("testMergeOfSmallRegions");
124     List<HRegionInfo> hris = new ArrayList<>();
125     Map<byte[], Integer> regionSizes = new HashMap<>();
126 
127     HRegionInfo hri1 = new HRegionInfo(testTable, Bytes.toBytes("aaa"), Bytes.toBytes("bbb"));
128     hris.add(hri1);
129     regionSizes.put(hri1.getRegionName(), 15);
130 
131     HRegionInfo hri2 = new HRegionInfo(testTable, Bytes.toBytes("bbb"), Bytes.toBytes("ccc"));
132     hris.add(hri2);
133     regionSizes.put(hri2.getRegionName(), 5);
134 
135     HRegionInfo hri3 = new HRegionInfo(testTable, Bytes.toBytes("ccc"), Bytes.toBytes("ddd"));
136     hris.add(hri3);
137     regionSizes.put(hri3.getRegionName(), 5);
138 
139     HRegionInfo hri4 = new HRegionInfo(testTable, Bytes.toBytes("ddd"), Bytes.toBytes("eee"));
140     hris.add(hri4);
141     regionSizes.put(hri4.getRegionName(), 15);
142 
143     HRegionInfo hri5 = new HRegionInfo(testTable, Bytes.toBytes("eee"), Bytes.toBytes("fff"));
144     hris.add(hri5);
145     regionSizes.put(hri5.getRegionName(), 16);
146 
147     setupMocksForNormalizer(regionSizes, hris);
148     List<NormalizationPlan> plans = normalizer.computePlanForTable(testTable);
149 
150     NormalizationPlan plan = plans.get(0);
151     assertTrue(plan instanceof MergeNormalizationPlan);
152     assertEquals(hri2, ((MergeNormalizationPlan) plan).getFirstRegion());
153     assertEquals(hri3, ((MergeNormalizationPlan) plan).getSecondRegion());
154   }
155 
156   // Test for situation illustrated in HBASE-14867
157   @Test
158   public void testMergeOfSecondSmallestRegions() throws HBaseIOException {
159     TableName testTable = TableName.valueOf("testMergeOfSmallRegions");
160     List<HRegionInfo> hris = new ArrayList<>();
161     Map<byte[], Integer> regionSizes = new HashMap<>();
162 
163     HRegionInfo hri1 = new HRegionInfo(testTable, Bytes.toBytes("aaa"), Bytes.toBytes("bbb"));
164     hris.add(hri1);
165     regionSizes.put(hri1.getRegionName(), 1);
166 
167     HRegionInfo hri2 = new HRegionInfo(testTable, Bytes.toBytes("bbb"), Bytes.toBytes("ccc"));
168     hris.add(hri2);
169     regionSizes.put(hri2.getRegionName(), 10000);
170 
171     HRegionInfo hri3 = new HRegionInfo(testTable, Bytes.toBytes("ccc"), Bytes.toBytes("ddd"));
172     hris.add(hri3);
173     regionSizes.put(hri3.getRegionName(), 10000);
174 
175     HRegionInfo hri4 = new HRegionInfo(testTable, Bytes.toBytes("ddd"), Bytes.toBytes("eee"));
176     hris.add(hri4);
177     regionSizes.put(hri4.getRegionName(), 10000);
178 
179     HRegionInfo hri5 = new HRegionInfo(testTable, Bytes.toBytes("eee"), Bytes.toBytes("fff"));
180     hris.add(hri5);
181     regionSizes.put(hri5.getRegionName(), 2700);
182 
183     HRegionInfo hri6 = new HRegionInfo(testTable, Bytes.toBytes("fff"), Bytes.toBytes("ggg"));
184     hris.add(hri6);
185     regionSizes.put(hri6.getRegionName(), 2700);
186 
187     setupMocksForNormalizer(regionSizes, hris);
188     List<NormalizationPlan> plans = normalizer.computePlanForTable(testTable);
189     NormalizationPlan plan = plans.get(0);
190 
191     assertTrue(plan instanceof MergeNormalizationPlan);
192     assertEquals(hri5, ((MergeNormalizationPlan) plan).getFirstRegion());
193     assertEquals(hri6, ((MergeNormalizationPlan) plan).getSecondRegion());
194   }
195 
196   @Test
197   public void testMergeOfSmallNonAdjacentRegions() throws HBaseIOException {
198     TableName testTable = TableName.valueOf("testMergeOfSmallRegions");
199     List<HRegionInfo> hris = new ArrayList<>();
200     Map<byte[], Integer> regionSizes = new HashMap<>();
201 
202     HRegionInfo hri1 = new HRegionInfo(testTable, Bytes.toBytes("aaa"), Bytes.toBytes("bbb"));
203     hris.add(hri1);
204     regionSizes.put(hri1.getRegionName(), 15);
205 
206     HRegionInfo hri2 = new HRegionInfo(testTable, Bytes.toBytes("bbb"), Bytes.toBytes("ccc"));
207     hris.add(hri2);
208     regionSizes.put(hri2.getRegionName(), 5);
209 
210     HRegionInfo hri3 = new HRegionInfo(testTable, Bytes.toBytes("ccc"), Bytes.toBytes("ddd"));
211     hris.add(hri3);
212     regionSizes.put(hri3.getRegionName(), 16);
213 
214     HRegionInfo hri4 = new HRegionInfo(testTable, Bytes.toBytes("ddd"), Bytes.toBytes("eee"));
215     hris.add(hri4);
216     regionSizes.put(hri4.getRegionName(), 15);
217 
218     HRegionInfo hri5 = new HRegionInfo(testTable, Bytes.toBytes("ddd"), Bytes.toBytes("eee"));
219     hris.add(hri4);
220     regionSizes.put(hri5.getRegionName(), 5);
221 
222     setupMocksForNormalizer(regionSizes, hris);
223     List<NormalizationPlan> plans = normalizer.computePlanForTable(testTable);
224 
225     assertTrue(plans == null);
226   }
227 
228   @Test
229   public void testSplitOfLargeRegion() throws HBaseIOException {
230     TableName testTable = TableName.valueOf("testSplitOfLargeRegion");
231     List<HRegionInfo> hris = new ArrayList<>();
232     Map<byte[], Integer> regionSizes = new HashMap<>();
233 
234     HRegionInfo hri1 = new HRegionInfo(testTable, Bytes.toBytes("aaa"), Bytes.toBytes("bbb"));
235     hris.add(hri1);
236     regionSizes.put(hri1.getRegionName(), 8);
237 
238     HRegionInfo hri2 = new HRegionInfo(testTable, Bytes.toBytes("bbb"), Bytes.toBytes("ccc"));
239     hris.add(hri2);
240     regionSizes.put(hri2.getRegionName(), 6);
241 
242     HRegionInfo hri3 = new HRegionInfo(testTable, Bytes.toBytes("ccc"), Bytes.toBytes("ddd"));
243     hris.add(hri3);
244     regionSizes.put(hri3.getRegionName(), 10);
245 
246     HRegionInfo hri4 = new HRegionInfo(testTable, Bytes.toBytes("ddd"), Bytes.toBytes("eee"));
247     hris.add(hri4);
248     regionSizes.put(hri4.getRegionName(), 30);
249 
250     setupMocksForNormalizer(regionSizes, hris);
251     List<NormalizationPlan> plans = normalizer.computePlanForTable(testTable);
252     NormalizationPlan plan = plans.get(0);
253 
254     assertTrue(plan instanceof SplitNormalizationPlan);
255     assertEquals(hri4, ((SplitNormalizationPlan) plan).getRegionInfo());
256   }
257 
258   protected void setupMocksForNormalizer(Map<byte[], Integer> regionSizes,
259                                          List<HRegionInfo> hris) {
260     masterServices = Mockito.mock(MasterServices.class, RETURNS_DEEP_STUBS);
261 
262     // for simplicity all regions are assumed to be on one server; doesn't matter to us
263     ServerName sn = ServerName.valueOf("localhost", -1, 1L);
264     when(masterServices.getAssignmentManager().getRegionStates().
265       getRegionsOfTable(any(TableName.class))).thenReturn(hris);
266     when(masterServices.getAssignmentManager().getRegionStates().
267       getRegionServerOfRegion(any(HRegionInfo.class))).thenReturn(sn);
268 
269     for (Map.Entry<byte[], Integer> region : regionSizes.entrySet()) {
270       RegionLoad regionLoad = Mockito.mock(RegionLoad.class);
271       when(regionLoad.getName()).thenReturn(region.getKey());
272       when(regionLoad.getStorefileSizeMB()).thenReturn(region.getValue());
273 
274       when(masterServices.getServerManager().getLoad(sn).
275         getRegionsLoad().get(region.getKey())).thenReturn(regionLoad);
276     }
277 
278     normalizer.setMasterServices(masterServices);
279   }
280 }