1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.regionserver;
20
21 import static org.apache.hadoop.hbase.regionserver.TestRegionServerNoMaster.*;
22 import java.io.IOException;
23 import java.util.Random;
24 import java.util.concurrent.ExecutorService;
25 import java.util.concurrent.Executors;
26 import java.util.concurrent.TimeUnit;
27 import java.util.concurrent.atomic.AtomicBoolean;
28 import java.util.concurrent.atomic.AtomicReference;
29
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.hadoop.hbase.Cell;
33 import org.apache.hadoop.hbase.HBaseTestingUtility;
34 import org.apache.hadoop.hbase.HConstants;
35 import org.apache.hadoop.hbase.HRegionInfo;
36 import org.apache.hadoop.hbase.testclassification.MediumTests;
37 import org.apache.hadoop.hbase.TableName;
38 import org.apache.hadoop.hbase.TestMetaTableAccessor;
39 import org.apache.hadoop.hbase.client.Consistency;
40 import org.apache.hadoop.hbase.client.Get;
41 import org.apache.hadoop.hbase.client.HTable;
42 import org.apache.hadoop.hbase.client.Put;
43 import org.apache.hadoop.hbase.client.Result;
44 import org.apache.hadoop.hbase.client.Table;
45 import org.apache.hadoop.hbase.io.hfile.HFileScanner;
46 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
47 import org.apache.hadoop.hbase.protobuf.RequestConverter;
48 import org.apache.hadoop.hbase.protobuf.generated.ClientProtos;
49 import org.apache.hadoop.hbase.util.Bytes;
50 import org.apache.hadoop.hbase.util.Threads;
51 import org.apache.hadoop.hbase.zookeeper.ZKAssign;
52 import org.apache.hadoop.hdfs.DFSConfigKeys;
53 import org.apache.hadoop.util.StringUtils;
54 import org.junit.After;
55 import org.junit.AfterClass;
56 import org.junit.Assert;
57 import org.junit.BeforeClass;
58 import org.junit.Test;
59 import org.junit.experimental.categories.Category;
60
61 import com.google.protobuf.ServiceException;
62
63
64
65
66
67 @Category(MediumTests.class)
68 public class TestRegionReplicas {
69 private static final Log LOG = LogFactory.getLog(TestRegionReplicas.class);
70
71 private static final int NB_SERVERS = 1;
72 private static HTable table;
73 private static final byte[] row = "TestRegionReplicas".getBytes();
74
75 private static HRegionInfo hriPrimary;
76 private static HRegionInfo hriSecondary;
77
78 private static final HBaseTestingUtility HTU = new HBaseTestingUtility();
79 private static final byte[] f = HConstants.CATALOG_FAMILY;
80
81 @BeforeClass
82 public static void before() throws Exception {
83
84
85 HTU.getConfiguration().setInt(DFSConfigKeys.DFS_BLOCK_SIZE_KEY, 8192);
86 HTU.getConfiguration().setInt(DFSConfigKeys.DFS_CLIENT_READ_PREFETCH_SIZE_KEY, 1);
87 HTU.getConfiguration().setInt(HConstants.HREGION_MEMSTORE_FLUSH_SIZE, 128 * 1024 * 1024);
88
89 HTU.startMiniCluster(NB_SERVERS);
90 final TableName tableName = TableName.valueOf(TestRegionReplicas.class.getSimpleName());
91
92
93 table = HTU.createTable(tableName, f);
94
95 hriPrimary = table.getRegionLocation(row, false).getRegionInfo();
96
97
98 hriSecondary = new HRegionInfo(hriPrimary.getTable(), hriPrimary.getStartKey(),
99 hriPrimary.getEndKey(), hriPrimary.isSplit(), hriPrimary.getRegionId(), 1);
100
101
102 TestRegionServerNoMaster.stopMasterAndAssignMeta(HTU);
103 }
104
105 @AfterClass
106 public static void afterClass() throws Exception {
107 table.close();
108 HTU.shutdownMiniCluster();
109 }
110
111 @After
112 public void after() throws Exception {
113
114
115
116 ZKAssign.deleteNodeFailSilent(HTU.getZooKeeperWatcher(), hriPrimary);
117 }
118
119 private HRegionServer getRS() {
120 return HTU.getMiniHBaseCluster().getRegionServer(0);
121 }
122
123 @Test(timeout = 60000)
124 public void testOpenRegionReplica() throws Exception {
125 openRegion(HTU, getRS(), hriSecondary);
126 try {
127
128 HTU.loadNumericRows(table, f, 0, 1000);
129
130
131 Assert.assertEquals(1000, HTU.countRows(table));
132 } finally {
133 HTU.deleteNumericRows(table, f, 0, 1000);
134 closeRegion(HTU, getRS(), hriSecondary);
135 }
136 }
137
138
139 @Test(timeout = 60000)
140 public void testRegionReplicaUpdatesMetaLocation() throws Exception {
141 openRegion(HTU, getRS(), hriSecondary);
142 Table meta = null;
143 try {
144 meta = HTU.getConnection().getTable(TableName.META_TABLE_NAME);
145 TestMetaTableAccessor.assertMetaLocation(meta, hriPrimary.getRegionName()
146 , getRS().getServerName(), -1, 1, false);
147 } finally {
148 if (meta != null ) meta.close();
149 closeRegion(HTU, getRS(), hriSecondary);
150 }
151 }
152
153 @Test(timeout = 60000)
154 public void testRegionReplicaGets() throws Exception {
155 try {
156
157 HTU.loadNumericRows(table, f, 0, 1000);
158
159 Assert.assertEquals(1000, HTU.countRows(table));
160
161 Region region = getRS().getRegionByEncodedName(hriPrimary.getEncodedName());
162 region.flush(true);
163
164 openRegion(HTU, getRS(), hriSecondary);
165
166
167 region = getRS().getFromOnlineRegions(hriSecondary.getEncodedName());
168 assertGet(region, 42, true);
169
170 assertGetRpc(hriSecondary, 42, true);
171 } finally {
172 HTU.deleteNumericRows(table, HConstants.CATALOG_FAMILY, 0, 1000);
173 closeRegion(HTU, getRS(), hriSecondary);
174 }
175 }
176
177 @Test(timeout = 60000)
178 public void testGetOnTargetRegionReplica() throws Exception {
179 try {
180
181 HTU.loadNumericRows(table, f, 0, 1000);
182
183 Assert.assertEquals(1000, HTU.countRows(table));
184
185 Region region = getRS().getRegionByEncodedName(hriPrimary.getEncodedName());
186 region.flush(true);
187
188 openRegion(HTU, getRS(), hriSecondary);
189
190 Thread.sleep(5000);
191 table.clearRegionCache();
192
193
194 byte[] row = Bytes.toBytes(String.valueOf(42));
195 Get get = new Get(row);
196 get.setConsistency(Consistency.TIMELINE);
197 get.setReplicaId(1);
198 Result result = table.get(get);
199 Assert.assertArrayEquals(row, result.getValue(f, null));
200 } finally {
201 HTU.deleteNumericRows(table, HConstants.CATALOG_FAMILY, 0, 1000);
202 closeRegion(HTU, getRS(), hriSecondary);
203 }
204 }
205
206 private void assertGet(Region region, int value, boolean expect) throws IOException {
207 byte[] row = Bytes.toBytes(String.valueOf(value));
208 Get get = new Get(row);
209 Result result = region.get(get);
210 if (expect) {
211 Assert.assertArrayEquals(row, result.getValue(f, null));
212 } else {
213 result.isEmpty();
214 }
215 }
216
217
218 private void assertGetRpc(HRegionInfo info, int value, boolean expect)
219 throws IOException, ServiceException {
220 byte[] row = Bytes.toBytes(String.valueOf(value));
221 Get get = new Get(row);
222 ClientProtos.GetRequest getReq = RequestConverter.buildGetRequest(info.getRegionName(), get);
223 ClientProtos.GetResponse getResp = getRS().getRSRpcServices().get(null, getReq);
224 Result result = ProtobufUtil.toResult(getResp.getResult());
225 if (expect) {
226 Assert.assertArrayEquals(row, result.getValue(f, null));
227 } else {
228 result.isEmpty();
229 }
230 }
231
232 private void restartRegionServer() throws Exception {
233 afterClass();
234 before();
235 }
236
237 @Test(timeout = 300000)
238 public void testRefreshStoreFiles() throws Exception {
239
240 final int refreshPeriod = 2000;
241 HTU.getConfiguration().setInt("hbase.hstore.compactionThreshold", 100);
242 HTU.getConfiguration().setInt(StorefileRefresherChore.REGIONSERVER_STOREFILE_REFRESH_PERIOD,
243 refreshPeriod);
244
245 restartRegionServer();
246
247 try {
248 LOG.info("Opening the secondary region " + hriSecondary.getEncodedName());
249 openRegion(HTU, getRS(), hriSecondary);
250
251
252 LOG.info("Loading data to primary region");
253 HTU.loadNumericRows(table, f, 0, 1000);
254
255 Assert.assertEquals(1000, HTU.countRows(table));
256
257 LOG.info("Flushing primary region");
258 Region region = getRS().getRegionByEncodedName(hriPrimary.getEncodedName());
259 region.flush(true);
260
261
262 LOG.info("Sleeping for " + (4 * refreshPeriod));
263 Threads.sleep(4 * refreshPeriod);
264
265 LOG.info("Checking results from secondary region replica");
266 Region secondaryRegion = getRS().getFromOnlineRegions(hriSecondary.getEncodedName());
267 Assert.assertEquals(1, secondaryRegion.getStore(f).getStorefilesCount());
268
269 assertGet(secondaryRegion, 42, true);
270 assertGetRpc(hriSecondary, 42, true);
271 assertGetRpc(hriSecondary, 1042, false);
272
273
274 HTU.loadNumericRows(table, f, 1000, 1100);
275 region = getRS().getRegionByEncodedName(hriPrimary.getEncodedName());
276 region.flush(true);
277
278 HTU.loadNumericRows(table, f, 2000, 2100);
279 region = getRS().getRegionByEncodedName(hriPrimary.getEncodedName());
280 region.flush(true);
281
282
283 Threads.sleep(4 * refreshPeriod);
284
285 assertGetRpc(hriSecondary, 42, true);
286 assertGetRpc(hriSecondary, 1042, true);
287 assertGetRpc(hriSecondary, 2042, true);
288
289
290 Assert.assertEquals(3, secondaryRegion.getStore(f).getStorefilesCount());
291
292
293 HTU.compact(table.getName(), true);
294
295 long wakeUpTime = System.currentTimeMillis() + 4 * refreshPeriod;
296 while (System.currentTimeMillis() < wakeUpTime) {
297 assertGetRpc(hriSecondary, 42, true);
298 assertGetRpc(hriSecondary, 1042, true);
299 assertGetRpc(hriSecondary, 2042, true);
300 Threads.sleep(10);
301 }
302
303
304 Assert.assertEquals(1, secondaryRegion.getStore(f).getStorefilesCount());
305
306 } finally {
307 HTU.deleteNumericRows(table, HConstants.CATALOG_FAMILY, 0, 1000);
308 closeRegion(HTU, getRS(), hriSecondary);
309 }
310 }
311
312 @Test(timeout = 300000)
313 public void testFlushAndCompactionsInPrimary() throws Exception {
314
315 long runtime = 30 * 1000;
316
317 final int refreshPeriod = 100;
318 HTU.getConfiguration().setInt("hbase.hstore.compactionThreshold", 3);
319 HTU.getConfiguration().setInt(StorefileRefresherChore.REGIONSERVER_STOREFILE_REFRESH_PERIOD, refreshPeriod);
320
321 restartRegionServer();
322 final int startKey = 0, endKey = 1000;
323
324 try {
325 openRegion(HTU, getRS(), hriSecondary);
326
327
328 HTU.loadNumericRows(table, f, startKey, endKey);
329 TestRegionServerNoMaster.flushRegion(HTU, hriPrimary);
330
331 Threads.sleep(2 * refreshPeriod);
332
333 final AtomicBoolean running = new AtomicBoolean(true);
334 @SuppressWarnings("unchecked")
335 final AtomicReference<Exception>[] exceptions = new AtomicReference[3];
336 for (int i=0; i < exceptions.length; i++) {
337 exceptions[i] = new AtomicReference<Exception>();
338 }
339
340 Runnable writer = new Runnable() {
341 int key = startKey;
342 @Override
343 public void run() {
344 try {
345 while (running.get()) {
346 byte[] data = Bytes.toBytes(String.valueOf(key));
347 Put put = new Put(data);
348 put.add(f, null, data);
349 table.put(put);
350 key++;
351 if (key == endKey) key = startKey;
352 }
353 } catch (Exception ex) {
354 LOG.warn(ex);
355 exceptions[0].compareAndSet(null, ex);
356 }
357 }
358 };
359
360 Runnable flusherCompactor = new Runnable() {
361 Random random = new Random();
362 @Override
363 public void run() {
364 try {
365 while (running.get()) {
366
367 if (random.nextBoolean()) {
368 TestRegionServerNoMaster.flushRegion(HTU, hriPrimary);
369 } else {
370 HTU.compact(table.getName(), random.nextBoolean());
371 }
372 }
373 } catch (Exception ex) {
374 LOG.warn(ex);
375 exceptions[1].compareAndSet(null, ex);
376 }
377 }
378 };
379
380 Runnable reader = new Runnable() {
381 Random random = new Random();
382 @Override
383 public void run() {
384 try {
385 while (running.get()) {
386
387 if (random.nextInt(10) == 0) {
388 try {
389 closeRegion(HTU, getRS(), hriSecondary);
390 } catch (Exception ex) {
391 LOG.warn("Failed closing the region " + hriSecondary + " " + StringUtils.stringifyException(ex));
392 exceptions[2].compareAndSet(null, ex);
393 }
394 try {
395 openRegion(HTU, getRS(), hriSecondary);
396 } catch (Exception ex) {
397 LOG.warn("Failed opening the region " + hriSecondary + " " + StringUtils.stringifyException(ex));
398 exceptions[2].compareAndSet(null, ex);
399 }
400 }
401
402 int key = random.nextInt(endKey - startKey) + startKey;
403 assertGetRpc(hriSecondary, key, true);
404 }
405 } catch (Exception ex) {
406 LOG.warn("Failed getting the value in the region " + hriSecondary + " " + StringUtils.stringifyException(ex));
407 exceptions[2].compareAndSet(null, ex);
408 }
409 }
410 };
411
412 LOG.info("Starting writer and reader");
413 ExecutorService executor = Executors.newFixedThreadPool(3);
414 executor.submit(writer);
415 executor.submit(flusherCompactor);
416 executor.submit(reader);
417
418
419 Threads.sleep(runtime);
420 running.set(false);
421 executor.shutdown();
422 executor.awaitTermination(30, TimeUnit.SECONDS);
423
424 for (AtomicReference<Exception> exRef : exceptions) {
425 Assert.assertNull(exRef.get());
426 }
427 } finally {
428 HTU.deleteNumericRows(table, HConstants.CATALOG_FAMILY, startKey, endKey);
429 closeRegion(HTU, getRS(), hriSecondary);
430 }
431 }
432
433 @Test(timeout = 300000)
434 public void testVerifySecondaryAbilityToReadWithOnFiles() throws Exception {
435
436 HTU.getConfiguration().setInt(StorefileRefresherChore.REGIONSERVER_STOREFILE_REFRESH_PERIOD, 0);
437 restartRegionServer();
438
439 try {
440 LOG.info("Opening the secondary region " + hriSecondary.getEncodedName());
441 openRegion(HTU, getRS(), hriSecondary);
442
443
444 LOG.info("Loading data to primary region");
445 for (int i = 0; i < 3; ++i) {
446 HTU.loadNumericRows(table, f, i * 1000, (i + 1) * 1000);
447 Region region = getRS().getRegionByEncodedName(hriPrimary.getEncodedName());
448 region.flush(true);
449 }
450
451 Region primaryRegion = getRS().getFromOnlineRegions(hriPrimary.getEncodedName());
452 Assert.assertEquals(3, primaryRegion.getStore(f).getStorefilesCount());
453
454
455 Region secondaryRegion = getRS().getFromOnlineRegions(hriSecondary.getEncodedName());
456 secondaryRegion.getStore(f).refreshStoreFiles();
457 Assert.assertEquals(3, secondaryRegion.getStore(f).getStorefilesCount());
458
459
460 LOG.info("Force Major compaction on primary region " + hriPrimary);
461 primaryRegion.compact(true);
462 Assert.assertEquals(1, primaryRegion.getStore(f).getStorefilesCount());
463
464
465
466
467
468 int keys = 0;
469 int sum = 0;
470 for (StoreFile sf: secondaryRegion.getStore(f).getStorefiles()) {
471
472 LOG.debug(getRS().getFileSystem().exists(sf.getPath()));
473 Assert.assertFalse(getRS().getFileSystem().exists(sf.getPath()));
474
475 HFileScanner scanner = sf.getReader().getScanner(false, false);
476 scanner.seekTo();
477 do {
478 keys++;
479
480 Cell cell = scanner.getKeyValue();
481 sum += Integer.parseInt(Bytes.toString(cell.getRowArray(),
482 cell.getRowOffset(), cell.getRowLength()));
483 } while (scanner.next());
484 }
485 Assert.assertEquals(3000, keys);
486 Assert.assertEquals(4498500, sum);
487 } finally {
488 HTU.deleteNumericRows(table, HConstants.CATALOG_FAMILY, 0, 1000);
489 closeRegion(HTU, getRS(), hriSecondary);
490 }
491 }
492 }