public void validateStorage(NNStorage storage) throws IOException { if (layoutVersion != storage.getLayoutVersion() || namespaceID != storage.getNamespaceID() || cTime != storage.cTime || !clusterID.equals(storage.getClusterID()) || !blockPoolID.equals(storage.getBlockPoolID())) { throw new IOException("Inconsistent namespace information:\n" + "NamespaceInfo has:\n" + "LV=" + layoutVersion + ";" + "NS=" + namespaceID + ";" + "cTime=" + cTime + ";" + "CID=" + clusterID + ";" + "BPID=" + blockPoolID + ".\nStorage has:\n" + "LV=" + storage.getLayoutVersion() + ";" + "NS=" + storage.getNamespaceID() + ";" + "cTime=" + storage.getCTime() + ";" + "CID=" + storage.getClusterID() + ";" + "BPID=" + storage.getBlockPoolID() + "."); } }
/** * Ensure that during downgrade the NN fails to load a fsimage with newer * format. */ @Test(expected = IncorrectVersionException.class) public void testRejectNewFsImage() throws IOException { final Configuration conf = new Configuration(); MiniDFSCluster cluster = null; try { cluster = new MiniDFSCluster.Builder(conf).numDataNodes(0).build(); cluster.waitActive(); DistributedFileSystem fs = cluster.getFileSystem(); fs.setSafeMode(SafeModeAction.SAFEMODE_ENTER); fs.saveNamespace(); fs.setSafeMode(SafeModeAction.SAFEMODE_LEAVE); NNStorage storage = spy(cluster.getNameNode().getFSImage().getStorage()); int futureVersion = NameNodeLayoutVersion.CURRENT_LAYOUT_VERSION - 1; doReturn(futureVersion).when(storage).getServiceLayoutVersion(); storage.writeAll(); cluster.restartNameNode(0, true, "-rollingUpgrade", "downgrade"); } finally { if (cluster != null) { cluster.shutdown(); } } }
private void checkNNStorage(NNStorage storage, long imageTxId, long trashEndTxId) { List<File> finalizedEdits = storage.getFiles( NNStorage.NameNodeDirType.EDITS, NNStorage.getFinalizedEditsFileName(1, imageTxId)); Assert.assertTrue(fileExists(finalizedEdits)); List<File> inprogressEdits = storage.getFiles( NNStorage.NameNodeDirType.EDITS, NNStorage.getInProgressEditsFileName(imageTxId + 1)); // For rollback case we will have an inprogress file for future transactions Assert.assertTrue(fileExists(inprogressEdits)); if (trashEndTxId > 0) { List<File> trashedEdits = storage.getFiles( NNStorage.NameNodeDirType.EDITS, NNStorage.getFinalizedEditsFileName(imageTxId + 1, trashEndTxId) + ".trash"); Assert.assertTrue(fileExists(trashedEdits)); } String imageFileName = trashEndTxId > 0 ? NNStorage .getImageFileName(imageTxId) : NNStorage .getRollbackImageFileName(imageTxId); List<File> imageFiles = storage.getFiles( NNStorage.NameNodeDirType.IMAGE, imageFileName); Assert.assertTrue(fileExists(imageFiles)); }
private void doOutOfSyncTest(int missingOnRecoveryIdx, long expectedRecoveryTxnId) throws Exception { setupLoggers345(); QJMTestUtil.assertExistsInQuorum(cluster, NNStorage.getInProgressEditsFileName(1)); // Shut down the specified JN, so it's not present during recovery. cluster.getJournalNode(missingOnRecoveryIdx).stopAndJoin(0); // Make a new QJM qjm = createSpyingQJM(); qjm.recoverUnfinalizedSegments(); checkRecovery(cluster, 1, expectedRecoveryTxnId); }
@Test public void testSelectInputStreamsNotOnBoundary() throws Exception { final int txIdsPerSegment = 10; for (int txid = 1; txid <= 5 * txIdsPerSegment; txid += txIdsPerSegment) { writeSegment(cluster, qjm, txid, txIdsPerSegment, true); } File curDir = cluster.getCurrentDir(0, JID); GenericTestUtils.assertGlobEquals(curDir, "edits_.*", NNStorage.getFinalizedEditsFileName(1, 10), NNStorage.getFinalizedEditsFileName(11, 20), NNStorage.getFinalizedEditsFileName(21, 30), NNStorage.getFinalizedEditsFileName(31, 40), NNStorage.getFinalizedEditsFileName(41, 50)); ArrayList<EditLogInputStream> streams = new ArrayList<EditLogInputStream>(); qjm.selectInputStreams(streams, 25, false); verifyEdits(streams, 25, 50); }
public static EditLogOutputStream writeSegment(MiniJournalCluster cluster, QuorumJournalManager qjm, long startTxId, int numTxns, boolean finalize) throws IOException { EditLogOutputStream stm = qjm.startLogSegment(startTxId, NameNodeLayoutVersion.CURRENT_LAYOUT_VERSION); // Should create in-progress assertExistsInQuorum(cluster, NNStorage.getInProgressEditsFileName(startTxId)); writeTxns(stm, startTxId, numTxns); if (finalize) { stm.close(); qjm.finalizeLogSegment(startTxId, startTxId + numTxns - 1); return null; } else { return stm; } }
/** * Ensure that restart namenode with downgrade option should throw exception * because it has been obsolete. */ @Test(expected = IllegalArgumentException.class) public void testRejectNewFsImage() throws IOException { final Configuration conf = new Configuration(); MiniDFSCluster cluster = null; try { cluster = new MiniDFSCluster.Builder(conf).numDataNodes(0).build(); cluster.waitActive(); DistributedFileSystem fs = cluster.getFileSystem(); fs.setSafeMode(SafeModeAction.SAFEMODE_ENTER); fs.saveNamespace(); fs.setSafeMode(SafeModeAction.SAFEMODE_LEAVE); NNStorage storage = spy(cluster.getNameNode().getFSImage().getStorage()); int futureVersion = NameNodeLayoutVersion.CURRENT_LAYOUT_VERSION - 1; doReturn(futureVersion).when(storage).getServiceLayoutVersion(); storage.writeAll(); cluster.restartNameNode(0, true, "-rollingUpgrade", "downgrade"); } finally { if (cluster != null) { cluster.shutdown(); } } }
private static void waitForLogRollInSharedDir(MiniDFSCluster cluster, long startTxId) throws Exception { URI sharedUri = cluster.getSharedEditsDir(0, 2); File sharedDir = new File(sharedUri.getPath(), "current"); final File expectedInProgressLog = new File(sharedDir, NNStorage.getInProgressEditsFileName(startTxId)); final File expectedFinalizedLog = new File(sharedDir, NNStorage.getFinalizedEditsFileName(startTxId, startTxId + 1)); // There is a chance that multiple rolling happens by multiple NameNodes // And expected inprogress file would have also finalized. So look for the // finalized edits file as well GenericTestUtils.waitFor(new Supplier<Boolean>() { @Override public Boolean get() { return expectedInProgressLog.exists() || expectedFinalizedLog.exists(); } }, 100, 10000); }
public static EditLogOutputStream writeSegment(MiniJournalCluster cluster, QuorumJournalManager qjm, long startTxId, int numTxns, boolean finalize) throws IOException { EditLogOutputStream stm = qjm.startLogSegment(startTxId); // Should create in-progress assertExistsInQuorum(cluster, NNStorage.getInProgressEditsFileName(startTxId)); writeTxns(stm, startTxId, numTxns); if (finalize) { stm.close(); qjm.finalizeLogSegment(startTxId, startTxId + numTxns - 1); return null; } else { return stm; } }
/** * Read version file from the given directory and return * the layout stored therein. */ public static int getVersion(URI editsURI) throws IOException { if (editsURI.getScheme().equals(NNStorage.LOCAL_URI_SCHEME)) { StorageDirectory sd = new NNStorage(new StorageInfo()).new StorageDirectory( new File(editsURI.getPath())); File versionFile = sd.getVersionFile(); if (!versionFile.exists()) { throw new IOException("No VERSION file in: " + editsURI + "version file: " + versionFile ); } Properties props = Storage.getProps(versionFile); String layout = props.getProperty(Storage.LAYOUT_VERSION); if (layout == null) { throw new IOException("No layout version in: " + editsURI); } return Integer.valueOf(layout); } else { throw new IOException("Non file journals not supported yet."); } }
@Test public void testMissingVersion() throws IOException { // -37 is pre-transactional layout int lv = 12345; StorageInfo si = new StorageInfo(lv, 10, 0); StorageDirectory sd = new NNStorage(si).new StorageDirectory(editsDir); format(sd); URI editsURI = Util.stringAsURI(sd.getRoot().getAbsolutePath()); // remove verision file sd.getVersionFile().delete(); try { NotifierUtils.getVersion(editsURI); fail("Should fail"); } catch (Exception e) { LOG.info("expected exception: " + e.getMessage()); } }
void recover(StartupOption startOpt) throws IOException { LOG.info("Recovering journal " + sd + " with nsid: " + getNamespaceID()); // Unlock the directory before formatting, because we will // re-analyze it after format(). The analyzeStorage() call // below is reponsible for re-locking it. This is a no-op // if the storage is not currently locked. unlockAll(); try { StorageState curState = sd.analyzeStorage(startOpt); NNStorage.recoverDirectory(sd, startOpt, curState, false); } catch (IOException ioe) { sd.unlock(); throw ioe; } }
@Test public void testSelectInputStreamsNotOnBoundary() throws Exception { final int txIdsPerSegment = 10; for (int txid = 1; txid <= 5 * txIdsPerSegment; txid += txIdsPerSegment) { writeSegment(cluster, qjm, txid, txIdsPerSegment, true); } File curDir = cluster.getCurrentDir(0, JID); GenericTestUtils.assertGlobEquals(curDir, "edits_.*", NNStorage.getFinalizedEditsFileName(1, 10), NNStorage.getFinalizedEditsFileName(11, 20), NNStorage.getFinalizedEditsFileName(21, 30), NNStorage.getFinalizedEditsFileName(31, 40), NNStorage.getFinalizedEditsFileName(41, 50)); ArrayList<EditLogInputStream> streams = new ArrayList<EditLogInputStream>(); qjm.selectInputStreams(streams, 25, false, false); verifyEdits(streams, 25, 50); }
/** * Iterate over all the storage directories, checking if it should be * formatted. Format the storage if necessary and allowed by the user. * @return True if formatting is processed */ private boolean format(NNStorage storage, NamespaceInfo nsInfo) throws IOException { // Check with the user before blowing away data. if (!Storage.confirmFormat(storage.dirIterable(null), force, interactive)) { storage.close(); return false; } else { // Format the storage (writes VERSION file) storage.format(nsInfo); return true; } }
private void doUpgrade(NNStorage storage) throws IOException { for (Iterator<StorageDirectory> it = storage.dirIterator(false); it.hasNext();) { StorageDirectory sd = it.next(); NNUpgradeUtil.doUpgrade(sd, storage); } }