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