1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.regionserver.wal;
21
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertNull;
24 import static org.junit.Assert.assertTrue;
25
26 import java.io.FileNotFoundException;
27 import java.io.IOException;
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.concurrent.atomic.AtomicBoolean;
32 import java.util.concurrent.atomic.AtomicLong;
33
34 import org.apache.hadoop.conf.Configuration;
35 import org.apache.hadoop.fs.FSDataInputStream;
36 import org.apache.hadoop.fs.FSDataOutputStream;
37 import org.apache.hadoop.fs.FileStatus;
38 import org.apache.hadoop.fs.FileSystem;
39 import org.apache.hadoop.fs.Path;
40 import org.apache.hadoop.hbase.HBaseTestingUtility;
41 import org.apache.hadoop.hbase.HRegionInfo;
42 import org.apache.hadoop.hbase.HTableDescriptor;
43 import org.apache.hadoop.hbase.KeyValue;
44 import org.apache.hadoop.hbase.regionserver.HRegion;
45 import org.apache.hadoop.hbase.util.Bytes;
46 import org.apache.hadoop.hbase.util.Threads;
47 import org.apache.hadoop.ipc.RemoteException;
48 import org.junit.After;
49 import org.junit.AfterClass;
50 import org.junit.Before;
51 import org.junit.BeforeClass;
52 import org.junit.Test;
53
54
55
56
57 public class TestHLogSplit {
58
59 private Configuration conf;
60 private FileSystem fs;
61
62 private final static HBaseTestingUtility
63 TEST_UTIL = new HBaseTestingUtility();
64
65
66 private static final Path hbaseDir = new Path("/hbase");
67 private static final Path hlogDir = new Path(hbaseDir, "hlog");
68 private static final Path oldLogDir = new Path(hbaseDir, "hlog.old");
69 private static final Path corruptDir = new Path(hbaseDir, ".corrupt");
70
71 private static final int NUM_WRITERS = 10;
72 private static final int ENTRIES = 10;
73
74 private HLog.Writer[] writer = new HLog.Writer[NUM_WRITERS];
75 private long seq = 0;
76 private static final byte[] TABLE_NAME = "t1".getBytes();
77 private static final byte[] FAMILY = "f1".getBytes();
78 private static final byte[] QUALIFIER = "q1".getBytes();
79 private static final byte[] VALUE = "v1".getBytes();
80 private static final String HLOG_FILE_PREFIX = "hlog.dat.";
81 private static List<String> regions;
82 private static final String HBASE_SKIP_ERRORS = "hbase.hlog.split.skip.errors";
83
84
85 static enum Corruptions {
86 INSERT_GARBAGE_ON_FIRST_LINE,
87 INSERT_GARBAGE_IN_THE_MIDDLE,
88 APPEND_GARBAGE,
89 TRUNCATE,
90 }
91
92 @BeforeClass
93 public static void setUpBeforeClass() throws Exception {
94 TEST_UTIL.getConfiguration().
95 setInt("hbase.regionserver.flushlogentries", 1);
96 TEST_UTIL.getConfiguration().
97 setBoolean("dfs.support.append", true);
98 TEST_UTIL.getConfiguration().
99 setStrings("hbase.rootdir", hbaseDir.toString());
100 TEST_UTIL.getConfiguration().
101 setClass("hbase.regionserver.hlog.writer.impl",
102 InstrumentedSequenceFileLogWriter.class, HLog.Writer.class);
103
104 TEST_UTIL.startMiniDFSCluster(2);
105 }
106
107 @AfterClass
108 public static void tearDownAfterClass() throws Exception {
109 TEST_UTIL.shutdownMiniDFSCluster();
110 }
111
112 @Before
113 public void setUp() throws Exception {
114 conf = TEST_UTIL.getConfiguration();
115 fs = TEST_UTIL.getDFSCluster().getFileSystem();
116 FileStatus[] entries = fs.listStatus(new Path("/"));
117 for (FileStatus dir : entries){
118 fs.delete(dir.getPath(), true);
119 }
120 seq = 0;
121 regions = new ArrayList<String>();
122 Collections.addAll(regions, "bbb", "ccc");
123 InstrumentedSequenceFileLogWriter.activateFailure = false;
124
125 TEST_UTIL.setNameNodeNameSystemLeasePeriod(100, 50000);
126 }
127
128 @After
129 public void tearDown() throws Exception {
130 }
131
132 @Test(expected = IOException.class)
133 public void testSplitFailsIfNewHLogGetsCreatedAfterSplitStarted()
134 throws IOException {
135 AtomicBoolean stop = new AtomicBoolean(false);
136 generateHLogs(-1);
137 fs.initialize(fs.getUri(), conf);
138 try {
139 (new ZombieNewLogWriterRegionServer(stop)).start();
140 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
141 } finally {
142 stop.set(true);
143 }
144 }
145
146
147 @Test
148 public void testSplitPreservesEdits() throws IOException{
149 final String REGION = "region__1";
150 regions.removeAll(regions);
151 regions.add(REGION);
152
153 generateHLogs(1, 10, -1);
154 fs.initialize(fs.getUri(), conf);
155 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
156
157 Path originalLog = (fs.listStatus(oldLogDir))[0].getPath();
158 Path splitLog = getLogForRegion(hbaseDir, TABLE_NAME, REGION);
159
160 assertEquals("edits differ after split", true, logsAreEqual(originalLog, splitLog));
161 }
162
163
164 @Test
165 public void testEmptyLogFiles() throws IOException {
166
167 injectEmptyFile(".empty", true);
168 generateHLogs(Integer.MAX_VALUE);
169 injectEmptyFile("empty", true);
170
171
172
173 fs.initialize(fs.getUri(), conf);
174
175 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
176
177
178 for (String region : regions) {
179 Path logfile = getLogForRegion(hbaseDir, TABLE_NAME, region);
180 assertEquals(NUM_WRITERS * ENTRIES, countHLog(logfile, fs, conf));
181 }
182
183 }
184
185
186 @Test
187 public void testEmptyOpenLogFiles() throws IOException {
188 injectEmptyFile(".empty", false);
189 generateHLogs(Integer.MAX_VALUE);
190 injectEmptyFile("empty", false);
191
192
193
194 fs.initialize(fs.getUri(), conf);
195
196 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
197
198 for (String region : regions) {
199 Path logfile = getLogForRegion(hbaseDir, TABLE_NAME, region);
200 assertEquals(NUM_WRITERS * ENTRIES, countHLog(logfile, fs, conf));
201 }
202 }
203
204 @Test
205 public void testOpenZeroLengthReportedFileButWithDataGetsSplit() throws IOException {
206
207 generateHLogs(5);
208
209 fs.initialize(fs.getUri(), conf);
210
211 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
212
213 for (String region : regions) {
214 Path logfile = getLogForRegion(hbaseDir, TABLE_NAME, region);
215 assertEquals(NUM_WRITERS * ENTRIES, countHLog(logfile, fs, conf));
216 }
217
218
219 }
220
221
222 @Test
223 public void testTralingGarbageCorruptionFileSkipErrorsPasses() throws IOException {
224 conf.setBoolean(HBASE_SKIP_ERRORS, true);
225 generateHLogs(Integer.MAX_VALUE);
226 corruptHLog(new Path(hlogDir, HLOG_FILE_PREFIX + "5"),
227 Corruptions.APPEND_GARBAGE, true, fs);
228 fs.initialize(fs.getUri(), conf);
229 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
230
231 for (String region : regions) {
232 Path logfile = getLogForRegion(hbaseDir, TABLE_NAME, region);
233 assertEquals(NUM_WRITERS * ENTRIES, countHLog(logfile, fs, conf));
234 }
235
236
237 }
238
239 @Test
240 public void testFirstLineCorruptionLogFileSkipErrorsPasses() throws IOException {
241 conf.setBoolean(HBASE_SKIP_ERRORS, true);
242 generateHLogs(Integer.MAX_VALUE);
243 corruptHLog(new Path(hlogDir, HLOG_FILE_PREFIX + "5"),
244 Corruptions.INSERT_GARBAGE_ON_FIRST_LINE, true, fs);
245 fs.initialize(fs.getUri(), conf);
246 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
247
248 for (String region : regions) {
249 Path logfile = getLogForRegion(hbaseDir, TABLE_NAME, region);
250 assertEquals((NUM_WRITERS - 1) * ENTRIES, countHLog(logfile, fs, conf));
251 }
252
253
254 }
255
256
257 @Test
258 public void testMiddleGarbageCorruptionSkipErrorsReadsHalfOfFile() throws IOException {
259 conf.setBoolean(HBASE_SKIP_ERRORS, true);
260 generateHLogs(Integer.MAX_VALUE);
261 corruptHLog(new Path(hlogDir, HLOG_FILE_PREFIX + "5"),
262 Corruptions.INSERT_GARBAGE_IN_THE_MIDDLE, false, fs);
263 fs.initialize(fs.getUri(), conf);
264 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
265
266 for (String region : regions) {
267 Path logfile = getLogForRegion(hbaseDir, TABLE_NAME, region);
268
269
270
271 int goodEntries = (NUM_WRITERS - 1) * ENTRIES;
272 int firstHalfEntries = (int) Math.ceil(ENTRIES / 2) - 1;
273 assertTrue("The file up to the corrupted area hasn't been parsed",
274 goodEntries + firstHalfEntries <= countHLog(logfile, fs, conf));
275 }
276 }
277
278
279
280 public void testCorruptedFileGetsArchivedIfSkipErrors() throws IOException {
281 conf.setBoolean(HBASE_SKIP_ERRORS, true);
282
283 Path c1 = new Path(hlogDir, HLOG_FILE_PREFIX + "0");
284 Path c2 = new Path(hlogDir, HLOG_FILE_PREFIX + "5");
285 Path c3 = new Path(hlogDir, HLOG_FILE_PREFIX + (NUM_WRITERS - 1));
286 generateHLogs(-1);
287 corruptHLog(c1, Corruptions.INSERT_GARBAGE_IN_THE_MIDDLE, false, fs);
288 corruptHLog(c2, Corruptions.APPEND_GARBAGE, true, fs);
289 corruptHLog(c3, Corruptions.INSERT_GARBAGE_ON_FIRST_LINE, true, fs);
290
291 fs.initialize(fs.getUri(), conf);
292 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
293
294 FileStatus[] archivedLogs = fs.listStatus(corruptDir);
295
296 assertEquals("expected a different file", c1.getName(), archivedLogs[0].getPath().getName());
297 assertEquals("expected a different file", c2.getName(), archivedLogs[1].getPath().getName());
298 assertEquals("expected a different file", c3.getName(), archivedLogs[2].getPath().getName());
299 assertEquals(archivedLogs.length, 3);
300
301 }
302
303 @Test
304 public void testEOFisIgnored() throws IOException {
305 conf.setBoolean(HBASE_SKIP_ERRORS, false);
306
307 final String REGION = "region__1";
308 regions.removeAll(regions);
309 regions.add(REGION);
310
311 int entryCount = 10;
312 Path c1 = new Path(hlogDir, HLOG_FILE_PREFIX + "0");
313 generateHLogs(1, entryCount, -1);
314 corruptHLog(c1, Corruptions.TRUNCATE, true, fs);
315
316 fs.initialize(fs.getUri(), conf);
317 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
318
319 Path originalLog = (fs.listStatus(oldLogDir))[0].getPath();
320 Path splitLog = getLogForRegion(hbaseDir, TABLE_NAME, REGION);
321
322 int actualCount = 0;
323 HLog.Reader in = HLog.getReader(fs, splitLog, conf);
324 HLog.Entry entry;
325 while ((entry = in.next()) != null) ++actualCount;
326 assertEquals(entryCount-1, actualCount);
327
328
329 FileStatus[] archivedLogs = fs.listStatus(corruptDir);
330 assertEquals(archivedLogs.length, 0);
331 }
332
333 @Test
334 public void testLogsGetArchivedAfterSplit() throws IOException {
335 conf.setBoolean(HBASE_SKIP_ERRORS, false);
336
337 generateHLogs(-1);
338
339 fs.initialize(fs.getUri(), conf);
340 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
341
342 FileStatus[] archivedLogs = fs.listStatus(oldLogDir);
343
344 assertEquals("wrong number of files in the archive log", NUM_WRITERS, archivedLogs.length);
345 }
346
347
348
349
350
351 public void testTrailingGarbageCorruptionLogFileSkipErrorsFalseThrows() throws IOException {
352 conf.setBoolean(HBASE_SKIP_ERRORS, false);
353 generateHLogs(Integer.MAX_VALUE);
354 corruptHLog(new Path(hlogDir, HLOG_FILE_PREFIX + "5"),
355 Corruptions.APPEND_GARBAGE, true, fs);
356
357 fs.initialize(fs.getUri(), conf);
358 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
359 }
360
361
362
363 public void testCorruptedLogFilesSkipErrorsFalseDoesNotTouchLogs() throws IOException {
364 conf.setBoolean(HBASE_SKIP_ERRORS, false);
365 generateHLogs(-1);
366 corruptHLog(new Path(hlogDir, HLOG_FILE_PREFIX + "5"),
367 Corruptions.APPEND_GARBAGE, true, fs);
368 fs.initialize(fs.getUri(), conf);
369 try {
370 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
371 } catch (IOException e) {
372
373 assertEquals("if skip.errors is false all files should remain in place",
374 NUM_WRITERS, fs.listStatus(hlogDir).length);
375 }
376
377
378 @Test
379 public void testSplit() throws IOException {
380 generateHLogs(-1);
381 fs.initialize(fs.getUri(), conf);
382 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
383
384
385
386 for (String region : regions) {
387 Path logfile = getLogForRegion(hbaseDir, TABLE_NAME, region);
388 assertEquals(NUM_WRITERS * ENTRIES, countHLog(logfile, fs, conf));
389
390 }
391 }
392
393 @Test
394 public void testLogDirectoryShouldBeDeletedAfterSuccessfulSplit()
395 throws IOException {
396 generateHLogs(-1);
397 fs.initialize(fs.getUri(), conf);
398 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
399 FileStatus [] statuses = null;
400 try {
401 statuses = fs.listStatus(hlogDir);
402 assertNull(statuses);
403 } catch (FileNotFoundException e) {
404
405 }
406 }
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438 @Test
439 public void testSplitWillNotTouchLogsIfNewHLogGetsCreatedAfterSplitStarted()
440 throws IOException {
441 AtomicBoolean stop = new AtomicBoolean(false);
442 generateHLogs(-1);
443 fs.initialize(fs.getUri(), conf);
444 Thread zombie = new ZombieNewLogWriterRegionServer(stop);
445
446 try {
447 zombie.start();
448 try {
449 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
450 } catch (IOException ex) {
451 int logFilesNumber = fs.listStatus(hlogDir).length;
452
453 assertEquals("Log files should not be archived if there's an extra file after split",
454 NUM_WRITERS + 1, logFilesNumber);
455 } finally {
456 stop.set(true);
457 }
458
459 }
460
461
462
463 @Test(expected = IOException.class)
464 public void testSplitWillFailIfWritingToRegionFails() throws Exception {
465
466 generateHLogs(4);
467
468 fs.initialize(fs.getUri(), conf);
469
470 InstrumentedSequenceFileLogWriter.activateFailure = false;
471 appendEntry(writer[4], TABLE_NAME, Bytes.toBytes("break"), ("r" + 999).getBytes(), FAMILY, QUALIFIER, VALUE, 0);
472 writer[4].close();
473
474
475 try {
476 InstrumentedSequenceFileLogWriter.activateFailure = true;
477 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
478
479 } catch (IOException e) {
480 assertEquals("java.io.IOException: This exception is instrumented and should only be thrown for testing", e.getMessage());
481 throw e;
482 } finally {
483 InstrumentedSequenceFileLogWriter.activateFailure = false;
484 }
485 }
486
487
488
489 public void testSplittingLargeNumberOfRegionsConsistency() throws IOException {
490
491 regions.removeAll(regions);
492 for (int i=0; i<100; i++) {
493 regions.add("region__"+i);
494 }
495
496 generateHLogs(1, 100, -1);
497 fs.initialize(fs.getUri(), conf);
498
499 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
500 fs.rename(oldLogDir, hlogDir);
501 Path firstSplitPath = new Path(hbaseDir, Bytes.toString(TABLE_NAME) + ".first");
502 Path splitPath = new Path(hbaseDir, Bytes.toString(TABLE_NAME));
503 fs.rename(splitPath,
504 firstSplitPath);
505
506
507 fs.initialize(fs.getUri(), conf);
508 HLog.splitLog(hbaseDir, hlogDir, oldLogDir, fs, conf);
509
510 assertEquals(0, compareHLogSplitDirs(firstSplitPath, splitPath));
511 }
512
513
514
515
516
517
518 class ZombieLastLogWriterRegionServer extends Thread {
519 AtomicLong editsCount;
520 AtomicBoolean stop;
521 Path log;
522 HLog.Writer lastLogWriter;
523 public ZombieLastLogWriterRegionServer(HLog.Writer writer, AtomicLong counter, AtomicBoolean stop) {
524 this.stop = stop;
525 this.editsCount = counter;
526 this.lastLogWriter = writer;
527 }
528
529 @Override
530 public void run() {
531 if (stop.get()){
532 return;
533 }
534 flushToConsole("starting");
535 while (true) {
536 try {
537
538 appendEntry(lastLogWriter, TABLE_NAME, "juliet".getBytes(),
539 ("r" + editsCount).getBytes(), FAMILY, QUALIFIER, VALUE, 0);
540 lastLogWriter.sync();
541 editsCount.incrementAndGet();
542 try {
543 Thread.sleep(1);
544 } catch (InterruptedException e) {
545
546 }
547
548
549 } catch (IOException ex) {
550 if (ex instanceof RemoteException) {
551 flushToConsole("Juliet: got RemoteException " +
552 ex.getMessage() + " while writing " + (editsCount.get() + 1));
553 break;
554 } else {
555 assertTrue("Failed to write " + editsCount.get(), false);
556 }
557
558 }
559 }
560
561
562 }
563 }
564
565
566
567
568
569
570 class ZombieNewLogWriterRegionServer extends Thread {
571 AtomicBoolean stop;
572 public ZombieNewLogWriterRegionServer(AtomicBoolean stop) {
573 super("ZombieNewLogWriterRegionServer");
574 this.stop = stop;
575 }
576
577 @Override
578 public void run() {
579 if (stop.get()) {
580 return;
581 }
582 boolean splitStarted = false;
583 Path p = new Path(hbaseDir, new String(TABLE_NAME));
584 while (!splitStarted) {
585 try {
586 FileStatus [] statuses = fs.listStatus(p);
587
588
589 if (statuses != null && statuses.length > 0) {
590
591 break;
592 }
593 } catch (FileNotFoundException e) {
594
595 } catch (IOException e1) {
596 assertTrue("Failed to list status ", false);
597 }
598 flushToConsole("Juliet: split not started, sleeping a bit...");
599 Threads.sleep(100);
600 }
601
602 Path julietLog = new Path(hlogDir, HLOG_FILE_PREFIX + ".juliet");
603 try {
604 HLog.Writer writer = HLog.createWriter(fs,
605 julietLog, conf);
606 appendEntry(writer, "juliet".getBytes(), ("juliet").getBytes(),
607 ("r").getBytes(), FAMILY, QUALIFIER, VALUE, 0);
608 writer.close();
609 flushToConsole("Juliet file creator: created file " + julietLog);
610 } catch (IOException e1) {
611 assertTrue("Failed to create file " + julietLog, false);
612 }
613 }
614 }
615
616 private void flushToConsole(String s) {
617 System.out.println(s);
618 System.out.flush();
619 }
620
621
622 private void generateHLogs(int leaveOpen) throws IOException {
623 generateHLogs(NUM_WRITERS, ENTRIES, leaveOpen);
624 }
625
626 private void generateHLogs(int writers, int entries, int leaveOpen) throws IOException {
627 for (int i = 0; i < writers; i++) {
628 writer[i] = HLog.createWriter(fs, new Path(hlogDir, HLOG_FILE_PREFIX + i), conf);
629 for (int j = 0; j < entries; j++) {
630 int prefix = 0;
631 for (String region : regions) {
632 String row_key = region + prefix++ + i + j;
633 appendEntry(writer[i], TABLE_NAME, region.getBytes(),
634 row_key.getBytes(), FAMILY, QUALIFIER, VALUE, seq);
635 }
636 }
637 if (i != leaveOpen) {
638 writer[i].close();
639 flushToConsole("Closing writer " + i);
640 }
641 }
642 }
643
644 private Path getLogForRegion(Path rootdir, byte[] table, String region)
645 throws IOException {
646 Path tdir = HTableDescriptor.getTableDir(rootdir, table);
647 Path editsdir = HLog.getRegionDirRecoveredEditsDir(HRegion.getRegionDir(tdir,
648 HRegionInfo.encodeRegionName(region.getBytes())));
649 FileStatus [] files = this.fs.listStatus(editsdir);
650 assertEquals(1, files.length);
651 return files[0].getPath();
652 }
653
654 private void corruptHLog(Path path, Corruptions corruption, boolean close,
655 FileSystem fs) throws IOException {
656
657 FSDataOutputStream out;
658 int fileSize = (int) fs.listStatus(path)[0].getLen();
659
660 FSDataInputStream in = fs.open(path);
661 byte[] corrupted_bytes = new byte[fileSize];
662 in.readFully(0, corrupted_bytes, 0, fileSize);
663 in.close();
664
665 switch (corruption) {
666 case APPEND_GARBAGE:
667 out = fs.append(path);
668 out.write("-----".getBytes());
669 closeOrFlush(close, out);
670 break;
671
672 case INSERT_GARBAGE_ON_FIRST_LINE:
673 fs.delete(path, false);
674 out = fs.create(path);
675 out.write(0);
676 out.write(corrupted_bytes);
677 closeOrFlush(close, out);
678 break;
679
680 case INSERT_GARBAGE_IN_THE_MIDDLE:
681 fs.delete(path, false);
682 out = fs.create(path);
683 int middle = (int) Math.floor(corrupted_bytes.length / 2);
684 out.write(corrupted_bytes, 0, middle);
685 out.write(0);
686 out.write(corrupted_bytes, middle, corrupted_bytes.length - middle);
687 closeOrFlush(close, out);
688 break;
689
690 case TRUNCATE:
691 fs.delete(path, false);
692 out = fs.create(path);
693 out.write(corrupted_bytes, 0, fileSize-32);
694 closeOrFlush(close, out);
695
696 break;
697 }
698
699
700 }
701
702 private void closeOrFlush(boolean close, FSDataOutputStream out)
703 throws IOException {
704 if (close) {
705 out.close();
706 } else {
707 out.sync();
708
709 }
710 }
711
712 @SuppressWarnings("unused")
713 private void dumpHLog(Path log, FileSystem fs, Configuration conf) throws IOException {
714 HLog.Entry entry;
715 HLog.Reader in = HLog.getReader(fs, log, conf);
716 while ((entry = in.next()) != null) {
717 System.out.println(entry);
718 }
719 }
720
721 private int countHLog(Path log, FileSystem fs, Configuration conf) throws IOException {
722 int count = 0;
723 HLog.Reader in = HLog.getReader(fs, log, conf);
724 while (in.next() != null) {
725 count++;
726 }
727 return count;
728 }
729
730
731 public long appendEntry(HLog.Writer writer, byte[] table, byte[] region,
732 byte[] row, byte[] family, byte[] qualifier,
733 byte[] value, long seq)
734 throws IOException {
735
736 long time = System.nanoTime();
737 WALEdit edit = new WALEdit();
738 seq++;
739 edit.add(new KeyValue(row, family, qualifier, time, KeyValue.Type.Put, value));
740 writer.append(new HLog.Entry(new HLogKey(region, table, seq, time), edit));
741 writer.sync();
742 return seq;
743
744 }
745
746
747 private void injectEmptyFile(String suffix, boolean closeFile)
748 throws IOException {
749 HLog.Writer writer = HLog.createWriter(
750 fs, new Path(hlogDir, HLOG_FILE_PREFIX + suffix), conf);
751 if (closeFile) writer.close();
752 }
753
754 @SuppressWarnings("unused")
755 private void listLogs(FileSystem fs, Path dir) throws IOException {
756 for (FileStatus file : fs.listStatus(dir)) {
757 System.out.println(file.getPath());
758 }
759
760 }
761
762 private int compareHLogSplitDirs(Path p1, Path p2) throws IOException {
763 FileStatus[] f1 = fs.listStatus(p1);
764 FileStatus[] f2 = fs.listStatus(p2);
765
766 for (int i=0; i<f1.length; i++) {
767
768
769 Path rd1 = HLog.getRegionDirRecoveredEditsDir(f1[i].getPath());
770 FileStatus [] rd1fs = fs.listStatus(rd1);
771 assertEquals(1, rd1fs.length);
772 Path rd2 = HLog.getRegionDirRecoveredEditsDir(f2[i].getPath());
773 FileStatus [] rd2fs = fs.listStatus(rd2);
774 assertEquals(1, rd2fs.length);
775 if (!logsAreEqual(rd1fs[0].getPath(), rd2fs[0].getPath())) {
776 return -1;
777 }
778 }
779 return 0;
780 }
781
782 private boolean logsAreEqual(Path p1, Path p2) throws IOException {
783 HLog.Reader in1, in2;
784 in1 = HLog.getReader(fs, p1, conf);
785 in2 = HLog.getReader(fs, p2, conf);
786 HLog.Entry entry1;
787 HLog.Entry entry2;
788 while ((entry1 = in1.next()) != null) {
789 entry2 = in2.next();
790 if ((entry1.getKey().compareTo(entry2.getKey()) != 0) ||
791 (!entry1.getEdit().toString().equals(entry2.getEdit().toString()))) {
792 return false;
793 }
794 }
795 return true;
796 }
797 }