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