1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.master.normalizer;
20
21 import static org.junit.Assert.assertEquals;
22 import static org.junit.Assert.assertFalse;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertTrue;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collections;
29 import java.util.Comparator;
30 import java.util.List;
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.apache.hadoop.hbase.CoordinatedStateException;
34 import org.apache.hadoop.hbase.HBaseTestingUtility;
35 import org.apache.hadoop.hbase.HConstants;
36 import org.apache.hadoop.hbase.HRegionInfo;
37 import org.apache.hadoop.hbase.HTableDescriptor;
38 import org.apache.hadoop.hbase.MetaTableAccessor;
39 import org.apache.hadoop.hbase.RegionLoad;
40 import org.apache.hadoop.hbase.ServerLoad;
41 import org.apache.hadoop.hbase.ServerName;
42 import org.apache.hadoop.hbase.TableName;
43 import org.apache.hadoop.hbase.Waiter;
44 import org.apache.hadoop.hbase.client.Admin;
45 import org.apache.hadoop.hbase.client.HTable;
46 import org.apache.hadoop.hbase.client.Put;
47 import org.apache.hadoop.hbase.master.HMaster;
48 import org.apache.hadoop.hbase.master.MasterServices;
49 import org.apache.hadoop.hbase.quotas.QuotaUtil;
50 import org.apache.hadoop.hbase.regionserver.HRegion;
51 import org.apache.hadoop.hbase.regionserver.Region;
52 import org.apache.hadoop.hbase.testclassification.MediumTests;
53 import org.apache.hadoop.hbase.util.Bytes;
54 import org.apache.hadoop.hbase.util.LoadTestKVGenerator;
55 import org.junit.AfterClass;
56 import org.junit.Before;
57 import org.junit.BeforeClass;
58 import org.junit.Rule;
59 import org.junit.Test;
60 import org.junit.experimental.categories.Category;
61 import org.junit.rules.TestName;
62
63
64
65
66 @Category(MediumTests.class)
67 public class TestSimpleRegionNormalizerOnCluster {
68 private static final Log LOG = LogFactory.getLog(TestSimpleRegionNormalizerOnCluster.class);
69 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
70 private static final byte[] FAMILYNAME = Bytes.toBytes("fam");
71 private static Admin admin;
72 private static HMaster master;
73
74 @Rule
75 public TestName name = new TestName();
76
77 @BeforeClass
78 public static void beforeAllTests() throws Exception {
79
80 TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 3);
81 TEST_UTIL.getConfiguration().setBoolean(QuotaUtil.QUOTA_CONF_KEY, true);
82
83
84 TEST_UTIL.getConfiguration().setInt("hbase.normalizer.merge.min_region_age.days", 0);
85
86
87 TEST_UTIL.startMiniCluster(1);
88
89 admin = TEST_UTIL.getHBaseAdmin();
90 master = TEST_UTIL.getHBaseCluster().getMaster();
91 assertNotNull(master);
92 }
93
94 @AfterClass
95 public static void afterAllTests() throws Exception {
96 TEST_UTIL.shutdownMiniCluster();
97 }
98
99 @Before
100 public void before() throws IOException {
101
102 admin.setNormalizerRunning(false);
103 }
104
105 @Test
106 public void testHonorsNormalizerSwitch() throws IOException {
107 assertFalse(admin.isNormalizerEnabled());
108 assertFalse(admin.normalize());
109 assertFalse(admin.setNormalizerRunning(true));
110 assertTrue(admin.normalize());
111 }
112
113
114 @Test(timeout = 60000)
115 @SuppressWarnings("deprecation")
116 public void testRegionNormalizationSplitOnCluster() throws Exception {
117 final TableName TABLENAME = TableName.valueOf(name.getMethodName());
118
119 try (HTable ht = TEST_UTIL.createMultiRegionTable(TABLENAME, FAMILYNAME, 5)) {
120
121 List<HRegion> generatedRegions = TEST_UTIL.getHBaseCluster().getRegions(TABLENAME);
122 Collections.sort(generatedRegions, new Comparator<HRegion>() {
123 @Override
124 public int compare(HRegion o1, HRegion o2) {
125 return o1.getRegionInfo().compareTo(o2.getRegionInfo());
126 }
127 });
128
129 HRegion region = generatedRegions.get(0);
130 generateTestData(region, 1);
131 region.flush(true);
132
133 region = generatedRegions.get(1);
134 generateTestData(region, 1);
135 region.flush(true);
136
137 region = generatedRegions.get(2);
138 generateTestData(region, 2);
139 region.flush(true);
140
141 region = generatedRegions.get(3);
142 generateTestData(region, 2);
143 region.flush(true);
144
145 region = generatedRegions.get(4);
146 generateTestData(region, 5);
147 region.flush(true);
148
149 }
150
151 HTableDescriptor htd = admin.getTableDescriptor(TABLENAME);
152 htd.setNormalizationEnabled(true);
153 admin.modifyTable(TABLENAME, htd);
154
155 admin.flush(TABLENAME);
156 admin.setNormalizerRunning(true);
157
158 System.out.println(admin.getTableDescriptor(TABLENAME));
159
160 assertEquals(5, MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), TABLENAME));
161
162
163 Thread.sleep(5000);
164 boolean b = master.normalizeRegions();
165 assertTrue(b);
166
167 while (true) {
168 List<HRegion> regions = TEST_UTIL.getHBaseCluster().getRegions(TABLENAME);
169 int cnt = 0;
170 for (HRegion region : regions) {
171 String regionName = region.getRegionInfo().getRegionNameAsString();
172 if (regionName.startsWith("testRegionNormalizationSplitOnCluster,zzzzz")) {
173 cnt++;
174 }
175 }
176 if (cnt >= 2) {
177 break;
178 }
179 }
180 admin.disableTable(TABLENAME);
181 admin.deleteTable(TABLENAME);
182 }
183
184 @Test(timeout = 60000)
185 @SuppressWarnings("deprecation")
186 public void testRegionNormalizationMergeOnCluster() throws Exception {
187 final TableName TABLENAME = TableName.valueOf(name.getMethodName());
188
189
190 createTable(TABLENAME, Arrays.asList(1, 1, 3, 3, 5));
191
192 HTableDescriptor htd = admin.getTableDescriptor(TABLENAME);
193 htd.setNormalizationEnabled(true);
194 admin.modifyTable(TABLENAME, htd);
195
196 admin.flush(TABLENAME);
197
198 assertEquals(5, MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), TABLENAME));
199
200
201 admin.setNormalizerRunning(true);
202 Thread.sleep(5000);
203 master.normalizeRegions();
204
205 while (MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), TABLENAME) > 4) {
206 LOG.info("Waiting for normalization merge to complete");
207 Thread.sleep(100);
208 }
209
210 assertEquals(4, MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), TABLENAME));
211 dropIfExists(TABLENAME);
212 }
213
214 @Test(timeout = 60000)
215 public void testMultiTablePlans()
216 throws IOException, InterruptedException, CoordinatedStateException {
217
218 int numOfTables = 3;
219 String methodName = name.getMethodName();
220 List<TableName> tableNames = new ArrayList<>();
221
222 for (int i = 0; i < numOfTables; i++) {
223 tableNames.add(TableName.valueOf(methodName + i));
224 }
225 createTable(tableNames.get(0), Arrays.asList(1, 1, 3, 5, 3));
226 createTable(tableNames.get(1), Arrays.asList(1, 1, 1, 1, 1));
227 createTable(tableNames.get(2), Arrays.asList(1, 1, 3, 5, 3));
228
229
230 for (int i = 0; i < numOfTables; i++) {
231 HTableDescriptor htd = admin.getTableDescriptor(tableNames.get(i));
232 htd.setNormalizationEnabled(true);
233 admin.modifyTable(tableNames.get(i), htd);
234 }
235 for (int i = 0; i < numOfTables; i++) {
236
237 assertEquals(5,
238 MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), tableNames.get(i)));
239 }
240 admin.setNormalizerRunning(true);
241 Thread.sleep(5000);
242 boolean checkStatus = master.normalizeRegions();
243 assertTrue(checkStatus);
244
245 Thread.sleep(5000);
246
247
248
249
250
251 assertEquals(4, MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), tableNames.get(0)));
252 assertEquals(5, MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), tableNames.get(1)));
253 assertEquals(4, MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), tableNames.get(2)));
254 for (int i = 0; i < numOfTables; i++) {
255 dropIfExists(tableNames.get(i));
256 }
257 }
258
259 private void createTable(TableName TABLENAME, List<Integer> rowsInRespectiveRegions)
260 throws IOException {
261 int numOfRegions = rowsInRespectiveRegions.size();
262 try (HTable ht = TEST_UTIL.createMultiRegionTable(TABLENAME, FAMILYNAME, numOfRegions)) {
263
264 List<HRegion> generatedRegions = TEST_UTIL.getHBaseCluster().getRegions(TABLENAME);
265 Collections.sort(generatedRegions, new Comparator<HRegion>() {
266 @Override
267 public int compare(HRegion o1, HRegion o2) {
268 return o1.getRegionInfo().compareTo(o2.getRegionInfo());
269 }
270 });
271 for (int i = 0; i < numOfRegions; i++) {
272 HRegion region = generatedRegions.get(i);
273 generateTestData(region, rowsInRespectiveRegions.get(i));
274 region.flush(true);
275 }
276 }
277 }
278
279 private static void waitForTableSplit(final TableName tableName, final int targetRegionCount)
280 throws IOException {
281 TEST_UTIL.waitFor(10*1000, new Waiter.ExplainingPredicate<IOException>() {
282 @Override public String explainFailure() {
283 return "expected normalizer to split region.";
284 }
285 @Override public boolean evaluate() throws IOException {
286 final int currentRegionCount =
287 MetaTableAccessor.getRegionCount(TEST_UTIL.getConnection(), tableName);
288 return currentRegionCount >= targetRegionCount;
289 }
290 });
291 }
292
293 private static List<HRegion> generateTestData(final TableName tableName,
294 final int... regionSizesMb) throws IOException {
295 final List<HRegion> generatedRegions;
296 final int numRegions = regionSizesMb.length;
297 try (HTable ignored = TEST_UTIL.createMultiRegionTable(tableName, FAMILYNAME, numRegions)) {
298
299 generatedRegions = TEST_UTIL.getHBaseCluster().getRegions(tableName);
300
301 Collections.sort(generatedRegions, new Comparator<HRegion>() {
302 @Override
303 public int compare(HRegion o1, HRegion o2) {
304 return o1.getRegionInfo().compareTo(o2.getRegionInfo());
305 }
306 });
307 assertEquals(numRegions, generatedRegions.size());
308 for (int i = 0; i < numRegions; i++) {
309 HRegion region = generatedRegions.get(i);
310 generateTestData(region, regionSizesMb[i]);
311 region.flush(true);
312 }
313 }
314 return generatedRegions;
315 }
316
317 private static void generateTestData(Region region, int numRows) throws IOException {
318
319 LoadTestKVGenerator dataGenerator = new LoadTestKVGenerator(1024 * 1024, 1024 * 1024);
320 for (int i = 0; i < numRows; ++i) {
321 byte[] key = Bytes.add(region.getRegionInfo().getStartKey(), Bytes.toBytes(i));
322 for (int j = 0; j < 1; ++j) {
323 Put put = new Put(key);
324 byte[] col = Bytes.toBytes(String.valueOf(j));
325 byte[] value = dataGenerator.generateRandomSizeValue(key, col);
326 put.add(FAMILYNAME, col, value);
327 region.put(put);
328 }
329 }
330 }
331
332 private static double getRegionSizeMB(final MasterServices masterServices,
333 final HRegionInfo regionInfo) {
334 ServerName sn =
335 masterServices.getAssignmentManager().getRegionStates().getRegionServerOfRegion(regionInfo);
336 if (sn == null) {
337 LOG.debug(regionInfo.getRegionNameAsString() + " region was not found on any Server");
338 return -1;
339 }
340 ServerLoad load = masterServices.getServerManager().getLoad(sn);
341 if (load == null) {
342 LOG.debug(sn.getServerName() + " was not found in online servers");
343 return -1;
344 }
345 RegionLoad regionLoad = load.getRegionsLoad().get(regionInfo.getRegionName());
346 if (regionLoad == null) {
347 LOG.debug(regionInfo.getRegionNameAsString() + " was not found in RegionsLoad");
348 return -1;
349 }
350 return regionLoad.getStorefileSizeMB();
351 }
352
353
354 private static void dropIfExists(final TableName tableName) throws IOException {
355 if (tableName != null && admin.tableExists(tableName)) {
356 if (admin.isTableEnabled(tableName)) {
357 admin.disableTable(tableName);
358 }
359 admin.deleteTable(tableName);
360 }
361 }
362 }