1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.util;
20
21 import static org.junit.Assert.assertArrayEquals;
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertFalse;
24 import static org.junit.Assert.assertNotSame;
25 import static org.junit.Assert.assertTrue;
26
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Map;
30
31 import org.apache.commons.lang.ArrayUtils;
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.apache.hadoop.conf.Configuration;
35 import org.apache.hadoop.hbase.HBaseTestingUtility;
36 import org.apache.hadoop.hbase.HRegionInfo;
37 import org.apache.hadoop.hbase.testclassification.MediumTests;
38 import org.apache.hadoop.hbase.ServerName;
39 import org.apache.hadoop.hbase.TableName;
40 import org.apache.hadoop.hbase.client.HTable;
41 import org.apache.hadoop.hbase.util.RegionSplitter.HexStringSplit;
42 import org.apache.hadoop.hbase.util.RegionSplitter.DecimalStringSplit;
43 import org.apache.hadoop.hbase.util.RegionSplitter.SplitAlgorithm;
44 import org.apache.hadoop.hbase.util.RegionSplitter.UniformSplit;
45 import org.junit.AfterClass;
46 import org.junit.BeforeClass;
47 import org.junit.Test;
48 import org.junit.experimental.categories.Category;
49
50
51
52
53
54 @Category(MediumTests.class)
55 public class TestRegionSplitter {
56 private final static Log LOG = LogFactory.getLog(TestRegionSplitter.class);
57 private final static HBaseTestingUtility UTIL = new HBaseTestingUtility();
58 private final static String CF_NAME = "SPLIT_TEST_CF";
59 private final static byte xFF = (byte) 0xff;
60
61 @BeforeClass
62 public static void setup() throws Exception {
63 UTIL.startMiniCluster();
64 }
65
66 @AfterClass
67 public static void teardown() throws Exception {
68 UTIL.shutdownMiniCluster();
69 }
70
71
72
73
74 @Test
75 public void testCreatePresplitTableHex() throws Exception {
76 final List<byte[]> expectedBounds = new ArrayList<byte[]>();
77 expectedBounds.add(ArrayUtils.EMPTY_BYTE_ARRAY);
78 expectedBounds.add("10000000".getBytes());
79 expectedBounds.add("20000000".getBytes());
80 expectedBounds.add("30000000".getBytes());
81 expectedBounds.add("40000000".getBytes());
82 expectedBounds.add("50000000".getBytes());
83 expectedBounds.add("60000000".getBytes());
84 expectedBounds.add("70000000".getBytes());
85 expectedBounds.add("80000000".getBytes());
86 expectedBounds.add("90000000".getBytes());
87 expectedBounds.add("a0000000".getBytes());
88 expectedBounds.add("b0000000".getBytes());
89 expectedBounds.add("c0000000".getBytes());
90 expectedBounds.add("d0000000".getBytes());
91 expectedBounds.add("e0000000".getBytes());
92 expectedBounds.add("f0000000".getBytes());
93 expectedBounds.add(ArrayUtils.EMPTY_BYTE_ARRAY);
94
95
96 preSplitTableAndVerify(expectedBounds,
97 HexStringSplit.class.getSimpleName(),
98 TableName.valueOf("NewHexPresplitTable"));
99 }
100
101
102
103
104 @Test
105 public void testCreatePresplitTableUniform() throws Exception {
106 List<byte[]> expectedBounds = new ArrayList<byte[]>();
107 expectedBounds.add(ArrayUtils.EMPTY_BYTE_ARRAY);
108 expectedBounds.add(new byte[] { 0x10, 0, 0, 0, 0, 0, 0, 0});
109 expectedBounds.add(new byte[] { 0x20, 0, 0, 0, 0, 0, 0, 0});
110 expectedBounds.add(new byte[] { 0x30, 0, 0, 0, 0, 0, 0, 0});
111 expectedBounds.add(new byte[] { 0x40, 0, 0, 0, 0, 0, 0, 0});
112 expectedBounds.add(new byte[] { 0x50, 0, 0, 0, 0, 0, 0, 0});
113 expectedBounds.add(new byte[] { 0x60, 0, 0, 0, 0, 0, 0, 0});
114 expectedBounds.add(new byte[] { 0x70, 0, 0, 0, 0, 0, 0, 0});
115 expectedBounds.add(new byte[] {(byte)0x80, 0, 0, 0, 0, 0, 0, 0});
116 expectedBounds.add(new byte[] {(byte)0x90, 0, 0, 0, 0, 0, 0, 0});
117 expectedBounds.add(new byte[] {(byte)0xa0, 0, 0, 0, 0, 0, 0, 0});
118 expectedBounds.add(new byte[] {(byte)0xb0, 0, 0, 0, 0, 0, 0, 0});
119 expectedBounds.add(new byte[] {(byte)0xc0, 0, 0, 0, 0, 0, 0, 0});
120 expectedBounds.add(new byte[] {(byte)0xd0, 0, 0, 0, 0, 0, 0, 0});
121 expectedBounds.add(new byte[] {(byte)0xe0, 0, 0, 0, 0, 0, 0, 0});
122 expectedBounds.add(new byte[] {(byte)0xf0, 0, 0, 0, 0, 0, 0, 0});
123 expectedBounds.add(ArrayUtils.EMPTY_BYTE_ARRAY);
124
125
126 preSplitTableAndVerify(expectedBounds, UniformSplit.class.getSimpleName(),
127 TableName.valueOf("NewUniformPresplitTable"));
128 }
129
130
131
132
133
134 @Test
135 public void unitTestHexStringSplit() {
136 HexStringSplit splitter = new HexStringSplit();
137
138
139 byte[][] twoRegionsSplits = splitter.split(2);
140 assertEquals(1, twoRegionsSplits.length);
141 assertArrayEquals("80000000".getBytes(), twoRegionsSplits[0]);
142
143 byte[][] threeRegionsSplits = splitter.split(3);
144 assertEquals(2, threeRegionsSplits.length);
145 byte[] expectedSplit0 = "55555555".getBytes();
146 assertArrayEquals(expectedSplit0, threeRegionsSplits[0]);
147 byte[] expectedSplit1 = "aaaaaaaa".getBytes();
148 assertArrayEquals(expectedSplit1, threeRegionsSplits[1]);
149
150
151 byte[] splitPoint = splitter.split("10000000".getBytes(), "30000000".getBytes());
152 assertArrayEquals("20000000".getBytes(), splitPoint);
153
154 byte[] lastRow = "ffffffff".getBytes();
155 assertArrayEquals(lastRow, splitter.lastRow());
156 byte[] firstRow = "00000000".getBytes();
157 assertArrayEquals(firstRow, splitter.firstRow());
158
159
160 splitPoint = splitter.split(firstRow, "20000000".getBytes());
161 assertArrayEquals("10000000".getBytes(), splitPoint);
162
163
164 splitPoint = splitter.split("dfffffff".getBytes(), lastRow);
165 assertArrayEquals(splitPoint,"efffffff".getBytes());
166
167
168 byte[][] splits = splitter.split("00000000".getBytes(), "30000000".getBytes(), 3, false);
169 assertEquals(2, splits.length);
170 assertArrayEquals(splits[0], "10000000".getBytes());
171 assertArrayEquals(splits[1], "20000000".getBytes());
172
173 splits = splitter.split("00000000".getBytes(), "20000000".getBytes(), 2, true);
174 assertEquals(3, splits.length);
175 assertArrayEquals(splits[1], "10000000".getBytes());
176 }
177
178
179
180
181
182 @Test
183 public void unitTestDecimalStringSplit() {
184 DecimalStringSplit splitter = new DecimalStringSplit();
185
186
187 byte[][] twoRegionsSplits = splitter.split(2);
188 assertEquals(1, twoRegionsSplits.length);
189 assertArrayEquals("50000000".getBytes(), twoRegionsSplits[0]);
190
191 byte[][] threeRegionsSplits = splitter.split(3);
192 assertEquals(2, threeRegionsSplits.length);
193 byte[] expectedSplit0 = "33333333".getBytes();
194 assertArrayEquals(expectedSplit0, threeRegionsSplits[0]);
195 byte[] expectedSplit1 = "66666666".getBytes();
196 assertArrayEquals(expectedSplit1, threeRegionsSplits[1]);
197
198
199 byte[] splitPoint = splitter.split("10000000".getBytes(), "30000000".getBytes());
200 assertArrayEquals("20000000".getBytes(), splitPoint);
201
202 byte[] lastRow = "99999999".getBytes();
203 assertArrayEquals(lastRow, splitter.lastRow());
204 byte[] firstRow = "00000000".getBytes();
205 assertArrayEquals(firstRow, splitter.firstRow());
206
207
208 splitPoint = splitter.split(firstRow, "20000000".getBytes());
209 assertArrayEquals("10000000".getBytes(), splitPoint);
210
211
212 splitPoint = splitter.split(firstRow, "19999999".getBytes());
213 assertArrayEquals("09999999".getBytes(), splitPoint);
214
215
216 splitPoint = splitter.split("79999999".getBytes(), lastRow);
217 assertArrayEquals("89999999".getBytes(), splitPoint);
218 }
219
220
221
222
223
224 @Test
225 public void unitTestUniformSplit() {
226 UniformSplit splitter = new UniformSplit();
227
228
229 try {
230 splitter.split(1);
231 throw new AssertionError("Splitting into <2 regions should have thrown exception");
232 } catch (IllegalArgumentException e) { }
233
234 byte[][] twoRegionsSplits = splitter.split(2);
235 assertEquals(1, twoRegionsSplits.length);
236 assertArrayEquals(twoRegionsSplits[0],
237 new byte[] { (byte) 0x80, 0, 0, 0, 0, 0, 0, 0 });
238
239 byte[][] threeRegionsSplits = splitter.split(3);
240 assertEquals(2, threeRegionsSplits.length);
241 byte[] expectedSplit0 = new byte[] {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
242 assertArrayEquals(expectedSplit0, threeRegionsSplits[0]);
243 byte[] expectedSplit1 = new byte[] {(byte)0xAA, (byte)0xAA, (byte)0xAA, (byte)0xAA,
244 (byte)0xAA, (byte)0xAA, (byte)0xAA, (byte)0xAA};
245 assertArrayEquals(expectedSplit1, threeRegionsSplits[1]);
246
247
248 byte[] splitPoint = splitter.split(new byte[] {0x10}, new byte[] {0x30});
249 assertArrayEquals(new byte[] {0x20}, splitPoint);
250
251 byte[] lastRow = new byte[] {xFF, xFF, xFF, xFF, xFF, xFF, xFF, xFF};
252 assertArrayEquals(lastRow, splitter.lastRow());
253 byte[] firstRow = ArrayUtils.EMPTY_BYTE_ARRAY;
254 assertArrayEquals(firstRow, splitter.firstRow());
255
256 splitPoint = splitter.split(firstRow, new byte[] {0x20});
257 assertArrayEquals(splitPoint, new byte[] {0x10});
258
259 splitPoint = splitter.split(new byte[] {(byte)0xdf, xFF, xFF, xFF, xFF,
260 xFF, xFF, xFF}, lastRow);
261 assertArrayEquals(splitPoint,
262 new byte[] {(byte)0xef, xFF, xFF, xFF, xFF, xFF, xFF, xFF});
263
264 splitPoint = splitter.split(new byte[] {'a', 'a', 'a'}, new byte[] {'a', 'a', 'b'});
265 assertArrayEquals(splitPoint, new byte[] {'a', 'a', 'a', (byte)0x80 });
266
267
268 byte[][] splits = splitter.split(new byte[] {'a', 'a', 'a'}, new byte[] {'a', 'a', 'd'}, 3, false);
269 assertEquals(2, splits.length);
270 assertArrayEquals(splits[0], new byte[]{'a', 'a', 'b'});
271 assertArrayEquals(splits[1], new byte[]{'a', 'a', 'c'});
272
273 splits = splitter.split(new byte[] {'a', 'a', 'a'}, new byte[] {'a', 'a', 'e'}, 2, true);
274 assertEquals(3, splits.length);
275 assertArrayEquals(splits[1], new byte[] { 'a', 'a', 'c'});
276 }
277
278 @Test
279 public void testUserInput() {
280 SplitAlgorithm algo = new HexStringSplit();
281 assertFalse(splitFailsPrecondition(algo));
282 assertFalse(splitFailsPrecondition(algo, "00", "AA"));
283 assertTrue(splitFailsPrecondition(algo, "AA", "00"));
284 assertTrue(splitFailsPrecondition(algo, "AA", "AA"));
285 assertFalse(splitFailsPrecondition(algo, "0", "2", 3));
286 assertFalse(splitFailsPrecondition(algo, "0", "A", 11));
287 assertTrue(splitFailsPrecondition(algo, "0", "A", 12));
288
289 algo = new DecimalStringSplit();
290 assertFalse(splitFailsPrecondition(algo));
291 assertFalse(splitFailsPrecondition(algo, "00", "99"));
292 assertTrue(splitFailsPrecondition(algo, "99", "00"));
293 assertTrue(splitFailsPrecondition(algo, "99", "99"));
294 assertFalse(splitFailsPrecondition(algo, "0", "2", 3));
295 assertFalse(splitFailsPrecondition(algo, "0", "9", 10));
296 assertTrue(splitFailsPrecondition(algo, "0", "9", 11));
297
298 algo = new UniformSplit();
299 assertFalse(splitFailsPrecondition(algo));
300 assertFalse(splitFailsPrecondition(algo, "\\x00", "\\xAA"));
301 assertTrue(splitFailsPrecondition(algo, "\\xAA", "\\x00"));
302 assertTrue(splitFailsPrecondition(algo, "\\xAA", "\\xAA"));
303 assertFalse(splitFailsPrecondition(algo, "\\x00", "\\x02", 3));
304 assertFalse(splitFailsPrecondition(algo, "\\x00", "\\x0A", 11));
305 assertFalse(splitFailsPrecondition(algo, "\\x00", "\\x0A", 12));
306 }
307
308 private boolean splitFailsPrecondition(SplitAlgorithm algo) {
309 return splitFailsPrecondition(algo, 100);
310 }
311
312 private boolean splitFailsPrecondition(SplitAlgorithm algo, String firstRow,
313 String lastRow) {
314 return splitFailsPrecondition(algo, firstRow, lastRow, 100);
315 }
316
317 private boolean splitFailsPrecondition(SplitAlgorithm algo, String firstRow,
318 String lastRow, int numRegions) {
319 algo.setFirstRow(firstRow);
320 algo.setLastRow(lastRow);
321 return splitFailsPrecondition(algo, numRegions);
322 }
323
324 private boolean splitFailsPrecondition(SplitAlgorithm algo, int numRegions) {
325 try {
326 byte[][] s = algo.split(numRegions);
327 LOG.debug("split algo = " + algo);
328 if (s != null) {
329 StringBuilder sb = new StringBuilder();
330 for (byte[] b : s) {
331 sb.append(Bytes.toStringBinary(b) + " ");
332 }
333 LOG.debug(sb.toString());
334 }
335 return false;
336 } catch (IllegalArgumentException e) {
337 return true;
338 } catch (IllegalStateException e) {
339 return true;
340 } catch (IndexOutOfBoundsException e) {
341 return true;
342 }
343 }
344
345
346
347
348
349
350
351 private void preSplitTableAndVerify(List<byte[]> expectedBounds,
352 String splitClass, TableName tableName) throws Exception {
353 final int numRegions = expectedBounds.size()-1;
354 final Configuration conf = UTIL.getConfiguration();
355 conf.setInt("split.count", numRegions);
356 SplitAlgorithm splitAlgo = RegionSplitter.newSplitAlgoInstance(conf, splitClass);
357 RegionSplitter.createPresplitTable(tableName, splitAlgo, new String[] {CF_NAME}, conf);
358 verifyBounds(expectedBounds, tableName);
359 }
360
361 @Test
362 public void noopRollingSplit() throws Exception {
363 final List<byte[]> expectedBounds = new ArrayList<byte[]>();
364 expectedBounds.add(ArrayUtils.EMPTY_BYTE_ARRAY);
365 rollingSplitAndVerify(
366 TableName.valueOf(TestRegionSplitter.class.getSimpleName()),
367 "UniformSplit", expectedBounds);
368 }
369
370 private void rollingSplitAndVerify(TableName tableName, String splitClass,
371 List<byte[]> expectedBounds) throws Exception {
372 final Configuration conf = UTIL.getConfiguration();
373
374
375 conf.setInt("split.outstanding", 5);
376 SplitAlgorithm splitAlgo = RegionSplitter.newSplitAlgoInstance(conf, splitClass);
377 RegionSplitter.rollingSplit(tableName, splitAlgo, conf);
378 verifyBounds(expectedBounds, tableName);
379 }
380
381 private void verifyBounds(List<byte[]> expectedBounds, TableName tableName)
382 throws Exception {
383
384 final Configuration conf = UTIL.getConfiguration();
385 final int numRegions = expectedBounds.size()-1;
386 final HTable hTable = new HTable(conf, tableName);
387 final Map<HRegionInfo, ServerName> regionInfoMap = hTable.getRegionLocations();
388 assertEquals(numRegions, regionInfoMap.size());
389 for (Map.Entry<HRegionInfo, ServerName> entry: regionInfoMap.entrySet()) {
390 final HRegionInfo regionInfo = entry.getKey();
391 byte[] regionStart = regionInfo.getStartKey();
392 byte[] regionEnd = regionInfo.getEndKey();
393
394
395 int startBoundaryIndex = indexOfBytes(expectedBounds, regionStart);
396 assertNotSame(-1, startBoundaryIndex);
397
398
399
400 byte[] expectedRegionEnd = expectedBounds.get(
401 startBoundaryIndex+1);
402 assertEquals(0, Bytes.compareTo(regionEnd, expectedRegionEnd));
403 }
404 hTable.close();
405 }
406
407
408
409
410
411
412
413
414
415 static private int indexOfBytes(List<byte[]> list, byte[] compareTo) {
416 int listIndex = 0;
417 for(byte[] elem: list) {
418 if(Bytes.BYTES_COMPARATOR.compare(elem, compareTo) == 0) {
419 return listIndex;
420 }
421 listIndex++;
422 }
423 return -1;
424 }
425
426 }
427