@Test public void testGetRemoteEditLog() throws IOException { StorageDirectory sd = FSImageTestUtil.mockStorageDirectory( NameNodeDirType.EDITS, false, NNStorage.getFinalizedEditsFileName(1, 100), NNStorage.getFinalizedEditsFileName(101, 200), NNStorage.getInProgressEditsFileName(201), NNStorage.getFinalizedEditsFileName(1001, 1100)); FileJournalManager fjm = new FileJournalManager(sd); assertEquals("[1,100],[101,200],[1001,1100]", getLogsAsString(fjm, 1)); assertEquals("[101,200],[1001,1100]", getLogsAsString(fjm, 101)); assertEquals("[1001,1100]", getLogsAsString(fjm, 201)); try { assertEquals("[]", getLogsAsString(fjm, 150)); fail("Did not throw when asking for a txn in the middle of a log"); } catch (IOException ioe) { GenericTestUtils.assertExceptionContains("150 which is in the middle", ioe); } assertEquals( "Asking for a newer log than exists should return empty list", "", getLogsAsString(fjm, 9999)); }
/** * Test that we can load an edits directory with a corrupt inprogress file. The corrupt inprogress * file should be moved to the side. */ @Test public void testManyLogsWithCorruptInprogress() throws IOException { File f = new File(TestEditLog.TEST_DIR + "/filejournaltest5"); NNStorage storage = setupEdits(Collections.<URI>singletonList(f.toURI()), 10, new AbortSpec(10, 0)); StorageDirectory sd = storage.dirIterator(NameNodeDirType.EDITS).next(); File[] files = new File(f, "current") .listFiles( new FilenameFilter() { public boolean accept(File dir, String name) { if (name.startsWith("edits_inprogress")) { return true; } return false; } }); assertEquals(files.length, 1); corruptAfterStartSegment(files[0]); FileJournalManager jm = new FileJournalManager(sd); assertEquals(10 * TXNS_PER_ROLL + 1, jm.getNumberOfTransactions(1)); }
/** * Test that we can read from a stream created by FileJournalManager. Create a single edits * directory, failing it on the final roll. Then try loading from the point of the 3rd roll. * Verify that we read the correct number of transactions from this point. */ @Test public void testReadFromStream() throws IOException { File f = new File(TestEditLog.TEST_DIR + "/filejournaltest1"); // abort after 10th roll NNStorage storage = setupEdits(Collections.<URI>singletonList(f.toURI()), 10, new AbortSpec(10, 0)); StorageDirectory sd = storage.dirIterator(NameNodeDirType.EDITS).next(); FileJournalManager jm = new FileJournalManager(sd); long expectedTotalTxnCount = TXNS_PER_ROLL * 10 + TXNS_PER_FAIL; assertEquals(expectedTotalTxnCount, jm.getNumberOfTransactions(1)); long skippedTxns = (3 * TXNS_PER_ROLL); // skip first 3 files long startingTxId = skippedTxns + 1; long numTransactionsToLoad = jm.getNumberOfTransactions(startingTxId); long numLoaded = 0; while (numLoaded < numTransactionsToLoad) { EditLogInputStream editIn = jm.getInputStream(startingTxId); FSEditLogLoader.EditLogValidation val = FSEditLogLoader.validateEditLog(editIn); long count = val.getNumTransactions(); editIn.close(); startingTxId += count; numLoaded += count; } assertEquals(expectedTotalTxnCount - skippedTxns, numLoaded); }
/** Checks the JournalManager.isSegmentInProgress() */ @Test public void testInprogressSegment() throws IOException { File f = new File(TestEditLog.TEST_DIR + "/testInprogressSegment"); // abort after the 5th roll NNStorage storage = setupEdits(Collections.<URI>singletonList(f.toURI()), 5, new AbortSpec(5, 0)); StorageDirectory sd = storage.dirIterator(NameNodeDirType.EDITS).next(); FileJournalManager jm = new FileJournalManager(sd); assertEquals(5 * TXNS_PER_ROLL + TXNS_PER_FAIL, jm.getNumberOfTransactions(0)); boolean isOneInProgress = false; boolean isOneNotInProgress = false; for (RemoteEditLog rel : jm.getRemoteEditLogs(0)) { if (rel.inProgress()) { isOneInProgress = true; assertTrue(jm.isSegmentInProgress(rel.getStartTxId())); } else { isOneNotInProgress = true; assertFalse(jm.isSegmentInProgress(rel.getStartTxId())); } } assertTrue(isOneInProgress); assertTrue(isOneNotInProgress); }
/** * Try to make a request with a start transaction id which doesn't match the start ID of some log * segment. This should fail as edit logs must currently be treated as indevisable units. */ @Test(expected = IOException.class) public void testAskForTransactionsMidfile() throws IOException { File f = new File(TestEditLog.TEST_DIR + "/filejournaltest2"); NNStorage storage = setupEdits(Collections.<URI>singletonList(f.toURI()), 10); StorageDirectory sd = storage.dirIterator(NameNodeDirType.EDITS).next(); FileJournalManager jm = new FileJournalManager(sd); jm.getNumberOfTransactions(2); }
/** * Test that inprogress files are handled correct. Set up a single edits directory. Fail on after * the last roll. Then verify that the logs have the expected number of transactions. */ @Test public void testInprogressRecovery() throws IOException { File f = new File(TestEditLog.TEST_DIR + "/filejournaltest0"); // abort after the 5th roll NNStorage storage = setupEdits(Collections.<URI>singletonList(f.toURI()), 5, new AbortSpec(5, 0)); StorageDirectory sd = storage.dirIterator(NameNodeDirType.EDITS).next(); FileJournalManager jm = new FileJournalManager(sd); assertEquals(5 * TXNS_PER_ROLL + TXNS_PER_FAIL, jm.getNumberOfTransactions(1)); }
/** * Test the normal operation of loading transactions from file journal manager. 3 edits * directories are setup without any failures. Test that we read in the expected number of * transactions. */ @Test public void testNormalOperation() throws IOException { File f1 = new File(TestEditLog.TEST_DIR + "/normtest0"); File f2 = new File(TestEditLog.TEST_DIR + "/normtest1"); File f3 = new File(TestEditLog.TEST_DIR + "/normtest2"); List<URI> editUris = ImmutableList.of(f1.toURI(), f2.toURI(), f3.toURI()); NNStorage storage = setupEdits(editUris, 5); long numJournals = 0; for (StorageDirectory sd : storage.dirIterable(NameNodeDirType.EDITS)) { FileJournalManager jm = new FileJournalManager(sd); assertEquals(6 * TXNS_PER_ROLL, jm.getNumberOfTransactions(1)); numJournals++; } assertEquals(3, numJournals); }
@Override public void inspectDirectory(StorageDirectory sd) throws IOException { // Was the directory just formatted? if (!sd.getVersionFile().exists()) { LOG.info("No version file in " + sd.getRoot()); needToSave |= true; return; } maxSeenTxId = Math.max(maxSeenTxId, NNStorage.readTransactionIdFile(sd)); File currentDir = sd.getCurrentDir(); File filesInStorage[]; try { filesInStorage = FileUtil.listFiles(currentDir); } catch (IOException ioe) { LOG.warn("Unable to inspect storage directory " + currentDir, ioe); return; } for (File f : filesInStorage) { LOG.info("Inspecting images: Checking file " + f); String name = f.getName(); // Check for fsimage_* Matcher imageMatch = IMAGE_REGEX.matcher(name); addImageIfMatching(imageMatch, foundImages, sd, f); // Check for fsimage_* Matcher imageCkptMatch = IMAGE_CKPT_REGEX.matcher(name); addImageIfMatching(imageCkptMatch, foundCkptImages, sd, f); } // Check for a seen_txid file, which marks a minimum transaction ID that // must be included in our load plan. try { maxSeenTxId = Math.max(maxSeenTxId, NNStorage.readTransactionIdFile(sd)); } catch (IOException ioe) { LOG.warn("Unable to determine the max transaction ID seen by " + sd, ioe); } // set finalized flag isUpgradeFinalized = isUpgradeFinalized && !sd.getPreviousDir().exists(); }
/** * Test that we receive the correct number of transactions when we count the number of * transactions around gaps. Set up a single edits directory, with no failures. Delete the 4th * logfile. Test that getNumberOfTransactions returns the correct number of transactions before * this gap and after this gap. Also verify that if you try to count on the gap that an exception * is thrown. */ @Test public void testManyLogsWithGaps() throws IOException { File f = new File(TestEditLog.TEST_DIR + "/filejournaltest3"); NNStorage storage = setupEdits(Collections.<URI>singletonList(f.toURI()), 10); StorageDirectory sd = storage.dirIterator(NameNodeDirType.EDITS).next(); final long startGapTxId = 3 * TXNS_PER_ROLL; // 30 final long endGapTxId = 4 * TXNS_PER_ROLL - 1; // 39 File[] files = new File(f, "current") .listFiles( new FilenameFilter() { public boolean accept(File dir, String name) { if (name.startsWith( NNStorage.getFinalizedEditsFileName(startGapTxId, endGapTxId))) { return true; } return false; } }); assertEquals(1, files.length); assertTrue(files[0].delete()); FileJournalManager jm = new FileJournalManager(sd); assertEquals(startGapTxId, jm.getNumberOfTransactions(0)); try { jm.getNumberOfTransactions(startGapTxId); fail("Should have thrown an exception by now"); } catch (IOException ioe) { assertTrue(true); } // rolled 10 times so there should be 11 files. assertEquals( 11 * TXNS_PER_ROLL - endGapTxId - 1, // 110 - 39 - 1 jm.getNumberOfTransactions(endGapTxId + 1)); }
/** * Test a mixture of inprogress files and finalised. Set up 3 edits directories and fail the * second on the last roll. Verify that reading the transactions, reads from the finalised * directories. */ @Test public void testInprogressRecoveryMixed() throws IOException { File f1 = new File(TestEditLog.TEST_DIR + "/mixtest0"); File f2 = new File(TestEditLog.TEST_DIR + "/mixtest1"); File f3 = new File(TestEditLog.TEST_DIR + "/mixtest2"); List<URI> editUris = ImmutableList.of(f1.toURI(), f2.toURI(), f3.toURI()); // abort after the 5th roll NNStorage storage = setupEdits(editUris, 5, new AbortSpec(5, 1)); Iterator<StorageDirectory> dirs = storage.dirIterator(NameNodeDirType.EDITS); StorageDirectory sd = dirs.next(); FileJournalManager jm = new FileJournalManager(sd); assertEquals(6 * TXNS_PER_ROLL, jm.getNumberOfTransactions(1)); sd = dirs.next(); jm = new FileJournalManager(sd); assertEquals(5 * TXNS_PER_ROLL + TXNS_PER_FAIL, jm.getNumberOfTransactions(1)); sd = dirs.next(); jm = new FileJournalManager(sd); assertEquals(6 * TXNS_PER_ROLL, jm.getNumberOfTransactions(1)); }