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.normalizer;
019
020import static java.lang.String.format;
021import static org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer.DEFAULT_MERGE_MIN_REGION_AGE_DAYS;
022import static org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer.MERGE_ENABLED_KEY;
023import static org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer.MERGE_MIN_REGION_AGE_DAYS_KEY;
024import static org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer.MERGE_MIN_REGION_SIZE_MB_KEY;
025import static org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer.MIN_REGION_COUNT_KEY;
026import static org.apache.hadoop.hbase.master.normalizer.SimpleRegionNormalizer.SPLIT_ENABLED_KEY;
027import static org.hamcrest.MatcherAssert.assertThat;
028import static org.hamcrest.Matchers.contains;
029import static org.hamcrest.Matchers.empty;
030import static org.hamcrest.Matchers.everyItem;
031import static org.hamcrest.Matchers.greaterThanOrEqualTo;
032import static org.hamcrest.Matchers.instanceOf;
033import static org.hamcrest.Matchers.iterableWithSize;
034import static org.hamcrest.Matchers.not;
035import static org.junit.Assert.assertEquals;
036import static org.junit.Assert.assertFalse;
037import static org.junit.Assert.assertTrue;
038import static org.mockito.ArgumentMatchers.any;
039import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
040import static org.mockito.Mockito.when;
041import java.time.Instant;
042import java.time.Period;
043import java.util.ArrayList;
044import java.util.Collections;
045import java.util.HashMap;
046import java.util.List;
047import java.util.Map;
048import org.apache.hadoop.conf.Configuration;
049import org.apache.hadoop.hbase.HBaseClassTestRule;
050import org.apache.hadoop.hbase.HBaseConfiguration;
051import org.apache.hadoop.hbase.RegionMetrics;
052import org.apache.hadoop.hbase.ServerName;
053import org.apache.hadoop.hbase.Size;
054import org.apache.hadoop.hbase.TableName;
055import org.apache.hadoop.hbase.client.RegionInfo;
056import org.apache.hadoop.hbase.client.RegionInfoBuilder;
057import org.apache.hadoop.hbase.master.MasterServices;
058import org.apache.hadoop.hbase.master.RegionState;
059import org.apache.hadoop.hbase.testclassification.MasterTests;
060import org.apache.hadoop.hbase.testclassification.SmallTests;
061import org.apache.hadoop.hbase.util.Bytes;
062import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
063import org.junit.Before;
064import org.junit.ClassRule;
065import org.junit.Rule;
066import org.junit.Test;
067import org.junit.experimental.categories.Category;
068import org.junit.rules.TestName;
069import org.mockito.Mockito;
070
071/**
072 * Tests logic of {@link SimpleRegionNormalizer}.
073 */
074@Category({MasterTests.class, SmallTests.class})
075public class TestSimpleRegionNormalizer {
076
077  @ClassRule
078  public static final HBaseClassTestRule CLASS_RULE =
079      HBaseClassTestRule.forClass(TestSimpleRegionNormalizer.class);
080
081  private Configuration conf;
082  private SimpleRegionNormalizer normalizer;
083  private MasterServices masterServices;
084
085  @Rule
086  public TestName name = new TestName();
087
088  @Before
089  public void before() {
090    conf = HBaseConfiguration.create();
091  }
092
093  @Test
094  public void testNoNormalizationForMetaTable() {
095    TableName testTable = TableName.META_TABLE_NAME;
096    List<RegionInfo> RegionInfo = new ArrayList<>();
097    Map<byte[], Integer> regionSizes = new HashMap<>();
098
099    setupMocksForNormalizer(regionSizes, RegionInfo);
100    List<NormalizationPlan> plans = normalizer.computePlansForTable(testTable);
101    assertThat(plans, empty());
102  }
103
104  @Test
105  public void testNoNormalizationIfTooFewRegions() {
106    final TableName tableName = TableName.valueOf(name.getMethodName());
107    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 2);
108    final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 10, 15);
109    setupMocksForNormalizer(regionSizes, regionInfos);
110
111    List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
112    assertThat(plans, empty());
113  }
114
115  @Test
116  public void testNoNormalizationOnNormalizedCluster() {
117    final TableName tableName = TableName.valueOf(name.getMethodName());
118    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4);
119    final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 10, 15, 8, 10);
120    setupMocksForNormalizer(regionSizes, regionInfos);
121
122    List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
123    assertThat(plans, empty());
124  }
125
126  private void noNormalizationOnTransitioningRegions(final RegionState.State state) {
127    final TableName tableName = TableName.valueOf(name.getMethodName());
128    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 3);
129    final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 10, 1, 100);
130
131    setupMocksForNormalizer(regionSizes, regionInfos);
132    when(masterServices.getAssignmentManager().getRegionStates()
133      .getRegionState(any(RegionInfo.class)))
134      .thenReturn(RegionState.createForTesting(null, state));
135    assertThat(normalizer.getMinRegionCount(), greaterThanOrEqualTo(regionInfos.size()));
136
137    List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
138    assertThat(format("Unexpected plans for RegionState %s", state), plans, empty());
139  }
140
141  @Test
142  public void testNoNormalizationOnMergingNewRegions() {
143    noNormalizationOnTransitioningRegions(RegionState.State.MERGING_NEW);
144  }
145
146  @Test
147  public void testNoNormalizationOnMergingRegions() {
148    noNormalizationOnTransitioningRegions(RegionState.State.MERGING);
149  }
150
151  @Test
152  public void testNoNormalizationOnMergedRegions() {
153    noNormalizationOnTransitioningRegions(RegionState.State.MERGED);
154  }
155
156  @Test
157  public void testNoNormalizationOnSplittingNewRegions() {
158    noNormalizationOnTransitioningRegions(RegionState.State.SPLITTING_NEW);
159  }
160
161  @Test
162  public void testNoNormalizationOnSplittingRegions() {
163    noNormalizationOnTransitioningRegions(RegionState.State.SPLITTING);
164  }
165
166  @Test
167  public void testNoNormalizationOnSplitRegions() {
168    noNormalizationOnTransitioningRegions(RegionState.State.SPLIT);
169  }
170
171  @Test
172  public void testMergeOfSmallRegions() {
173    final TableName tableName = TableName.valueOf(name.getMethodName());
174    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5);
175    final Map<byte[], Integer> regionSizes =
176      createRegionSizesMap(regionInfos, 15, 5, 5, 15, 16);
177    setupMocksForNormalizer(regionSizes, regionInfos);
178
179    List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
180    assertThat(plans.get(0), instanceOf(MergeNormalizationPlan.class));
181    MergeNormalizationPlan plan = (MergeNormalizationPlan) plans.get(0);
182    assertEquals(regionInfos.get(1), plan.getFirstRegion());
183    assertEquals(regionInfos.get(2), plan.getSecondRegion());
184  }
185
186  // Test for situation illustrated in HBASE-14867
187  @Test
188  public void testMergeOfSecondSmallestRegions() {
189    final TableName tableName = TableName.valueOf(name.getMethodName());
190    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 6);
191    final Map<byte[], Integer> regionSizes =
192      createRegionSizesMap(regionInfos, 1, 10000, 10000, 10000, 2700, 2700);
193    setupMocksForNormalizer(regionSizes, regionInfos);
194
195    List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
196    assertThat(plans.get(0), instanceOf(MergeNormalizationPlan.class));
197    MergeNormalizationPlan plan = (MergeNormalizationPlan) plans.get(0);
198    assertEquals(regionInfos.get(4), plan.getFirstRegion());
199    assertEquals(regionInfos.get(5), plan.getSecondRegion());
200  }
201
202  @Test
203  public void testMergeOfSmallNonAdjacentRegions() {
204    final TableName tableName = TableName.valueOf(name.getMethodName());
205    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5);
206    final Map<byte[], Integer> regionSizes =
207      createRegionSizesMap(regionInfos, 15, 5, 16, 15, 5);
208    setupMocksForNormalizer(regionSizes, regionInfos);
209
210    List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
211    assertThat(plans, empty());
212  }
213
214  @Test
215  public void testSplitOfLargeRegion() {
216    final TableName tableName = TableName.valueOf(name.getMethodName());
217    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4);
218    final Map<byte[], Integer> regionSizes =
219      createRegionSizesMap(regionInfos, 8, 6, 10, 30);
220    setupMocksForNormalizer(regionSizes, regionInfos);
221
222    List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
223    assertThat(plans.get(0), instanceOf(SplitNormalizationPlan.class));
224    SplitNormalizationPlan plan = (SplitNormalizationPlan) plans.get(0);
225    assertEquals(regionInfos.get(3), plan.getRegionInfo());
226  }
227
228  @Test
229  public void testSplitWithTargetRegionCount() throws Exception {
230    final TableName tableName = TableName.valueOf(name.getMethodName());
231    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 6);
232    final Map<byte[], Integer> regionSizes =
233      createRegionSizesMap(regionInfos, 20, 40, 60, 80, 100, 120);
234    setupMocksForNormalizer(regionSizes, regionInfos);
235
236    // test when target region size is 20
237    when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionSize())
238        .thenReturn(20L);
239    List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
240    assertThat(plans, iterableWithSize(4));
241    assertThat(plans, everyItem(instanceOf(SplitNormalizationPlan.class)));
242
243    // test when target region size is 200
244    when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionSize())
245        .thenReturn(200L);
246    plans = normalizer.computePlansForTable(tableName);
247    assertThat(plans, iterableWithSize(2));
248    assertTrue(plans.get(0) instanceof MergeNormalizationPlan);
249    MergeNormalizationPlan plan = (MergeNormalizationPlan) plans.get(0);
250    assertEquals(regionInfos.get(0), plan.getFirstRegion());
251    assertEquals(regionInfos.get(1), plan.getSecondRegion());
252  }
253
254  @Test
255  public void testSplitWithTargetRegionSize() throws Exception {
256    final TableName tableName = TableName.valueOf(name.getMethodName());
257    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4);
258    final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 20, 40, 60, 80);
259    setupMocksForNormalizer(regionSizes, regionInfos);
260
261    // test when target region count is 8
262    when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionCount())
263        .thenReturn(8);
264    List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
265    assertThat(plans, iterableWithSize(2));
266    assertThat(plans, everyItem(instanceOf(SplitNormalizationPlan.class)));
267
268    // test when target region count is 3
269    when(masterServices.getTableDescriptors().get(any()).getNormalizerTargetRegionCount())
270        .thenReturn(3);
271    plans = normalizer.computePlansForTable(tableName);
272    assertThat(plans, contains(instanceOf(MergeNormalizationPlan.class)));
273    MergeNormalizationPlan plan = (MergeNormalizationPlan) plans.get(0);
274    assertEquals(regionInfos.get(0), plan.getFirstRegion());
275    assertEquals(regionInfos.get(1), plan.getSecondRegion());
276  }
277
278  @Test
279  public void testHonorsSplitEnabled() {
280    conf.setBoolean(SPLIT_ENABLED_KEY, true);
281    final TableName tableName = TableName.valueOf(name.getMethodName());
282    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5);
283    final Map<byte[], Integer> regionSizes =
284      createRegionSizesMap(regionInfos, 5, 5, 20, 5, 5);
285    setupMocksForNormalizer(regionSizes, regionInfos);
286    assertThat(
287      normalizer.computePlansForTable(tableName),
288      contains(instanceOf(SplitNormalizationPlan.class)));
289
290    conf.setBoolean(SPLIT_ENABLED_KEY, false);
291    setupMocksForNormalizer(regionSizes, regionInfos);
292    assertThat(normalizer.computePlansForTable(tableName), empty());
293  }
294
295  @Test
296  public void testHonorsMergeEnabled() {
297    conf.setBoolean(MERGE_ENABLED_KEY, true);
298    final TableName tableName = TableName.valueOf(name.getMethodName());
299    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5);
300    final Map<byte[], Integer> regionSizes =
301      createRegionSizesMap(regionInfos, 20, 5, 5, 20, 20);
302    setupMocksForNormalizer(regionSizes, regionInfos);
303    assertThat(
304      normalizer.computePlansForTable(tableName),
305      contains(instanceOf(MergeNormalizationPlan.class)));
306
307    conf.setBoolean(MERGE_ENABLED_KEY, false);
308    setupMocksForNormalizer(regionSizes, regionInfos);
309    assertThat(normalizer.computePlansForTable(tableName), empty());
310  }
311
312  @Test
313  public void testHonorsMinimumRegionCount() {
314    conf.setInt(MIN_REGION_COUNT_KEY, 1);
315    final TableName tableName = TableName.valueOf(name.getMethodName());
316    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 3);
317    // create a table topology that results in both a merge plan and a split plan. Assert that the
318    // merge is only created when the when the number of table regions is above the region count
319    // threshold, and that the split plan is create in both cases.
320    final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 1, 1, 10);
321    setupMocksForNormalizer(regionSizes, regionInfos);
322
323    List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
324    assertThat(plans, contains(
325      instanceOf(SplitNormalizationPlan.class),
326      instanceOf(MergeNormalizationPlan.class)));
327    SplitNormalizationPlan splitPlan = (SplitNormalizationPlan) plans.get(0);
328    assertEquals(regionInfos.get(2), splitPlan.getRegionInfo());
329    MergeNormalizationPlan mergePlan = (MergeNormalizationPlan) plans.get(1);
330    assertEquals(regionInfos.get(0), mergePlan.getFirstRegion());
331    assertEquals(regionInfos.get(1), mergePlan.getSecondRegion());
332
333    // have to call setupMocks again because we don't have dynamic config update on normalizer.
334    conf.setInt(MIN_REGION_COUNT_KEY, 4);
335    setupMocksForNormalizer(regionSizes, regionInfos);
336    plans = normalizer.computePlansForTable(tableName);
337    assertThat(plans, contains(instanceOf(SplitNormalizationPlan.class)));
338    splitPlan = (SplitNormalizationPlan) plans.get(0);
339    assertEquals(regionInfos.get(2), splitPlan.getRegionInfo());
340  }
341
342  @Test
343  public void testHonorsMergeMinRegionAge() {
344    conf.setInt(MERGE_MIN_REGION_AGE_DAYS_KEY, 7);
345    final TableName tableName = TableName.valueOf(name.getMethodName());
346    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 4);
347    final Map<byte[], Integer> regionSizes =
348      createRegionSizesMap(regionInfos, 1, 1, 10, 10);
349    setupMocksForNormalizer(regionSizes, regionInfos);
350    assertEquals(Period.ofDays(7), normalizer.getMergeMinRegionAge());
351    assertThat(
352      normalizer.computePlansForTable(tableName),
353      everyItem(not(instanceOf(MergeNormalizationPlan.class))));
354
355    // have to call setupMocks again because we don't have dynamic config update on normalizer.
356    conf.unset(MERGE_MIN_REGION_AGE_DAYS_KEY);
357    setupMocksForNormalizer(regionSizes, regionInfos);
358    assertEquals(
359      Period.ofDays(DEFAULT_MERGE_MIN_REGION_AGE_DAYS), normalizer.getMergeMinRegionAge());
360    final List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
361    assertThat(plans, not(empty()));
362    assertThat(plans, everyItem(instanceOf(MergeNormalizationPlan.class)));
363  }
364
365  @Test
366  public void testHonorsMergeMinRegionSize() {
367    conf.setBoolean(SPLIT_ENABLED_KEY, false);
368    final TableName tableName = TableName.valueOf(name.getMethodName());
369    final List<RegionInfo> regionInfos = createRegionInfos(tableName, 5);
370    final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 1, 2, 0, 10, 10);
371    setupMocksForNormalizer(regionSizes, regionInfos);
372
373    assertFalse(normalizer.isSplitEnabled());
374    assertEquals(1, normalizer.getMergeMinRegionSizeMb());
375    final List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
376    assertThat(plans, everyItem(instanceOf(MergeNormalizationPlan.class)));
377    assertThat(plans, iterableWithSize(1));
378    final MergeNormalizationPlan plan = (MergeNormalizationPlan) plans.get(0);
379    assertEquals(regionInfos.get(0), plan.getFirstRegion());
380    assertEquals(regionInfos.get(1), plan.getSecondRegion());
381
382    conf.setInt(MERGE_MIN_REGION_SIZE_MB_KEY, 3);
383    setupMocksForNormalizer(regionSizes, regionInfos);
384    assertEquals(3, normalizer.getMergeMinRegionSizeMb());
385    assertThat(normalizer.computePlansForTable(tableName), empty());
386  }
387
388  // This test is to make sure that normalizer is only going to merge adjacent regions.
389  @Test
390  public void testNormalizerCannotMergeNonAdjacentRegions() {
391    final TableName tableName = TableName.valueOf(name.getMethodName());
392    // create 5 regions with sizes to trigger merge of small regions. region ranges are:
393    // [, "aa"), ["aa", "aa1"), ["aa1", "aa1!"), ["aa1!", "aa2"), ["aa2", )
394    // Region ["aa", "aa1") and ["aa1!", "aa2") are not adjacent, they are not supposed to
395    // merged.
396    final byte[][] keys = {
397      null,
398      Bytes.toBytes("aa"),
399      Bytes.toBytes("aa1!"),
400      Bytes.toBytes("aa1"),
401      Bytes.toBytes("aa2"),
402      null,
403    };
404    final List<RegionInfo> regionInfos = createRegionInfos(tableName, keys);
405    final Map<byte[], Integer> regionSizes = createRegionSizesMap(regionInfos, 3, 1, 1, 3, 5);
406    setupMocksForNormalizer(regionSizes, regionInfos);
407
408    // Compute the plan, no merge plan returned as they are not adjacent.
409    List<NormalizationPlan> plans = normalizer.computePlansForTable(tableName);
410    assertThat(plans, empty());
411  }
412
413  @SuppressWarnings("MockitoCast")
414  private void setupMocksForNormalizer(Map<byte[], Integer> regionSizes,
415    List<RegionInfo> regionInfoList) {
416    masterServices = Mockito.mock(MasterServices.class, RETURNS_DEEP_STUBS);
417
418    // for simplicity all regions are assumed to be on one server; doesn't matter to us
419    ServerName sn = ServerName.valueOf("localhost", 0, 0L);
420    when(masterServices.getAssignmentManager().getRegionStates()
421      .getRegionsOfTable(any())).thenReturn(regionInfoList);
422    when(masterServices.getAssignmentManager().getRegionStates()
423      .getRegionServerOfRegion(any())).thenReturn(sn);
424    when(masterServices.getAssignmentManager().getRegionStates()
425      .getRegionState(any(RegionInfo.class))).thenReturn(
426        RegionState.createForTesting(null, RegionState.State.OPEN));
427
428    for (Map.Entry<byte[], Integer> region : regionSizes.entrySet()) {
429      RegionMetrics regionLoad = Mockito.mock(RegionMetrics.class);
430      when(regionLoad.getRegionName()).thenReturn(region.getKey());
431      when(regionLoad.getStoreFileSize())
432        .thenReturn(new Size(region.getValue(), Size.Unit.MEGABYTE));
433
434      // this is possibly broken with jdk9, unclear if false positive or not
435      // suppress it for now, fix it when we get to running tests on 9
436      // see: http://errorprone.info/bugpattern/MockitoCast
437      when((Object) masterServices.getServerManager().getLoad(sn)
438        .getRegionMetrics().get(region.getKey())).thenReturn(regionLoad);
439    }
440
441    when(masterServices.isSplitOrMergeEnabled(any())).thenReturn(true);
442
443    normalizer = new SimpleRegionNormalizer();
444    normalizer.setConf(conf);
445    normalizer.setMasterServices(masterServices);
446  }
447
448  /**
449   * Create a list of {@link RegionInfo}s that represent a region chain of the specified length.
450   */
451  private static List<RegionInfo> createRegionInfos(final TableName tableName, final int length) {
452    if (length < 1) {
453      throw new IllegalStateException("length must be greater than or equal to 1.");
454    }
455
456    final byte[] startKey = Bytes.toBytes("aaaaa");
457    final byte[] endKey = Bytes.toBytes("zzzzz");
458    if (length == 1) {
459      return Collections.singletonList(createRegionInfo(tableName, startKey, endKey));
460    }
461
462    final byte[][] splitKeys = Bytes.split(startKey, endKey, length - 1);
463    final List<RegionInfo> ret = new ArrayList<>(length);
464    for (int i = 0; i < splitKeys.length - 1; i++) {
465      ret.add(createRegionInfo(tableName, splitKeys[i], splitKeys[i+1]));
466    }
467    return ret;
468  }
469
470  private static RegionInfo createRegionInfo(final TableName tableName, final byte[] startKey,
471    final byte[] endKey) {
472    return RegionInfoBuilder.newBuilder(tableName)
473      .setStartKey(startKey)
474      .setEndKey(endKey)
475      .setRegionId(generateRegionId())
476      .build();
477  }
478
479  private static long generateRegionId() {
480    return Instant.ofEpochMilli(EnvironmentEdgeManager.currentTime())
481      .minus(Period.ofDays(DEFAULT_MERGE_MIN_REGION_AGE_DAYS + 1))
482      .toEpochMilli();
483  }
484
485  private static List<RegionInfo> createRegionInfos(final TableName tableName,
486    final byte[][] splitKeys) {
487    final List<RegionInfo> ret = new ArrayList<>(splitKeys.length);
488    for (int i = 0; i < splitKeys.length - 1; i++) {
489      ret.add(createRegionInfo(tableName, splitKeys[i], splitKeys[i+1]));
490    }
491    return ret;
492  }
493
494  private static Map<byte[], Integer> createRegionSizesMap(final List<RegionInfo> regionInfos,
495    int... sizes) {
496    if (regionInfos.size() != sizes.length) {
497      throw new IllegalStateException("Parameter lengths must match.");
498    }
499
500    final Map<byte[], Integer> ret = new HashMap<>(regionInfos.size());
501    for (int i = 0; i < regionInfos.size(); i++) {
502      ret.put(regionInfos.get(i).getRegionName(), sizes[i]);
503    }
504    return ret;
505  }
506}