View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.regionserver;
19  
20  import static org.junit.Assert.assertEquals;
21  import static org.junit.Assert.assertFalse;
22  import static org.junit.Assert.assertNull;
23  import static org.junit.Assert.assertTrue;
24  
25  import java.io.IOException;
26  import java.util.ArrayList;
27  import java.util.List;
28  
29  import org.apache.hadoop.conf.Configuration;
30  import org.apache.hadoop.hbase.TableName;
31  import org.apache.hadoop.hbase.HBaseConfiguration;
32  import org.apache.hadoop.hbase.HConstants;
33  import org.apache.hadoop.hbase.HRegionInfo;
34  import org.apache.hadoop.hbase.HTableDescriptor;
35  import org.apache.hadoop.hbase.testclassification.SmallTests;
36  import org.apache.hadoop.hbase.util.Bytes;
37  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
38  import org.junit.Before;
39  import org.junit.Test;
40  import org.junit.experimental.categories.Category;
41  import org.mockito.Mockito;
42  
43  @Category(SmallTests.class)
44  public class TestRegionSplitPolicy {
45  
46    private Configuration conf;
47    private HTableDescriptor htd;
48    private HRegion mockRegion;
49    private List<Store> stores;
50    private static final TableName TABLENAME = TableName.valueOf("t");
51  
52    @Before
53    public void setupMocks() {
54      conf = HBaseConfiguration.create();
55      HRegionInfo hri = new HRegionInfo(TABLENAME);
56      htd = new HTableDescriptor(TABLENAME);
57      mockRegion = Mockito.mock(HRegion.class);
58      Mockito.doReturn(htd).when(mockRegion).getTableDesc();
59      Mockito.doReturn(hri).when(mockRegion).getRegionInfo();
60      stores = new ArrayList<Store>();
61      Mockito.doReturn(stores).when(mockRegion).getStores();
62    }
63  
64    @Test
65    public void testForceSplitRegionWithReference() throws IOException {
66      htd.setMaxFileSize(1024L);
67      // Add a store above the requisite size. Should split.
68      HStore mockStore = Mockito.mock(HStore.class);
69      Mockito.doReturn(2000L).when(mockStore).getSize();
70      // Act as if there's a reference file or some other reason it can't split.
71      // This should prevent splitting even though it's big enough.
72      Mockito.doReturn(false).when(mockStore).canSplit();
73      stores.add(mockStore);
74  
75      conf.set(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
76        ConstantSizeRegionSplitPolicy.class.getName());
77      ConstantSizeRegionSplitPolicy policy =
78          (ConstantSizeRegionSplitPolicy)RegionSplitPolicy.create(mockRegion, conf);
79      assertFalse(policy.shouldSplit());
80      Mockito.doReturn(true).when(mockRegion).shouldForceSplit();
81      assertFalse(policy.shouldSplit());
82  
83      Mockito.doReturn(false).when(mockRegion).shouldForceSplit();
84      conf.set(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
85        IncreasingToUpperBoundRegionSplitPolicy.class.getName());
86      policy = (IncreasingToUpperBoundRegionSplitPolicy) RegionSplitPolicy.create(mockRegion, conf);
87      assertFalse(policy.shouldSplit());
88      Mockito.doReturn(true).when(mockRegion).shouldForceSplit();
89      assertFalse(policy.shouldSplit());
90    }
91  
92    @Test
93    public void testIncreasingToUpperBoundRegionSplitPolicy() throws IOException {
94      // Configure IncreasingToUpperBoundRegionSplitPolicy as our split policy
95      conf.set(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
96        IncreasingToUpperBoundRegionSplitPolicy.class.getName());
97      // Now make it so the mock region has a RegionServerService that will
98      // return 'online regions'.
99      RegionServerServices rss = Mockito.mock(RegionServerServices.class);
100     final List<Region> regions = new ArrayList<Region>();
101     Mockito.when(rss.getOnlineRegions(TABLENAME)).thenReturn(regions);
102     Mockito.when(mockRegion.getRegionServerServices()).thenReturn(rss);
103     // Set max size for this 'table'.
104     long maxSplitSize = 1024L;
105     htd.setMaxFileSize(maxSplitSize);
106     // Set flush size to 1/8.  IncreasingToUpperBoundRegionSplitPolicy
107     // grows by the cube of the number of regions times flushsize each time.
108     long flushSize = maxSplitSize/8;
109     conf.setLong(HConstants.HREGION_MEMSTORE_FLUSH_SIZE, flushSize);
110     htd.setMemStoreFlushSize(flushSize);
111     // If RegionServerService with no regions in it -- 'online regions' == 0 --
112     // then IncreasingToUpperBoundRegionSplitPolicy should act like a
113     // ConstantSizePolicy
114     IncreasingToUpperBoundRegionSplitPolicy policy =
115       (IncreasingToUpperBoundRegionSplitPolicy)RegionSplitPolicy.create(mockRegion, conf);
116     doConstantSizePolicyTests(policy);
117 
118     // Add a store in excess of split size.  Because there are "no regions"
119     // on this server -- rss.getOnlineRegions is 0 -- then we should split
120     // like a constantsizeregionsplitpolicy would
121     HStore mockStore = Mockito.mock(HStore.class);
122     Mockito.doReturn(2000L).when(mockStore).getSize();
123     Mockito.doReturn(true).when(mockStore).canSplit();
124     stores.add(mockStore);
125     // It should split
126     assertTrue(policy.shouldSplit());
127 
128     // Now test that we increase our split size as online regions for a table
129     // grows. With one region, split size should be flushsize.
130     regions.add(mockRegion);
131     Mockito.doReturn(flushSize).when(mockStore).getSize();
132     // Should not split since store is flush size.
133     assertFalse(policy.shouldSplit());
134     // Set size of store to be > 2*flush size and we should split
135     Mockito.doReturn(flushSize*2 + 1).when(mockStore).getSize();
136     assertTrue(policy.shouldSplit());
137     // Add another region to the 'online regions' on this server and we should
138     // now be no longer be splittable since split size has gone up.
139     regions.add(mockRegion);
140     assertFalse(policy.shouldSplit());
141     // make sure its just over; verify it'll split
142     Mockito.doReturn((long)(maxSplitSize * 1.25 + 1)).when(mockStore).getSize();
143     assertTrue(policy.shouldSplit());
144 
145     // Finally assert that even if loads of regions, we'll split at max size
146     assertWithinJitter(maxSplitSize, policy.getSizeToCheck(1000));
147     // Assert same is true if count of regions is zero.
148     assertWithinJitter(maxSplitSize, policy.getSizeToCheck(0));
149   }
150 
151   @Test
152   public void testBusyRegionSplitPolicy() throws Exception {
153     conf.set(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
154         BusyRegionSplitPolicy.class.getName());
155     conf.setLong("hbase.busy.policy.minAge", 1000000L);
156     conf.setFloat("hbase.busy.policy.blockedRequests", 0.1f);
157 
158     RegionServerServices rss  = Mockito.mock(RegionServerServices.class);
159     final List<Region> regions = new ArrayList<Region>();
160     Mockito.when(rss.getOnlineRegions(TABLENAME)).thenReturn(regions);
161     Mockito.when(mockRegion.getRegionServerServices()).thenReturn(rss);
162     Mockito.when(mockRegion.getBlockedRequestsCount()).thenReturn(0L);
163     Mockito.when(mockRegion.getWriteRequestsCount()).thenReturn(0L);
164 
165 
166     BusyRegionSplitPolicy policy =
167         (BusyRegionSplitPolicy)RegionSplitPolicy.create(mockRegion, conf);
168 
169     Mockito.when(mockRegion.getBlockedRequestsCount()).thenReturn(10L);
170     Mockito.when(mockRegion.getWriteRequestsCount()).thenReturn(10L);
171     // Not enough time since region came online
172     assertFalse(policy.shouldSplit());
173 
174 
175     // Reset min age for split to zero
176     conf.setLong("hbase.busy.policy.minAge", 0L);
177     // Aggregate over 500 ms periods
178     conf.setLong("hbase.busy.policy.aggWindow", 500L);
179     policy =
180         (BusyRegionSplitPolicy)RegionSplitPolicy.create(mockRegion, conf);
181     long start = EnvironmentEdgeManager.currentTime();
182     Mockito.when(mockRegion.getBlockedRequestsCount()).thenReturn(10L);
183     Mockito.when(mockRegion.getWriteRequestsCount()).thenReturn(20L);
184     Thread.sleep(300);
185     assertFalse(policy.shouldSplit());
186     Mockito.when(mockRegion.getBlockedRequestsCount()).thenReturn(12L);
187     Mockito.when(mockRegion.getWriteRequestsCount()).thenReturn(30L);
188     Thread.sleep(2);
189     // Enough blocked requests since last time, but aggregate blocked request
190     // rate over last 500 ms is still low, because major portion of the window is constituted
191     // by the previous zero blocked request period which lasted at least 300 ms off last 500 ms.
192     if (EnvironmentEdgeManager.currentTime() - start < 500) {
193       assertFalse(policy.shouldSplit());
194     }
195     Mockito.when(mockRegion.getBlockedRequestsCount()).thenReturn(14L);
196     Mockito.when(mockRegion.getWriteRequestsCount()).thenReturn(40L);
197     Thread.sleep(200);
198     assertTrue(policy.shouldSplit());
199   }
200 
201   private void assertWithinJitter(long maxSplitSize, long sizeToCheck) {
202     assertTrue("Size greater than lower bound of jitter",
203         (long)(maxSplitSize * 0.75) <= sizeToCheck);
204     assertTrue("Size less than upper bound of jitter",
205         (long)(maxSplitSize * 1.25) >= sizeToCheck);
206   }
207 
208   @Test
209   public void testCreateDefault() throws IOException {
210     conf.setLong(HConstants.HREGION_MAX_FILESIZE, 1234L);
211 
212     // Using a default HTD, should pick up the file size from
213     // configuration.
214     ConstantSizeRegionSplitPolicy policy =
215         (ConstantSizeRegionSplitPolicy)RegionSplitPolicy.create(
216             mockRegion, conf);
217     assertWithinJitter(1234L, policy.getDesiredMaxFileSize());
218 
219     // If specified in HTD, should use that
220     htd.setMaxFileSize(9999L);
221     policy = (ConstantSizeRegionSplitPolicy)RegionSplitPolicy.create(
222         mockRegion, conf);
223     assertWithinJitter(9999L, policy.getDesiredMaxFileSize());
224   }
225 
226   /**
227    * Test setting up a customized split policy
228    */
229   @Test
230   public void testCustomPolicy() throws IOException {
231     HTableDescriptor myHtd = new HTableDescriptor();
232     myHtd.setValue(HTableDescriptor.SPLIT_POLICY,
233         KeyPrefixRegionSplitPolicy.class.getName());
234     myHtd.setValue(KeyPrefixRegionSplitPolicy.PREFIX_LENGTH_KEY, String.valueOf(2));
235 
236     HRegion myMockRegion = Mockito.mock(HRegion.class);
237     Mockito.doReturn(myHtd).when(myMockRegion).getTableDesc();
238     Mockito.doReturn(stores).when(myMockRegion).getStores();
239 
240     HStore mockStore = Mockito.mock(HStore.class);
241     Mockito.doReturn(2000L).when(mockStore).getSize();
242     Mockito.doReturn(true).when(mockStore).canSplit();
243     Mockito.doReturn(Bytes.toBytes("abcd")).when(mockStore).getSplitPoint();
244     stores.add(mockStore);
245 
246     KeyPrefixRegionSplitPolicy policy = (KeyPrefixRegionSplitPolicy) RegionSplitPolicy
247         .create(myMockRegion, conf);
248 
249     assertEquals("ab", Bytes.toString(policy.getSplitPoint()));
250 
251     Mockito.doReturn(true).when(myMockRegion).shouldForceSplit();
252     Mockito.doReturn(Bytes.toBytes("efgh")).when(myMockRegion)
253         .getExplicitSplitPoint();
254 
255     policy = (KeyPrefixRegionSplitPolicy) RegionSplitPolicy
256         .create(myMockRegion, conf);
257 
258     assertEquals("ef", Bytes.toString(policy.getSplitPoint()));
259   }
260 
261   @Test
262   public void testConstantSizePolicy() throws IOException {
263     htd.setMaxFileSize(1024L);
264     ConstantSizeRegionSplitPolicy policy =
265       (ConstantSizeRegionSplitPolicy)RegionSplitPolicy.create(mockRegion, conf);
266     doConstantSizePolicyTests(policy);
267   }
268 
269   /**
270    * Run through tests for a ConstantSizeRegionSplitPolicy
271    * @param policy
272    */
273   private void doConstantSizePolicyTests(final ConstantSizeRegionSplitPolicy policy) {
274     // For no stores, should not split
275     assertFalse(policy.shouldSplit());
276 
277     // Add a store above the requisite size. Should split.
278     HStore mockStore = Mockito.mock(HStore.class);
279     Mockito.doReturn(2000L).when(mockStore).getSize();
280     Mockito.doReturn(true).when(mockStore).canSplit();
281     stores.add(mockStore);
282 
283     assertTrue(policy.shouldSplit());
284 
285     // Act as if there's a reference file or some other reason it can't split.
286     // This should prevent splitting even though it's big enough.
287     Mockito.doReturn(false).when(mockStore).canSplit();
288     assertFalse(policy.shouldSplit());
289 
290     // Reset splittability after above
291     Mockito.doReturn(true).when(mockStore).canSplit();
292 
293     // Set to a small size but turn on forceSplit. Should result in a split.
294     Mockito.doReturn(true).when(mockRegion).shouldForceSplit();
295     Mockito.doReturn(100L).when(mockStore).getSize();
296     assertTrue(policy.shouldSplit());
297 
298     // Turn off forceSplit, should not split
299     Mockito.doReturn(false).when(mockRegion).shouldForceSplit();
300     assertFalse(policy.shouldSplit());
301 
302     // Clear families we added above
303     stores.clear();
304   }
305 
306   @Test
307   public void testGetSplitPoint() throws IOException {
308     ConstantSizeRegionSplitPolicy policy =
309       (ConstantSizeRegionSplitPolicy)RegionSplitPolicy.create(mockRegion, conf);
310 
311     // For no stores, should not split
312     assertFalse(policy.shouldSplit());
313     assertNull(policy.getSplitPoint());
314 
315     // Add a store above the requisite size. Should split.
316     HStore mockStore = Mockito.mock(HStore.class);
317     Mockito.doReturn(2000L).when(mockStore).getSize();
318     Mockito.doReturn(true).when(mockStore).canSplit();
319     Mockito.doReturn(Bytes.toBytes("store 1 split"))
320       .when(mockStore).getSplitPoint();
321     stores.add(mockStore);
322 
323     assertEquals("store 1 split",
324         Bytes.toString(policy.getSplitPoint()));
325 
326     // Add a bigger store. The split point should come from that one
327     HStore mockStore2 = Mockito.mock(HStore.class);
328     Mockito.doReturn(4000L).when(mockStore2).getSize();
329     Mockito.doReturn(true).when(mockStore2).canSplit();
330     Mockito.doReturn(Bytes.toBytes("store 2 split"))
331       .when(mockStore2).getSplitPoint();
332     stores.add(mockStore2);
333 
334     assertEquals("store 2 split",
335         Bytes.toString(policy.getSplitPoint()));
336   }
337 
338   @Test
339   public void testDelimitedKeyPrefixRegionSplitPolicy() throws IOException {
340     HTableDescriptor myHtd = new HTableDescriptor();
341     myHtd.setValue(HTableDescriptor.SPLIT_POLICY,
342         DelimitedKeyPrefixRegionSplitPolicy.class.getName());
343     myHtd.setValue(DelimitedKeyPrefixRegionSplitPolicy.DELIMITER_KEY, ",");
344 
345     HRegion myMockRegion = Mockito.mock(HRegion.class);
346     Mockito.doReturn(myHtd).when(myMockRegion).getTableDesc();
347     Mockito.doReturn(stores).when(myMockRegion).getStores();
348 
349     HStore mockStore = Mockito.mock(HStore.class);
350     Mockito.doReturn(2000L).when(mockStore).getSize();
351     Mockito.doReturn(true).when(mockStore).canSplit();
352     Mockito.doReturn(Bytes.toBytes("ab,cd")).when(mockStore).getSplitPoint();
353     stores.add(mockStore);
354 
355     DelimitedKeyPrefixRegionSplitPolicy policy = (DelimitedKeyPrefixRegionSplitPolicy) RegionSplitPolicy
356         .create(myMockRegion, conf);
357 
358     assertEquals("ab", Bytes.toString(policy.getSplitPoint()));
359 
360     Mockito.doReturn(true).when(myMockRegion).shouldForceSplit();
361     Mockito.doReturn(Bytes.toBytes("efg,h")).when(myMockRegion)
362         .getExplicitSplitPoint();
363 
364     policy = (DelimitedKeyPrefixRegionSplitPolicy) RegionSplitPolicy
365         .create(myMockRegion, conf);
366 
367     assertEquals("efg", Bytes.toString(policy.getSplitPoint()));
368 
369     Mockito.doReturn(Bytes.toBytes("ijk")).when(myMockRegion)
370     .getExplicitSplitPoint();
371     assertEquals("ijk", Bytes.toString(policy.getSplitPoint()));
372   }
373 
374   @Test
375   public void testConstantSizePolicyWithJitter() throws IOException {
376     conf.set(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
377       ConstantSizeRegionSplitPolicy.class.getName());
378     htd.setMaxFileSize(Long.MAX_VALUE);
379     boolean positiveJitter = false;
380     ConstantSizeRegionSplitPolicy policy = null;
381     while (!positiveJitter) {
382       policy = (ConstantSizeRegionSplitPolicy) RegionSplitPolicy.create(mockRegion, conf);
383       positiveJitter = policy.positiveJitterRate();
384     }
385     // add a store
386     HStore mockStore = Mockito.mock(HStore.class);
387     Mockito.doReturn(2000L).when(mockStore).getSize();
388     Mockito.doReturn(true).when(mockStore).canSplit();
389     stores.add(mockStore);
390     // Jitter shouldn't cause overflow when HTableDescriptor.MAX_FILESIZE set to Long.MAX_VALUE
391     assertFalse(policy.shouldSplit());
392   }
393 
394 }