You are viewing a plain text version of this content. The canonical link for it is here.
Posted to hdfs-commits@hadoop.apache.org by to...@apache.org on 2011/07/29 18:28:51 UTC
svn commit: r1152295 [9/10] - in /hadoop/common/trunk/hdfs: ./ bin/ ivy/
src/docs/src/documentation/content/xdocs/ src/java/
src/java/org/apache/hadoop/hdfs/ src/java/org/apache/hadoop/hdfs/protocol/
src/java/org/apache/hadoop/hdfs/server/common/ src/j...
Added: hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestNNStorageRetentionManager.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestNNStorageRetentionManager.java?rev=1152295&view=auto
==============================================================================
--- hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestNNStorageRetentionManager.java (added)
+++ hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestNNStorageRetentionManager.java Fri Jul 29 16:28:45 2011
@@ -0,0 +1,307 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.hdfs.server.namenode;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory;
+import org.apache.hadoop.hdfs.server.namenode.FSImageTransactionalStorageInspector.FoundEditLog;
+import org.apache.hadoop.hdfs.server.namenode.FSImageTransactionalStorageInspector.FoundFSImage;
+import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeDirType;
+import static org.apache.hadoop.hdfs.server.namenode.NNStorage.getInProgressEditsFileName;
+import static org.apache.hadoop.hdfs.server.namenode.NNStorage.getFinalizedEditsFileName;
+import static org.apache.hadoop.hdfs.server.namenode.NNStorage.getImageFileName;
+
+import org.apache.hadoop.hdfs.server.namenode.NNStorageRetentionManager.StoragePurger;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+
+public class TestNNStorageRetentionManager {
+ /**
+ * Test the "easy case" where we have more images in the
+ * directory than we need to keep. Should purge the
+ * old ones.
+ */
+ @Test
+ public void testPurgeEasyCase() throws IOException {
+ TestCaseDescription tc = new TestCaseDescription();
+ tc.addRoot("/foo1", NameNodeDirType.IMAGE_AND_EDITS);
+ tc.addImage("/foo1/current/" + getImageFileName(100), true);
+ tc.addImage("/foo1/current/" + getImageFileName(200), true);
+ tc.addImage("/foo1/current/" + getImageFileName(300), false);
+ tc.addImage("/foo1/current/" + getImageFileName(400), false);
+ tc.addLog("/foo1/current/" + getFinalizedEditsFileName(101,200), true);
+ tc.addLog("/foo1/current/" + getFinalizedEditsFileName(201,300), true);
+ tc.addLog("/foo1/current/" + getFinalizedEditsFileName(301,400), false);
+ tc.addLog("/foo1/current/" + getInProgressEditsFileName(401), false);
+
+ // Test that other files don't get purged
+ tc.addLog("/foo1/current/VERSION", false);
+ runTest(tc);
+ }
+
+ /**
+ * Same as above, but across multiple directories
+ */
+ @Test
+ public void testPurgeMultipleDirs() throws IOException {
+ TestCaseDescription tc = new TestCaseDescription();
+ tc.addRoot("/foo1", NameNodeDirType.IMAGE_AND_EDITS);
+ tc.addRoot("/foo2", NameNodeDirType.IMAGE_AND_EDITS);
+ tc.addImage("/foo1/current/" + getImageFileName(100), true);
+ tc.addImage("/foo1/current/" + getImageFileName(200), true);
+ tc.addImage("/foo2/current/" + getImageFileName(200), true);
+ tc.addImage("/foo1/current/" + getImageFileName(300), false);
+ tc.addImage("/foo1/current/" + getImageFileName(400), false);
+ tc.addLog("/foo1/current/" + getFinalizedEditsFileName(101, 200), true);
+ tc.addLog("/foo1/current/" + getFinalizedEditsFileName(201, 300), true);
+ tc.addLog("/foo2/current/" + getFinalizedEditsFileName(201, 300), true);
+ tc.addLog("/foo1/current/" + getFinalizedEditsFileName(301, 400), false);
+ tc.addLog("/foo2/current/" + getFinalizedEditsFileName(301, 400), false);
+ tc.addLog("/foo1/current/" + getInProgressEditsFileName(401), false);
+ runTest(tc);
+ }
+
+ /**
+ * Test that if we have fewer fsimages than the configured
+ * retention, we don't purge any of them
+ */
+ @Test
+ public void testPurgeLessThanRetention() throws IOException {
+ TestCaseDescription tc = new TestCaseDescription();
+ tc.addRoot("/foo1", NameNodeDirType.IMAGE_AND_EDITS);
+ tc.addImage("/foo1/current/" + getImageFileName(100), false);
+ tc.addLog("/foo1/current/" + getFinalizedEditsFileName(101,200), false);
+ tc.addLog("/foo1/current/" + getFinalizedEditsFileName(201,300), false);
+ tc.addLog("/foo1/current/" + getFinalizedEditsFileName(301,400), false);
+ tc.addLog("/foo1/current/" + getInProgressEditsFileName(401), false);
+ runTest(tc);
+ }
+
+ /**
+ * Check for edge case with no logs present at all.
+ */
+ @Test
+ public void testNoLogs() throws IOException {
+ TestCaseDescription tc = new TestCaseDescription();
+ tc.addRoot("/foo1", NameNodeDirType.IMAGE_AND_EDITS);
+ tc.addImage("/foo1/current/" + getImageFileName(100), true);
+ tc.addImage("/foo1/current/" + getImageFileName(200), true);
+ tc.addImage("/foo1/current/" + getImageFileName(300), false);
+ tc.addImage("/foo1/current/" + getImageFileName(400), false);
+ runTest(tc);
+ }
+
+ /**
+ * Check for edge case with no logs or images present at all.
+ */
+ @Test
+ public void testEmptyDir() throws IOException {
+ TestCaseDescription tc = new TestCaseDescription();
+ tc.addRoot("/foo1", NameNodeDirType.IMAGE_AND_EDITS);
+ runTest(tc);
+ }
+
+ /**
+ * Test that old in-progress logs are properly purged
+ */
+ @Test
+ public void testOldInProgress() throws IOException {
+ TestCaseDescription tc = new TestCaseDescription();
+ tc.addRoot("/foo1", NameNodeDirType.IMAGE_AND_EDITS);
+ tc.addImage("/foo1/current/" + getImageFileName(100), true);
+ tc.addImage("/foo1/current/" + getImageFileName(200), true);
+ tc.addImage("/foo1/current/" + getImageFileName(300), false);
+ tc.addImage("/foo1/current/" + getImageFileName(400), false);
+ tc.addLog("/foo1/current/" + getInProgressEditsFileName(101), true);
+ runTest(tc);
+ }
+
+ @Test
+ public void testSeparateEditDirs() throws IOException {
+ TestCaseDescription tc = new TestCaseDescription();
+ tc.addRoot("/foo1", NameNodeDirType.IMAGE);
+ tc.addRoot("/foo2", NameNodeDirType.EDITS);
+ tc.addImage("/foo1/current/" + getImageFileName(100), true);
+ tc.addImage("/foo1/current/" + getImageFileName(200), true);
+ tc.addImage("/foo1/current/" + getImageFileName(300), false);
+ tc.addImage("/foo1/current/" + getImageFileName(400), false);
+
+ tc.addLog("/foo2/current/" + getFinalizedEditsFileName(101, 200), true);
+ tc.addLog("/foo2/current/" + getFinalizedEditsFileName(201, 300), true);
+ tc.addLog("/foo2/current/" + getFinalizedEditsFileName(301, 400), false);
+ tc.addLog("/foo2/current/" + getInProgressEditsFileName(401), false);
+ runTest(tc);
+ }
+
+ private void runTest(TestCaseDescription tc) throws IOException {
+ Configuration conf = new Configuration();
+
+ StoragePurger mockPurger =
+ Mockito.mock(NNStorageRetentionManager.StoragePurger.class);
+ ArgumentCaptor<FoundFSImage> imagesPurgedCaptor =
+ ArgumentCaptor.forClass(FoundFSImage.class);
+ ArgumentCaptor<FoundEditLog> logsPurgedCaptor =
+ ArgumentCaptor.forClass(FoundEditLog.class);
+
+ // Ask the manager to purge files we don't need any more
+ new NNStorageRetentionManager(conf,
+ tc.mockStorage(), tc.mockEditLog(), mockPurger)
+ .purgeOldStorage();
+
+ // Verify that it asked the purger to remove the correct files
+ Mockito.verify(mockPurger, Mockito.atLeast(0))
+ .purgeImage(imagesPurgedCaptor.capture());
+ Mockito.verify(mockPurger, Mockito.atLeast(0))
+ .purgeLog(logsPurgedCaptor.capture());
+
+ // Check images
+ Set<String> purgedPaths = Sets.newHashSet();
+ for (FoundFSImage purged : imagesPurgedCaptor.getAllValues()) {
+ purgedPaths.add(purged.getFile().toString());
+ }
+ Assert.assertEquals(Joiner.on(",").join(tc.expectedPurgedImages),
+ Joiner.on(",").join(purgedPaths));
+
+ // Check images
+ purgedPaths.clear();
+ for (FoundEditLog purged : logsPurgedCaptor.getAllValues()) {
+ purgedPaths.add(purged.getFile().toString());
+ }
+ Assert.assertEquals(Joiner.on(",").join(tc.expectedPurgedLogs),
+ Joiner.on(",").join(purgedPaths));
+ }
+
+ private static class TestCaseDescription {
+ private Map<String, FakeRoot> dirRoots = Maps.newHashMap();
+ private Set<String> expectedPurgedLogs = Sets.newHashSet();
+ private Set<String> expectedPurgedImages = Sets.newHashSet();
+
+ private static class FakeRoot {
+ NameNodeDirType type;
+ List<String> files;
+
+ FakeRoot(NameNodeDirType type) {
+ this.type = type;
+ files = Lists.newArrayList();
+ }
+
+ StorageDirectory mockStorageDir() {
+ return TestFSImageStorageInspector.mockDirectory(
+ type, false,
+ files.toArray(new String[0]));
+ }
+ }
+
+ void addRoot(String root, NameNodeDirType dir) {
+ dirRoots.put(root, new FakeRoot(dir));
+ }
+
+ private void addFile(String path) {
+ for (Map.Entry<String, FakeRoot> entry : dirRoots.entrySet()) {
+ if (path.startsWith(entry.getKey())) {
+ entry.getValue().files.add(path);
+ }
+ }
+ }
+
+ void addLog(String path, boolean expectPurge) {
+ addFile(path);
+ if (expectPurge) {
+ expectedPurgedLogs.add(path);
+ }
+ }
+
+ void addImage(String path, boolean expectPurge) {
+ addFile(path);
+ if (expectPurge) {
+ expectedPurgedImages.add(path);
+ }
+ }
+
+ NNStorage mockStorage() throws IOException {
+ List<StorageDirectory> sds = Lists.newArrayList();
+ for (FakeRoot root : dirRoots.values()) {
+ sds.add(root.mockStorageDir());
+ }
+ return mockStorageForDirs(sds.toArray(new StorageDirectory[0]));
+ }
+
+ public FSEditLog mockEditLog() {
+ final List<JournalManager> jms = Lists.newArrayList();
+ for (FakeRoot root : dirRoots.values()) {
+ if (!root.type.isOfType(NameNodeDirType.EDITS)) continue;
+
+ FileJournalManager fjm = new FileJournalManager(
+ root.mockStorageDir());
+ jms.add(fjm);
+ }
+
+ FSEditLog mockLog = Mockito.mock(FSEditLog.class);
+ Mockito.doAnswer(new Answer<Void>() {
+
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ assert args.length == 2;
+ long txId = (Long) args[0];
+ StoragePurger purger = (StoragePurger) args[1];
+
+ for (JournalManager jm : jms) {
+ jm.purgeLogsOlderThan(txId, purger);
+ }
+ return null;
+ }
+ }).when(mockLog).purgeLogsOlderThan(
+ Mockito.anyLong(), (StoragePurger) Mockito.anyObject());
+ return mockLog;
+ }
+ }
+
+ private static NNStorage mockStorageForDirs(final StorageDirectory ... mockDirs)
+ throws IOException {
+ NNStorage mockStorage = Mockito.mock(NNStorage.class);
+ Mockito.doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ FSImageStorageInspector inspector =
+ (FSImageStorageInspector) invocation.getArguments()[0];
+ for (StorageDirectory sd : mockDirs) {
+ inspector.inspectDirectory(sd);
+ }
+ return null;
+ }
+ }).when(mockStorage).inspectStorageDirs(
+ Mockito.<FSImageStorageInspector>anyObject());
+ return mockStorage;
+ }
+}
Modified: hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestNameEditsConfigs.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestNameEditsConfigs.java?rev=1152295&r1=1152294&r2=1152295&view=diff
==============================================================================
--- hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestNameEditsConfigs.java (original)
+++ hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestNameEditsConfigs.java Fri Jul 29 16:28:45 2011
@@ -28,6 +28,10 @@ import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.DFSConfigKeys;
+import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeDirType;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
/**
* This class tests various combinations of dfs.namenode.name.dir
@@ -46,13 +50,10 @@ public class TestNameEditsConfigs extend
System.getProperty("test.build.data", "build/test/data"), "dfs/");
protected void setUp() throws java.lang.Exception {
- if(base_dir.exists())
- tearDown();
- }
-
- protected void tearDown() throws java.lang.Exception {
- if (!FileUtil.fullyDelete(base_dir))
- throw new IOException("Cannot remove directory " + base_dir);
+ if(base_dir.exists()) {
+ if (!FileUtil.fullyDelete(base_dir))
+ throw new IOException("Cannot remove directory " + base_dir);
+ }
}
private void writeFile(FileSystem fileSys, Path name, int repl)
@@ -68,10 +69,22 @@ public class TestNameEditsConfigs extend
}
void checkImageAndEditsFilesExistence(File dir,
- boolean imageMustExist,
- boolean editsMustExist) {
- assertTrue(imageMustExist == new File(dir, FILE_IMAGE).exists());
- assertTrue(editsMustExist == new File(dir, FILE_EDITS).exists());
+ boolean shouldHaveImages,
+ boolean shouldHaveEdits)
+ throws IOException {
+ FSImageTransactionalStorageInspector ins = inspect(dir);
+
+ if (shouldHaveImages) {
+ assertTrue("Expect images in " + dir, ins.foundImages.size() > 0);
+ } else {
+ assertTrue("Expect no images in " + dir, ins.foundImages.isEmpty());
+ }
+
+ if (shouldHaveEdits) {
+ assertTrue("Expect edits in " + dir, ins.foundEditLogs.size() > 0);
+ } else {
+ assertTrue("Expect no edits in " + dir, ins.foundEditLogs.isEmpty());
+ }
}
private void checkFile(FileSystem fileSys, Path name, int repl)
@@ -110,9 +123,10 @@ public class TestNameEditsConfigs extend
* do not read any stale image or edits.
* All along the test, we create and delete files at reach restart to make
* sure we are reading proper edits and image.
+ * @throws Exception
*/
@SuppressWarnings("deprecation")
- public void testNameEditsConfigs() throws IOException {
+ public void testNameEditsConfigs() throws Exception {
Path file1 = new Path("TestNameEditsConfigs1");
Path file2 = new Path("TestNameEditsConfigs2");
Path file3 = new Path("TestNameEditsConfigs3");
@@ -120,12 +134,26 @@ public class TestNameEditsConfigs extend
SecondaryNameNode secondary = null;
Configuration conf = null;
FileSystem fileSys = null;
- File newNameDir = new File(base_dir, "name");
- File newEditsDir = new File(base_dir, "edits");
- File nameAndEdits = new File(base_dir, "name_and_edits");
- File checkpointNameDir = new File(base_dir, "secondname");
- File checkpointEditsDir = new File(base_dir, "secondedits");
- File checkpointNameAndEdits = new File(base_dir, "second_name_and_edits");
+ final File newNameDir = new File(base_dir, "name");
+ final File newEditsDir = new File(base_dir, "edits");
+ final File nameAndEdits = new File(base_dir, "name_and_edits");
+ final File checkpointNameDir = new File(base_dir, "secondname");
+ final File checkpointEditsDir = new File(base_dir, "secondedits");
+ final File checkpointNameAndEdits = new File(base_dir, "second_name_and_edits");
+
+ ImmutableList<File> allCurrentDirs = ImmutableList.of(
+ new File(nameAndEdits, "current"),
+ new File(newNameDir, "current"),
+ new File(newEditsDir, "current"),
+ new File(checkpointNameAndEdits, "current"),
+ new File(checkpointNameDir, "current"),
+ new File(checkpointEditsDir, "current"));
+ ImmutableList<File> imageCurrentDirs = ImmutableList.of(
+ new File(nameAndEdits, "current"),
+ new File(newNameDir, "current"),
+ new File(checkpointNameAndEdits, "current"),
+ new File(checkpointNameDir, "current"));
+
// Start namenode with same dfs.namenode.name.dir and dfs.namenode.edits.dir
conf = new HdfsConfiguration();
@@ -191,23 +219,12 @@ public class TestNameEditsConfigs extend
secondary.shutdown();
}
- checkImageAndEditsFilesExistence(nameAndEdits, true, true);
- checkImageAndEditsFilesExistence(newNameDir, true, false);
- checkImageAndEditsFilesExistence(newEditsDir, false, true);
- checkImageAndEditsFilesExistence(checkpointNameAndEdits, true, true);
- checkImageAndEditsFilesExistence(checkpointNameDir, true, false);
- checkImageAndEditsFilesExistence(checkpointEditsDir, false, true);
-
+ FSImageTestUtil.assertParallelFilesAreIdentical(allCurrentDirs,
+ ImmutableSet.of("VERSION"));
+ FSImageTestUtil.assertSameNewestImage(imageCurrentDirs);
+
// Now remove common directory both have and start namenode with
// separate name and edits dirs
- new File(nameAndEdits, FILE_EDITS).renameTo(
- new File(newNameDir, FILE_EDITS));
- new File(nameAndEdits, FILE_IMAGE).renameTo(
- new File(newEditsDir, FILE_IMAGE));
- new File(checkpointNameAndEdits, FILE_EDITS).renameTo(
- new File(checkpointNameDir, FILE_EDITS));
- new File(checkpointNameAndEdits, FILE_IMAGE).renameTo(
- new File(checkpointEditsDir, FILE_IMAGE));
conf = new HdfsConfiguration();
conf.set(DFSConfigKeys.DFS_NAMENODE_NAME_DIR_KEY, newNameDir.getPath());
conf.set(DFSConfigKeys.DFS_NAMENODE_EDITS_DIR_KEY, newEditsDir.getPath());
@@ -237,7 +254,8 @@ public class TestNameEditsConfigs extend
cluster.shutdown();
secondary.shutdown();
}
-
+
+ // No edit logs in new name dir
checkImageAndEditsFilesExistence(newNameDir, true, false);
checkImageAndEditsFilesExistence(newEditsDir, false, true);
checkImageAndEditsFilesExistence(checkpointNameDir, true, false);
@@ -281,12 +299,18 @@ public class TestNameEditsConfigs extend
checkImageAndEditsFilesExistence(checkpointNameAndEdits, true, true);
}
+ private FSImageTransactionalStorageInspector inspect(File storageDir)
+ throws IOException {
+ return FSImageTestUtil.inspectStorageDirectory(
+ new File(storageDir, "current"), NameNodeDirType.IMAGE_AND_EDITS);
+ }
+
/**
* Test various configuration options of dfs.namenode.name.dir and dfs.namenode.edits.dir
* This test tries to simulate failure scenarios.
* 1. Start cluster with shared name and edits dir
* 2. Restart cluster by adding separate name and edits dirs
- * 3. Restart cluster by removing shared name and edits dir
+ * T3. Restart cluster by removing shared name and edits dir
* 4. Restart cluster with old shared name and edits dir, but only latest
* name dir. This should fail since we dont have latest edits dir
* 5. Restart cluster with old shared name and edits dir, but only latest
@@ -314,6 +338,10 @@ public class TestNameEditsConfigs extend
.manageNameDfsDirs(false)
.build();
cluster.waitActive();
+
+ // Check that the dir has a VERSION file
+ assertTrue(new File(nameAndEdits, "current/VERSION").exists());
+
fileSys = cluster.getFileSystem();
try {
@@ -342,6 +370,12 @@ public class TestNameEditsConfigs extend
.manageNameDfsDirs(false)
.build();
cluster.waitActive();
+
+ // Check that the dirs have a VERSION file
+ assertTrue(new File(nameAndEdits, "current/VERSION").exists());
+ assertTrue(new File(newNameDir, "current/VERSION").exists());
+ assertTrue(new File(newEditsDir, "current/VERSION").exists());
+
fileSys = cluster.getFileSystem();
try {
@@ -380,7 +414,7 @@ public class TestNameEditsConfigs extend
fileSys.close();
cluster.shutdown();
}
-
+
// Add old shared directory for name and edits along with latest name
conf = new HdfsConfiguration();
conf.set(DFSConfigKeys.DFS_NAMENODE_NAME_DIR_KEY, newNameDir.getPath() + "," +
@@ -401,7 +435,9 @@ public class TestNameEditsConfigs extend
cluster = null;
}
- // Add old shared directory for name and edits along with latest edits
+ // Add old shared directory for name and edits along with latest edits.
+ // This is OK, since the latest edits will have segments leading all
+ // the way from the image in name_and_edits.
conf = new HdfsConfiguration();
conf.set(DFSConfigKeys.DFS_NAMENODE_NAME_DIR_KEY, nameAndEdits.getPath());
conf.set(DFSConfigKeys.DFS_NAMENODE_EDITS_DIR_KEY, newEditsDir.getPath() +
@@ -413,11 +449,17 @@ public class TestNameEditsConfigs extend
.format(false)
.manageNameDfsDirs(false)
.build();
- assertTrue(false);
+ assertTrue(!fileSys.exists(file1));
+ assertTrue(fileSys.exists(file2));
+ checkFile(fileSys, file2, replication);
+ cleanupFile(fileSys, file2);
+ writeFile(fileSys, file3, replication);
+ checkFile(fileSys, file3, replication);
} catch (IOException e) { // expect to fail
System.out.println("cluster start failed due to missing latest name dir");
} finally {
- cluster = null;
+ fileSys.close();
+ cluster.shutdown();
}
}
}
Modified: hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestParallelImageWrite.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestParallelImageWrite.java?rev=1152295&r1=1152294&r2=1152295&view=diff
==============================================================================
--- hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestParallelImageWrite.java (original)
+++ hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestParallelImageWrite.java Fri Jul 29 16:28:45 2011
@@ -30,16 +30,12 @@ import org.apache.hadoop.hdfs.MiniDFSClu
import org.apache.hadoop.hdfs.DFSTestUtil;
import org.apache.hadoop.hdfs.HdfsConfiguration;
import org.apache.hadoop.hdfs.protocol.FSConstants.SafeModeAction;
-import org.apache.hadoop.util.PureJavaCrc32;
import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeDirType;
-import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeFile;
-import java.util.Iterator;
+import java.util.Collections;
import java.util.List;
-import java.util.ArrayList;
import java.io.File;
-import java.io.FileInputStream;
/**
* A JUnit test for checking if restarting DFS preserves integrity.
@@ -84,6 +80,10 @@ public class TestParallelImageWrite exte
if (cluster != null) { cluster.shutdown(); }
}
try {
+ // Force the NN to save its images on startup so long as
+ // there are any uncheckpointed txns
+ conf.setInt(DFSConfigKeys.DFS_NAMENODE_CHECKPOINT_TXNS_KEY, 1);
+
// Here we restart the MiniDFScluster without formatting namenode
cluster = new MiniDFSCluster.Builder(conf).format(false)
.numDataNodes(NUM_DATANODES).build();
@@ -102,16 +102,17 @@ public class TestParallelImageWrite exte
assertEquals(dirstatus.getGroup() + "_XXX", newdirstatus.getGroup());
rootmtime = fs.getFileStatus(rootpath).getModificationTime();
- final long checkAfterRestart = checkImages(fsn, numNamenodeDirs);
+ final String checkAfterRestart = checkImages(fsn, numNamenodeDirs);
// Modify the system and then perform saveNamespace
files.cleanup(fs, dir);
files.createFiles(fs, dir);
fsn.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
cluster.getNameNode().saveNamespace();
- final long checkAfterModify = checkImages(fsn, numNamenodeDirs);
- assertTrue("Modified namespace doesn't change fsimage contents",
- checkAfterRestart != checkAfterModify);
+ final String checkAfterModify = checkImages(fsn, numNamenodeDirs);
+ assertFalse("Modified namespace should change fsimage contents. " +
+ "was: " + checkAfterRestart + " now: " + checkAfterModify,
+ checkAfterRestart.equals(checkAfterModify));
fsn.setSafeMode(SafeModeAction.SAFEMODE_LEAVE);
files.cleanup(fs, dir);
} finally {
@@ -124,42 +125,35 @@ public class TestParallelImageWrite exte
* and non-empty, and there are the expected number of them.
* @param fsn - the FSNamesystem being checked.
* @param numImageDirs - the configured number of StorageDirectory of type IMAGE.
- * @return - the checksum of the FSImage files, which must all be the same.
+ * @return - the md5 hash of the most recent FSImage files, which must all be the same.
* @throws AssertionFailedError if image files are empty or different,
* if less than two StorageDirectory are provided, or if the
* actual number of StorageDirectory is less than configured.
*/
- public static long checkImages(FSNamesystem fsn, int numImageDirs) throws Exception {
+ public static String checkImages(
+ FSNamesystem fsn, int numImageDirs)
+ throws Exception {
NNStorage stg = fsn.getFSImage().getStorage();
//any failed StorageDirectory is removed from the storageDirs list
assertEquals("Some StorageDirectories failed Upgrade",
numImageDirs, stg.getNumStorageDirs(NameNodeDirType.IMAGE));
assertTrue("Not enough fsimage copies in MiniDFSCluster " +
"to test parallel write", numImageDirs > 1);
- //checksum the FSImage stored in each storageDir
- Iterator<StorageDirectory> iter = stg.dirIterator(NameNodeDirType.IMAGE);
- List<Long> checksums = new ArrayList<Long>();
- while (iter.hasNext()) {
- StorageDirectory sd = iter.next();
- File fsImage = NNStorage.getStorageFile(sd, NameNodeFile.IMAGE);
- PureJavaCrc32 crc = new PureJavaCrc32();
- FileInputStream in = new FileInputStream(fsImage);
- byte[] buff = new byte[4096];
- int read = 0;
- while ((read = in.read(buff)) != -1) {
- crc.update(buff, 0, read);
- }
- long val = crc.getValue();
- checksums.add(val);
- }
- assertEquals(numImageDirs, checksums.size());
- PureJavaCrc32 crc = new PureJavaCrc32();
- long emptyCrc = crc.getValue();
- assertTrue("Empty fsimage file", checksums.get(0) != emptyCrc);
- for (int i = 1; i < numImageDirs; i++) {
- assertEquals(checksums.get(i - 1), checksums.get(i));
- }
- return checksums.get(0);
+
+ // List of "current/" directory from each SD
+ List<File> dirs = FSImageTestUtil.getCurrentDirs(stg, NameNodeDirType.IMAGE);
+
+ // across directories, all files with same names should be identical hashes
+ FSImageTestUtil.assertParallelFilesAreIdentical(
+ dirs, Collections.<String>emptySet());
+ FSImageTestUtil.assertSameNewestImage(dirs);
+
+ // Return the hash of the newest image file
+ StorageDirectory firstSd = stg.dirIterator(NameNodeDirType.IMAGE).next();
+ File latestImage = FSImageTestUtil.findLatestImageFile(firstSd);
+ String md5 = FSImageTestUtil.getImageFileMD5IgnoringTxId(latestImage);
+ System.err.println("md5 of " + latestImage + ": " + md5);
+ return md5;
}
}
Modified: hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSaveNamespace.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSaveNamespace.java?rev=1152295&r1=1152294&r2=1152295&view=diff
==============================================================================
--- hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSaveNamespace.java (original)
+++ hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSaveNamespace.java Fri Jul 29 16:28:45 2011
@@ -18,10 +18,11 @@
package org.apache.hadoop.hdfs.server.namenode;
import static org.apache.hadoop.hdfs.server.common.Util.fileAsURI;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+
+import static org.junit.Assert.*;
+
import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.spy;
@@ -31,6 +32,7 @@ import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.commons.logging.impl.Log4JLogger;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.permission.FsPermission;
@@ -42,7 +44,7 @@ import org.apache.hadoop.hdfs.MiniDFSClu
import org.apache.hadoop.hdfs.protocol.FSConstants.SafeModeAction;
import org.apache.hadoop.hdfs.server.common.HdfsConstants.NamenodeRole;
import org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory;
-import org.apache.hadoop.test.GenericTestUtils;
+import org.apache.log4j.Level;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
@@ -60,46 +62,47 @@ import org.mockito.stubbing.Answer;
* </ol>
*/
public class TestSaveNamespace {
+ static {
+ ((Log4JLogger)FSImage.LOG).getLogger().setLevel(Level.ALL);
+ }
+
private static final Log LOG = LogFactory.getLog(TestSaveNamespace.class);
private static class FaultySaveImage implements Answer<Void> {
int count = 0;
- boolean exceptionType = true;
-
- // generate a RuntimeException
- public FaultySaveImage() {
- this.exceptionType = true;
- }
+ boolean throwRTE = true;
// generate either a RuntimeException or IOException
- public FaultySaveImage(boolean etype) {
- this.exceptionType = etype;
+ public FaultySaveImage(boolean throwRTE) {
+ this.throwRTE = throwRTE;
}
public Void answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
- File f = (File)args[0];
+ StorageDirectory sd = (StorageDirectory)args[0];
if (count++ == 1) {
- LOG.info("Injecting fault for file: " + f);
- if (exceptionType) {
+ LOG.info("Injecting fault for sd: " + sd);
+ if (throwRTE) {
throw new RuntimeException("Injected fault: saveFSImage second time");
} else {
throw new IOException("Injected fault: saveFSImage second time");
}
}
- LOG.info("Not injecting fault for file: " + f);
+ LOG.info("Not injecting fault for sd: " + sd);
return (Void)invocation.callRealMethod();
}
}
private enum Fault {
- SAVE_FSIMAGE,
- MOVE_CURRENT,
- MOVE_LAST_CHECKPOINT
+ SAVE_SECOND_FSIMAGE_RTE,
+ SAVE_SECOND_FSIMAGE_IOE,
+ SAVE_ALL_FSIMAGES,
+ WRITE_STORAGE_ALL,
+ WRITE_STORAGE_ONE
};
- private void saveNamespaceWithInjectedFault(Fault fault) throws IOException {
+ private void saveNamespaceWithInjectedFault(Fault fault) throws Exception {
Configuration conf = getConf();
NameNode.initMetrics(conf, NamenodeRole.NAMENODE);
DFSTestUtil.formatNameNode(conf);
@@ -108,46 +111,71 @@ public class TestSaveNamespace {
// Replace the FSImage with a spy
FSImage originalImage = fsn.dir.fsImage;
NNStorage storage = originalImage.getStorage();
- storage.close(); // unlock any directories that FSNamesystem's initialization may have locked
NNStorage spyStorage = spy(storage);
originalImage.storage = spyStorage;
FSImage spyImage = spy(originalImage);
fsn.dir.fsImage = spyImage;
-
- spyImage.getStorage().setStorageDirectories(FSNamesystem.getNamespaceDirs(conf),
- FSNamesystem.getNamespaceEditsDirs(conf));
+ boolean shouldFail = false; // should we expect the save operation to fail
// inject fault
switch(fault) {
- case SAVE_FSIMAGE:
+ case SAVE_SECOND_FSIMAGE_RTE:
// The spy throws a RuntimeException when writing to the second directory
- doAnswer(new FaultySaveImage()).
- when(spyImage).saveFSImage((File)anyObject());
+ doAnswer(new FaultySaveImage(true)).
+ when(spyImage).saveFSImage((StorageDirectory)anyObject(), anyLong());
+ shouldFail = false;
+ break;
+ case SAVE_SECOND_FSIMAGE_IOE:
+ // The spy throws an IOException when writing to the second directory
+ doAnswer(new FaultySaveImage(false)).
+ when(spyImage).saveFSImage((StorageDirectory)anyObject(), anyLong());
+ shouldFail = false;
+ break;
+ case SAVE_ALL_FSIMAGES:
+ // The spy throws IOException in all directories
+ doThrow(new RuntimeException("Injected")).
+ when(spyImage).saveFSImage((StorageDirectory)anyObject(), anyLong());
+ shouldFail = true;
break;
- case MOVE_CURRENT:
- // The spy throws a RuntimeException when calling moveCurrent()
- doThrow(new RuntimeException("Injected fault: moveCurrent")).
- when(spyStorage).moveCurrent((StorageDirectory)anyObject());
+ case WRITE_STORAGE_ALL:
+ // The spy throws an exception before writing any VERSION files
+ doThrow(new RuntimeException("Injected"))
+ .when(spyStorage).writeAll();
+ shouldFail = true;
break;
- case MOVE_LAST_CHECKPOINT:
- // The spy throws a RuntimeException when calling moveLastCheckpoint()
- doThrow(new RuntimeException("Injected fault: moveLastCheckpoint")).
- when(spyStorage).moveLastCheckpoint((StorageDirectory)anyObject());
+ case WRITE_STORAGE_ONE:
+ // The spy throws on exception on one particular storage directory
+ doAnswer(new FaultySaveImage(true))
+ .when(spyStorage).writeProperties((StorageDirectory)anyObject());
+ // TODO: unfortunately this fails -- should be improved.
+ // See HDFS-2173.
+ shouldFail = true;
break;
}
try {
doAnEdit(fsn, 1);
- // Save namespace - this will fail because we inject a fault.
+ // Save namespace - this may fail, depending on fault injected
fsn.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
try {
fsn.saveNamespace();
+ if (shouldFail) {
+ fail("Did not fail!");
+ }
} catch (Exception e) {
- LOG.info("Test caught expected exception", e);
+ if (! shouldFail) {
+ throw e;
+ } else {
+ LOG.info("Test caught expected exception", e);
+ }
}
+
+ fsn.setSafeMode(SafeModeAction.SAFEMODE_LEAVE);
+ // Should still be able to perform edits
+ doAnEdit(fsn, 2);
// Now shut down and restart the namesystem
originalImage.close();
@@ -158,8 +186,9 @@ public class TestSaveNamespace {
// the namespace from the previous incarnation.
fsn = new FSNamesystem(conf);
- // Make sure the image loaded including our edit.
+ // Make sure the image loaded including our edits.
checkEditExists(fsn, 1);
+ checkEditExists(fsn, 2);
} finally {
if (fsn != null) {
fsn.close();
@@ -185,35 +214,33 @@ public class TestSaveNamespace {
// Replace the FSImage with a spy
FSImage originalImage = fsn.dir.fsImage;
NNStorage storage = originalImage.getStorage();
- storage.close(); // unlock any directories that FSNamesystem's initialization may have locked
-
- NNStorage spyStorage = spy(storage);
- originalImage.storage = spyStorage;
FSImage spyImage = spy(originalImage);
fsn.dir.fsImage = spyImage;
-
- spyImage.getStorage().setStorageDirectories(FSNamesystem.getNamespaceDirs(conf),
- FSNamesystem.getNamespaceEditsDirs(conf));
-
- // inject fault
- // The spy throws a IOException when writing to the second directory
- doAnswer(new FaultySaveImage(false)).
- when(spyImage).saveFSImage((File)anyObject());
+
+ File rootDir = storage.getStorageDir(0).getRoot();
+ rootDir.setExecutable(false);
+ rootDir.setWritable(false);
+ rootDir.setReadable(false);
try {
doAnEdit(fsn, 1);
fsn.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
- // Save namespace - this injects a fault and marks one
- // directory as faulty.
+ // Save namespace - should mark the first storage dir as faulty
+ // since it's not traversable.
LOG.info("Doing the first savenamespace.");
fsn.saveNamespace();
- LOG.warn("First savenamespace sucessful.");
+ LOG.info("First savenamespace sucessful.");
+
assertTrue("Savenamespace should have marked one directory as bad." +
- " But found " + spyStorage.getRemovedStorageDirs().size() +
+ " But found " + storage.getRemovedStorageDirs().size() +
" bad directories.",
- spyStorage.getRemovedStorageDirs().size() == 1);
+ storage.getRemovedStorageDirs().size() == 1);
+
+ rootDir.setExecutable(true);
+ rootDir.setWritable(true);
+ rootDir.setReadable(true);
// The next call to savenamespace should try inserting the
// erroneous directory back to fs.name.dir. This command should
@@ -243,33 +270,53 @@ public class TestSaveNamespace {
checkEditExists(fsn, 1);
LOG.info("Reloaded image is good.");
} finally {
+ if (rootDir.exists()) {
+ rootDir.setExecutable(true);
+ rootDir.setWritable(true);
+ rootDir.setReadable(true);
+ }
+
if (fsn != null) {
- fsn.close();
+ try {
+ fsn.close();
+ } catch (Throwable t) {
+ LOG.fatal("Failed to shut down", t);
+ }
}
}
}
@Test
- public void testCrashWhileSavingSecondImage() throws Exception {
- saveNamespaceWithInjectedFault(Fault.SAVE_FSIMAGE);
+ public void testRTEWhileSavingSecondImage() throws Exception {
+ saveNamespaceWithInjectedFault(Fault.SAVE_SECOND_FSIMAGE_RTE);
}
@Test
- public void testCrashWhileMoveCurrent() throws Exception {
- saveNamespaceWithInjectedFault(Fault.MOVE_CURRENT);
+ public void testIOEWhileSavingSecondImage() throws Exception {
+ saveNamespaceWithInjectedFault(Fault.SAVE_SECOND_FSIMAGE_IOE);
}
@Test
- public void testCrashWhileMoveLastCheckpoint() throws Exception {
- saveNamespaceWithInjectedFault(Fault.MOVE_LAST_CHECKPOINT);
+ public void testCrashInAllImageDirs() throws Exception {
+ saveNamespaceWithInjectedFault(Fault.SAVE_ALL_FSIMAGES);
+ }
+
+ @Test
+ public void testCrashWhenWritingVersionFiles() throws Exception {
+ saveNamespaceWithInjectedFault(Fault.WRITE_STORAGE_ALL);
+ }
+
+ @Test
+ public void testCrashWhenWritingVersionFileInOneDir() throws Exception {
+ saveNamespaceWithInjectedFault(Fault.WRITE_STORAGE_ONE);
}
/**
* Test case where savenamespace fails in all directories
* and then the NN shuts down. Here we should recover from the
- * failed checkpoint by moving the directories back on next
- * NN start. This is a regression test for HDFS-1921.
+ * failed checkpoint since it only affected ".ckpt" files, not
+ * valid image files
*/
@Test
public void testFailedSaveNamespace() throws Exception {
@@ -313,7 +360,8 @@ public class TestSaveNamespace {
FSNamesystem.getNamespaceEditsDirs(conf));
doThrow(new IOException("Injected fault: saveFSImage")).
- when(spyImage).saveFSImage((File)anyObject());
+ when(spyImage).saveFSImage((StorageDirectory)anyObject(),
+ Mockito.anyLong());
try {
doAnEdit(fsn, 1);
@@ -360,16 +408,6 @@ public class TestSaveNamespace {
DFSTestUtil.formatNameNode(conf);
FSNamesystem fsn = new FSNamesystem(conf);
- // Replace the FSImage with a spy
- final FSImage originalImage = fsn.dir.fsImage;
- originalImage.getStorage().close();
-
- FSImage spyImage = spy(originalImage);
- spyImage.getStorage().setStorageDirectories(
- FSNamesystem.getNamespaceDirs(conf),
- FSNamesystem.getNamespaceEditsDirs(conf));
- fsn.dir.fsImage = spyImage;
-
try {
doAnEdit(fsn, 1);
CheckpointSignature sig = fsn.rollEditLog();
@@ -382,7 +420,6 @@ public class TestSaveNamespace {
fsn.saveNamespace();
// Now shut down and restart the NN
- originalImage.close();
fsn.close();
fsn = null;
@@ -399,7 +436,45 @@ public class TestSaveNamespace {
}
}
}
+
+ @Test
+ public void testTxIdPersistence() throws Exception {
+ Configuration conf = getConf();
+ NameNode.initMetrics(conf, NamenodeRole.NAMENODE);
+ DFSTestUtil.formatNameNode(conf);
+ FSNamesystem fsn = new FSNamesystem(conf);
+
+ try {
+ // We have a BEGIN_LOG_SEGMENT txn to start
+ assertEquals(1, fsn.getEditLog().getLastWrittenTxId());
+ doAnEdit(fsn, 1);
+ assertEquals(2, fsn.getEditLog().getLastWrittenTxId());
+
+ fsn.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
+ fsn.saveNamespace();
+ // 2 more txns: END the first segment, BEGIN a new one
+ assertEquals(4, fsn.getEditLog().getLastWrittenTxId());
+
+ // Shut down and restart
+ fsn.getFSImage().close();
+ fsn.close();
+
+ // 1 more txn to END that segment
+ assertEquals(5, fsn.getEditLog().getLastWrittenTxId());
+ fsn = null;
+
+ fsn = new FSNamesystem(conf);
+ // 1 more txn to start new segment on restart
+ assertEquals(6, fsn.getEditLog().getLastWrittenTxId());
+
+ } finally {
+ if (fsn != null) {
+ fsn.close();
+ }
+ }
+ }
+
private void doAnEdit(FSNamesystem fsn, int id) throws IOException {
// Make an edit
fsn.mkdirs(
Modified: hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSecurityTokenEditLog.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSecurityTokenEditLog.java?rev=1152295&r1=1152294&r2=1152295&view=diff
==============================================================================
--- hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSecurityTokenEditLog.java (original)
+++ hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestSecurityTokenEditLog.java Fri Jul 29 16:28:45 2011
@@ -106,9 +106,7 @@ public class TestSecurityTokenEditLog ex
FSEditLog editLog = fsimage.getEditLog();
// set small size of flush buffer
- editLog.setBufferCapacity(2048);
- editLog.close();
- editLog.open();
+ editLog.setOutputBufferCapacity(2048);
namesystem.getDelegationTokenSecretManager().startThreads();
// Create threads and make them run transactions concurrently.
@@ -129,25 +127,24 @@ public class TestSecurityTokenEditLog ex
}
editLog.close();
-
+
// Verify that we can read in all the transactions that we have written.
// If there were any corruptions, it is likely that the reading in
// of these transactions will throw an exception.
//
- FSEditLogLoader loader = new FSEditLogLoader(namesystem);
namesystem.getDelegationTokenSecretManager().stopThreads();
int numKeys = namesystem.getDelegationTokenSecretManager().getNumberOfKeys();
- for (Iterator<StorageDirectory> it =
- fsimage.getStorage().dirIterator(NameNodeDirType.EDITS); it.hasNext();) {
- File editFile = fsimage.getStorage().getStorageFile(it.next(), NameNodeFile.EDITS);
+ int expectedTransactions = NUM_THREADS * opsPerTrans * NUM_TRANSACTIONS + numKeys
+ + 2; // + 2 for BEGIN and END txns
+
+ for (StorageDirectory sd : fsimage.getStorage().dirIterable(NameNodeDirType.EDITS)) {
+ File editFile = NNStorage.getFinalizedEditsFile(sd, 1, 1 + expectedTransactions - 1);
System.out.println("Verifying file: " + editFile);
+
+ FSEditLogLoader loader = new FSEditLogLoader(namesystem);
int numEdits = loader.loadFSEdits(
- new EditLogFileInputStream(editFile));
- assertTrue("Verification for " + editFile + " failed. " +
- "Expected " + (NUM_THREADS * opsPerTrans * NUM_TRANSACTIONS + numKeys) + " transactions. "+
- "Found " + numEdits + " transactions.",
- numEdits == NUM_THREADS * opsPerTrans * NUM_TRANSACTIONS +numKeys);
-
+ new EditLogFileInputStream(editFile), 1);
+ assertEquals("Verification for " + editFile, expectedTransactions, numEdits);
}
} finally {
if(fileSys != null) fileSys.close();
Modified: hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartup.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartup.java?rev=1152295&r1=1152294&r2=1152295&view=diff
==============================================================================
--- hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartup.java (original)
+++ hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartup.java Fri Jul 29 16:28:45 2011
@@ -21,16 +21,12 @@ import static org.apache.hadoop.hdfs.ser
import static org.apache.hadoop.hdfs.server.common.Util.fileAsURI;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.RandomAccessFile;
import java.net.InetAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
-import java.util.Properties;
import java.util.Random;
import junit.framework.TestCase;
@@ -45,7 +41,6 @@ import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.fs.permission.PermissionStatus;
-import org.apache.hadoop.hdfs.DFSClient;
import org.apache.hadoop.hdfs.DFSConfigKeys;
import org.apache.hadoop.hdfs.DFSTestUtil;
import org.apache.hadoop.hdfs.HdfsConfiguration;
@@ -56,7 +51,7 @@ import org.apache.hadoop.hdfs.protocol.F
import org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory;
import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeDirType;
import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeFile;
-import org.apache.hadoop.io.IOUtils;
+import org.apache.hadoop.hdfs.util.MD5FileUtils;
import org.apache.hadoop.io.MD5Hash;
import org.apache.hadoop.util.StringUtils;
import org.junit.Assert;
@@ -237,13 +232,11 @@ public class TestStartup extends TestCas
sd = it.next();
if(sd.getStorageDirType().isOfType(NameNodeDirType.IMAGE)) {
- img.getStorage();
- File imf = NNStorage.getStorageFile(sd, NameNodeFile.IMAGE);
+ File imf = img.getStorage().getStorageFile(sd, NameNodeFile.IMAGE, 0);
LOG.info("--image file " + imf.getAbsolutePath() + "; len = " + imf.length() + "; expected = " + expectedImgSize);
assertEquals(expectedImgSize, imf.length());
} else if(sd.getStorageDirType().isOfType(NameNodeDirType.EDITS)) {
- img.getStorage();
- File edf = NNStorage.getStorageFile(sd, NameNodeFile.EDITS);
+ File edf = img.getStorage().getStorageFile(sd, NameNodeFile.EDITS, 0);
LOG.info("-- edits file " + edf.getAbsolutePath() + "; len = " + edf.length() + "; expected = " + expectedEditsSize);
assertEquals(expectedEditsSize, edf.length());
} else {
@@ -348,8 +341,8 @@ public class TestStartup extends TestCas
FSImage image = nn.getFSImage();
StorageDirectory sd = image.getStorage().getStorageDir(0); //only one
assertEquals(sd.getStorageDirType(), NameNodeDirType.IMAGE_AND_EDITS);
- File imf = image.getStorage().getStorageFile(sd, NameNodeFile.IMAGE);
- File edf = image.getStorage().getStorageFile(sd, NameNodeFile.EDITS);
+ File imf = image.getStorage().getStorageFile(sd, NameNodeFile.IMAGE, 0);
+ File edf = image.getStorage().getStorageFile(sd, NameNodeFile.EDITS, 0);
LOG.info("--image file " + imf.getAbsolutePath() + "; len = " + imf.length());
LOG.info("--edits file " + edf.getAbsolutePath() + "; len = " + edf.length());
@@ -430,70 +423,57 @@ public class TestStartup extends TestCas
}
private void testImageChecksum(boolean compress) throws Exception {
- Configuration conf = new Configuration();
- FileSystem.setDefaultUri(conf, "hdfs://localhost:0");
- conf.set(DFSConfigKeys.DFS_NAMENODE_HTTP_ADDRESS_KEY, "127.0.0.1:0");
- File base_dir = new File(
- System.getProperty("test.build.data", "build/test/data"), "dfs/");
- conf.set(DFSConfigKeys.DFS_NAMENODE_NAME_DIR_KEY,
- new File(base_dir, "name").getPath());
- conf.setBoolean(DFSConfigKeys.DFS_PERMISSIONS_ENABLED_KEY, false);
+ MiniDFSCluster cluster = null;
+ Configuration conf = new HdfsConfiguration();
if (compress) {
conf.setBoolean(DFSConfigKeys.DFS_IMAGE_COMPRESSION_CODEC_KEY, true);
}
- DFSTestUtil.formatNameNode(conf);
-
- // create an image
- LOG.info("Create an fsimage");
- NameNode namenode = new NameNode(conf);
- namenode.getNamesystem().mkdirs("/test",
- new PermissionStatus("hairong", null, FsPermission.getDefault()), true);
- assertTrue(namenode.getFileInfo("/test").isDir());
- namenode.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
- namenode.saveNamespace();
-
- FSImage image = namenode.getFSImage();
- image.loadFSImage();
-
- File versionFile = image.getStorage().getStorageDir(0).getVersionFile();
-
- RandomAccessFile file = new RandomAccessFile(versionFile, "rws");
- FileInputStream in = null;
- FileOutputStream out = null;
try {
- // read the property from version file
- in = new FileInputStream(file.getFD());
- file.seek(0);
- Properties props = new Properties();
- props.load(in);
-
- // get the MD5 property and change it
- String sMd5 = props.getProperty(NNStorage.MESSAGE_DIGEST_PROPERTY);
- MD5Hash md5 = new MD5Hash(sMd5);
- byte[] bytes = md5.getDigest();
- bytes[0] += 1;
- md5 = new MD5Hash(bytes);
- props.setProperty(NNStorage.MESSAGE_DIGEST_PROPERTY, md5.toString());
-
- // write the properties back to version file
- file.seek(0);
- out = new FileOutputStream(file.getFD());
- props.store(out, null);
- out.flush();
- file.setLength(out.getChannel().position());
-
- // now load the image again
- image.loadFSImage();
-
- fail("Expect to get a checksumerror");
- } catch(IOException e) {
- assertTrue(e.getMessage().contains("is corrupt"));
+ LOG.info("\n===========================================\n" +
+ "Starting empty cluster");
+
+ cluster = new MiniDFSCluster.Builder(conf)
+ .numDataNodes(0)
+ .format(true)
+ .build();
+ cluster.waitActive();
+
+ FileSystem fs = cluster.getFileSystem();
+ fs.mkdirs(new Path("/test"));
+
+ // Directory layout looks like:
+ // test/data/dfs/nameN/current/{fsimage,edits,...}
+ File nameDir = new File(cluster.getNameDirs(0).iterator().next().getPath());
+ File dfsDir = nameDir.getParentFile();
+ assertEquals(dfsDir.getName(), "dfs"); // make sure we got right dir
+
+ LOG.info("Shutting down cluster #1");
+ cluster.shutdown();
+ cluster = null;
+
+ // Corrupt the md5 file to all 0s
+ File imageFile = new File(nameDir, "current/" + NNStorage.getImageFileName(0));
+ MD5FileUtils.saveMD5File(imageFile, new MD5Hash(new byte[16]));
+
+ // Try to start a new cluster
+ LOG.info("\n===========================================\n" +
+ "Starting same cluster after simulated crash");
+ try {
+ cluster = new MiniDFSCluster.Builder(conf)
+ .numDataNodes(0)
+ .format(false)
+ .build();
+ fail("Should not have successfully started with corrupt image");
+ } catch (IOException ioe) {
+ if (!ioe.getCause().getMessage().contains("is corrupt with MD5")) {
+ throw ioe;
+ }
+ }
} finally {
- IOUtils.closeStream(in);
- IOUtils.closeStream(out);
- namenode.stop();
- namenode.join();
+ if (cluster != null) {
+ cluster.shutdown();
+ }
}
}
Modified: hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartupOptionUpgrade.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartupOptionUpgrade.java?rev=1152295&r1=1152294&r2=1152295&view=diff
==============================================================================
--- hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartupOptionUpgrade.java (original)
+++ hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStartupOptionUpgrade.java Fri Jul 29 16:28:45 2011
@@ -17,6 +17,8 @@
*/
package org.apache.hadoop.hdfs.server.namenode;
+import java.net.URI;
+import java.util.Collections;
import junit.framework.Assert;
import org.apache.hadoop.conf.Configuration;
@@ -43,7 +45,9 @@ public class TestStartupOptionUpgrade {
conf = new HdfsConfiguration();
startOpt = StartupOption.UPGRADE;
startOpt.setClusterId(null);
- storage = new NNStorage(conf);
+ storage = new NNStorage(conf,
+ Collections.<URI>emptyList(),
+ Collections.<URI>emptyList());
}
@After
@@ -136,4 +140,4 @@ public class TestStartupOptionUpgrade {
Assert.assertEquals("Clusterid should match with the existing one",
"currentcid", storage.getClusterID());
}
-}
\ No newline at end of file
+}
Modified: hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStorageRestore.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStorageRestore.java?rev=1152295&r1=1152294&r2=1152295&view=diff
==============================================================================
--- hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStorageRestore.java (original)
+++ hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestStorageRestore.java Fri Jul 29 16:28:45 2011
@@ -22,38 +22,38 @@ import static org.junit.Assert.assertEqu
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import java.io.DataInputStream;
-import java.io.EOFException;
import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.math.BigInteger;
-import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Iterator;
-import java.util.Random;
import java.util.Set;
+import static org.mockito.Matchers.anyByte;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.spy;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.cli.CLITestCmdDFS;
import org.apache.hadoop.cli.util.CLICommandDFSAdmin;
import org.apache.hadoop.cli.util.CommandExecutor;
import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.DFSConfigKeys;
import org.apache.hadoop.hdfs.HdfsConfiguration;
import org.apache.hadoop.hdfs.MiniDFSCluster;
-import org.apache.hadoop.hdfs.server.common.Storage;
import org.apache.hadoop.hdfs.server.common.Storage.StorageDirectory;
-import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeDirType;
-import org.apache.hadoop.hdfs.server.namenode.NNStorage.NameNodeFile;
-import org.junit.After;
+import org.apache.hadoop.io.Writable;
+
+import static org.apache.hadoop.hdfs.server.namenode.NNStorage.getInProgressEditsFileName;
+import static org.apache.hadoop.hdfs.server.namenode.NNStorage.getFinalizedEditsFileName;
+import static org.apache.hadoop.hdfs.server.namenode.NNStorage.getImageFileName;
+
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mockito;
import com.google.common.collect.ImmutableSet;
/**
@@ -71,20 +71,7 @@ public class TestStorageRestore {
static final int blockSize = 4096;
static final int fileSize = 8192;
private File path1, path2, path3;
- private MiniDFSCluster cluster;
-
- private void writeFile(FileSystem fileSys, Path name, int repl)
- throws IOException {
- FSDataOutputStream stm = fileSys.create(name, true,
- fileSys.getConf().getInt("io.file.buffer.size", 4096),
- (short)repl, (long)blockSize);
- byte[] buffer = new byte[fileSize];
- Random rand = new Random(seed);
- rand.nextBytes(buffer);
- stm.write(buffer);
- stm.close();
- }
-
+ private MiniDFSCluster cluster;
@Before
public void setUpNameDirs() throws Exception {
config = new HdfsConfiguration();
@@ -119,19 +106,9 @@ public class TestStorageRestore {
// set the restore feature on
config.setBoolean(DFSConfigKeys.DFS_NAMENODE_NAME_DIR_RESTORE_KEY, true);
}
-
- /**
- * clean up
- */
- @After
- public void cleanUpNameDirs() throws Exception {
- if (hdfsDir.exists() && !FileUtil.fullyDelete(hdfsDir) ) {
- throw new IOException("Could not delete hdfs directory in tearDown '" + hdfsDir + "'");
- }
- }
/**
- * invalidate storage by removing storage directories
+ * invalidate storage by removing the second and third storage directories
*/
public void invalidateStorage(FSImage fi, Set<File> filesToInvalidate) throws IOException {
ArrayList<StorageDirectory> al = new ArrayList<StorageDirectory>(2);
@@ -145,6 +122,19 @@ public class TestStorageRestore {
}
// simulate an error
fi.getStorage().reportErrorsOnDirectories(al);
+
+ for (FSEditLog.JournalAndStream j : fi.getEditLog().getJournals()) {
+ if (j.getManager() instanceof FileJournalManager) {
+ FileJournalManager fm = (FileJournalManager)j.getManager();
+ if (fm.getStorageDirectory().getRoot().equals(path2)
+ || fm.getStorageDirectory().getRoot().equals(path3)) {
+ EditLogOutputStream mockStream = spy(j.getCurrentStream());
+ j.setCurrentStreamForTests(mockStream);
+ doThrow(new IOException("Injected fault: write")).
+ when(mockStream).write(Mockito.<FSEditLogOp>anyObject());
+ }
+ }
+ }
}
/**
@@ -154,130 +144,14 @@ public class TestStorageRestore {
LOG.info("current storages and corresponding sizes:");
for(Iterator<StorageDirectory> it = fs.getStorage().dirIterator(); it.hasNext(); ) {
StorageDirectory sd = it.next();
-
- if(sd.getStorageDirType().isOfType(NameNodeDirType.IMAGE)) {
- File imf = NNStorage.getStorageFile(sd, NameNodeFile.IMAGE);
- LOG.info(" image file " + imf.getAbsolutePath() + "; len = " + imf.length());
- }
- if(sd.getStorageDirType().isOfType(NameNodeDirType.EDITS)) {
- File edf = NNStorage.getStorageFile(sd, NameNodeFile.EDITS);
- LOG.info(" edits file " + edf.getAbsolutePath() + "; len = " + edf.length());
- }
- }
- }
-
-
- /**
- * This function returns a md5 hash of a file.
- *
- * @param file input file
- * @return The md5 string
- */
- public String getFileMD5(File file) throws Exception {
- String res = new String();
- MessageDigest mD = MessageDigest.getInstance("MD5");
- DataInputStream dis = new DataInputStream(new FileInputStream(file));
-
- try {
- while(true) {
- mD.update(dis.readByte());
- }
- } catch (EOFException eof) {}
- BigInteger bigInt = new BigInteger(1, mD.digest());
- res = bigInt.toString(16);
- dis.close();
-
- return res;
- }
-
-
- /**
- * read currentCheckpointTime directly from the file
- * @param currDir
- * @return the checkpoint time
- * @throws IOException
- */
- long readCheckpointTime(File currDir) throws IOException {
- File timeFile = new File(currDir, NameNodeFile.TIME.getName());
- long timeStamp = 0L;
- if (timeFile.exists() && timeFile.canRead()) {
- DataInputStream in = new DataInputStream(new FileInputStream(timeFile));
- try {
- timeStamp = in.readLong();
- } finally {
- in.close();
+ File curDir = sd.getCurrentDir();
+ for (File f : curDir.listFiles()) {
+ LOG.info(" file " + f.getAbsolutePath() + "; len = " + f.length());
}
}
- return timeStamp;
}
-
- /**
- * check if files exist/not exist
- * @throws IOException
- */
- public void checkFiles(boolean valid) throws IOException {
- //look at the valid storage
- File fsImg1 = new File(path1, Storage.STORAGE_DIR_CURRENT + "/" + NameNodeFile.IMAGE.getName());
- File fsImg2 = new File(path2, Storage.STORAGE_DIR_CURRENT + "/" + NameNodeFile.IMAGE.getName());
- File fsImg3 = new File(path3, Storage.STORAGE_DIR_CURRENT + "/" + NameNodeFile.IMAGE.getName());
-
- File fsEdits1 = new File(path1, Storage.STORAGE_DIR_CURRENT + "/" + NameNodeFile.EDITS.getName());
- File fsEdits2 = new File(path2, Storage.STORAGE_DIR_CURRENT + "/" + NameNodeFile.EDITS.getName());
- File fsEdits3 = new File(path3, Storage.STORAGE_DIR_CURRENT + "/" + NameNodeFile.EDITS.getName());
-
- long chkPt1 = readCheckpointTime(new File(path1, Storage.STORAGE_DIR_CURRENT));
- long chkPt2 = readCheckpointTime(new File(path2, Storage.STORAGE_DIR_CURRENT));
- long chkPt3 = readCheckpointTime(new File(path3, Storage.STORAGE_DIR_CURRENT));
-
- String md5_1 = null,md5_2 = null,md5_3 = null;
- try {
- md5_1 = getFileMD5(fsEdits1);
- md5_2 = getFileMD5(fsEdits2);
- md5_3 = getFileMD5(fsEdits3);
- } catch (Exception e) {
- System.err.println("md 5 calculation failed:" + e.getLocalizedMessage());
- }
- this.printStorages(cluster.getNameNode().getFSImage());
-
- LOG.info("++++ image files = "+fsImg1.getAbsolutePath() + "," + fsImg2.getAbsolutePath() + ","+ fsImg3.getAbsolutePath());
- LOG.info("++++ edits files = "+fsEdits1.getAbsolutePath() + "," + fsEdits2.getAbsolutePath() + ","+ fsEdits3.getAbsolutePath());
- LOG.info("checkFiles compares lengths: img1=" + fsImg1.length() + ",img2=" + fsImg2.length() + ",img3=" + fsImg3.length());
- LOG.info("checkFiles compares lengths: edits1=" + fsEdits1.length() + ",edits2=" + fsEdits2.length() + ",edits3=" + fsEdits3.length());
- LOG.info("checkFiles compares chkPts: name1=" + chkPt1 + ",name2=" + chkPt2 + ",name3=" + chkPt3);
- LOG.info("checkFiles compares md5s: " + fsEdits1.getAbsolutePath() +
- "="+ md5_1 + "," + fsEdits2.getAbsolutePath() + "=" + md5_2 + "," +
- fsEdits3.getAbsolutePath() + "=" + md5_3);
-
- if(valid) {
- // should be the same
- assertTrue(fsImg1.length() == fsImg2.length());
- assertTrue(0 == fsImg3.length()); //shouldn't be created
- assertTrue(fsEdits1.length() == fsEdits2.length());
- assertTrue(fsEdits1.length() == fsEdits3.length());
- assertTrue(md5_1.equals(md5_2));
- assertTrue(md5_1.equals(md5_3));
-
- // checkpoint times
- assertTrue(chkPt1 == chkPt2);
- assertTrue(chkPt1 == chkPt3);
- } else {
- // should be different
- //assertTrue(fsImg1.length() != fsImg2.length());
- //assertTrue(fsImg1.length() != fsImg3.length());
- assertTrue("edits1 = edits2", fsEdits1.length() != fsEdits2.length());
- assertTrue("edits1 = edits3", fsEdits1.length() != fsEdits3.length());
-
- assertTrue(!md5_1.equals(md5_2));
- assertTrue(!md5_1.equals(md5_3));
-
-
- // checkpoint times
- assertTrue(chkPt1 > chkPt2);
- assertTrue(chkPt1 > chkPt3);
- }
- }
-
+
/**
* test
* 1. create DFS cluster with 3 storage directories - 2 EDITS_IMAGE, 1 EDITS
@@ -293,7 +167,7 @@ public class TestStorageRestore {
@SuppressWarnings("deprecation")
@Test
public void testStorageRestore() throws Exception {
- int numDatanodes = 2;
+ int numDatanodes = 0;
cluster = new MiniDFSCluster.Builder(config).numDataNodes(numDatanodes)
.manageNameDfsDirs(false)
.build();
@@ -305,36 +179,88 @@ public class TestStorageRestore {
FileSystem fs = cluster.getFileSystem();
Path path = new Path("/", "test");
- writeFile(fs, path, 2);
+ assertTrue(fs.mkdirs(path));
- System.out.println("****testStorageRestore: file test written, invalidating storage...");
+ System.out.println("****testStorageRestore: dir 'test' created, invalidating storage...");
invalidateStorage(cluster.getNameNode().getFSImage(), ImmutableSet.of(path2, path3));
- //secondary.doCheckpoint(); // this will cause storages to be removed.
printStorages(cluster.getNameNode().getFSImage());
- System.out.println("****testStorageRestore: storage invalidated + doCheckpoint");
+ System.out.println("****testStorageRestore: storage invalidated");
path = new Path("/", "test1");
- writeFile(fs, path, 2);
- System.out.println("****testStorageRestore: file test1 written");
-
- checkFiles(false); // SHOULD BE FALSE
-
+ assertTrue(fs.mkdirs(path));
+
+ System.out.println("****testStorageRestore: dir 'test1' created");
+
+ // We did another edit, so the still-active directory at 'path1'
+ // should now differ from the others
+ FSImageTestUtil.assertFileContentsDifferent(2,
+ new File(path1, "current/" + getInProgressEditsFileName(1)),
+ new File(path2, "current/" + getInProgressEditsFileName(1)),
+ new File(path3, "current/" + getInProgressEditsFileName(1)));
+ FSImageTestUtil.assertFileContentsSame(
+ new File(path2, "current/" + getInProgressEditsFileName(1)),
+ new File(path3, "current/" + getInProgressEditsFileName(1)));
+
System.out.println("****testStorageRestore: checkfiles(false) run");
secondary.doCheckpoint(); ///should enable storage..
- checkFiles(true);
- System.out.println("****testStorageRestore: second Checkpoint done and checkFiles(true) run");
+ // We should have a checkpoint through txid 4 in the two image dirs
+ // (txid=4 for BEGIN, mkdir, mkdir, END)
+ FSImageTestUtil.assertFileContentsSame(
+ new File(path1, "current/" + getImageFileName(4)),
+ new File(path2, "current/" + getImageFileName(4)));
+ assertFalse("Should not have any image in an edits-only directory",
+ new File(path3, "current/" + getImageFileName(4)).exists());
+
+ // Should have finalized logs in the directory that didn't fail
+ assertTrue("Should have finalized logs in the directory that didn't fail",
+ new File(path1, "current/" + getFinalizedEditsFileName(1,4)).exists());
+ // Should not have finalized logs in the failed directories
+ assertFalse("Should not have finalized logs in the failed directories",
+ new File(path2, "current/" + getFinalizedEditsFileName(1,4)).exists());
+ assertFalse("Should not have finalized logs in the failed directories",
+ new File(path3, "current/" + getFinalizedEditsFileName(1,4)).exists());
+
+ // The new log segment should be in all of the directories.
+ FSImageTestUtil.assertFileContentsSame(
+ new File(path1, "current/" + getInProgressEditsFileName(5)),
+ new File(path2, "current/" + getInProgressEditsFileName(5)),
+ new File(path3, "current/" + getInProgressEditsFileName(5)));
+ String md5BeforeEdit = FSImageTestUtil.getFileMD5(
+ new File(path1, "current/" + getInProgressEditsFileName(5)));
+
+ // The original image should still be the previously failed image
+ // directory after it got restored, since it's still useful for
+ // a recovery!
+ FSImageTestUtil.assertFileContentsSame(
+ new File(path1, "current/" + getImageFileName(0)),
+ new File(path2, "current/" + getImageFileName(0)));
- // verify that all the logs are active
+ // Do another edit to verify that all the logs are active.
path = new Path("/", "test2");
- writeFile(fs, path, 2);
- System.out.println("****testStorageRestore: wrote a file and checkFiles(true) run");
- checkFiles(true);
-
+ assertTrue(fs.mkdirs(path));
+
+ // Logs should be changed by the edit.
+ String md5AfterEdit = FSImageTestUtil.getFileMD5(
+ new File(path1, "current/" + getInProgressEditsFileName(5)));
+ assertFalse(md5BeforeEdit.equals(md5AfterEdit));
+
+ // And all logs should be changed.
+ FSImageTestUtil.assertFileContentsSame(
+ new File(path1, "current/" + getInProgressEditsFileName(5)),
+ new File(path2, "current/" + getInProgressEditsFileName(5)),
+ new File(path3, "current/" + getInProgressEditsFileName(5)));
+
secondary.shutdown();
cluster.shutdown();
+
+ // All logs should be finalized by clean shutdown
+ FSImageTestUtil.assertFileContentsSame(
+ new File(path1, "current/" + getFinalizedEditsFileName(5,7)),
+ new File(path2, "current/" + getFinalizedEditsFileName(5,7)),
+ new File(path3, "current/" + getFinalizedEditsFileName(5,7)));
}
/**
@@ -412,7 +338,7 @@ public class TestStorageRestore {
FileSystem fs = cluster.getFileSystem();
Path testPath = new Path("/", "test");
- writeFile(fs, testPath, 2);
+ assertTrue(fs.mkdirs(testPath));
printStorages(fsImage);
Modified: hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestTransferFsImage.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestTransferFsImage.java?rev=1152295&r1=1152294&r2=1152295&view=diff
==============================================================================
--- hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestTransferFsImage.java (original)
+++ hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/server/namenode/TestTransferFsImage.java Fri Jul 29 16:28:45 2011
@@ -20,42 +20,80 @@ package org.apache.hadoop.hdfs.server.na
import static org.junit.Assert.*;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdfs.HdfsConfiguration;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.util.StringUtils;
import org.junit.Test;
+import org.mockito.Mockito;
+
+import com.google.common.collect.ImmutableList;
+
public class TestTransferFsImage {
+ private static final File TEST_DIR = new File(
+ System.getProperty("test.build.data","build/test/data"));
+
/**
* Regression test for HDFS-1997. Test that, if an exception
- * occurs on the client side, it is properly reported as such
+ * occurs on the client side, it is properly reported as such,
+ * and reported to the associated NNStorage object.
*/
@Test
public void testClientSideException() throws IOException {
-
Configuration conf = new HdfsConfiguration();
MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf)
.numDataNodes(0).build();
+ NNStorage mockStorage = Mockito.mock(NNStorage.class);
+ List<File> localPath = Collections.<File>singletonList(
+ new File("/xxxxx-does-not-exist/blah"));
+
try {
-
String fsName = NameNode.getHostPortString(
cluster.getNameNode().getHttpAddress());
- String id = "getimage=1";
+ String id = "getimage=1&txid=0";
- File[] localPath = new File[] {
- new File("/xxxxx-does-not-exist/blah")
- };
-
- TransferFsImage.getFileClient(fsName, id, localPath, false);
+ TransferFsImage.getFileClient(fsName, id, localPath, mockStorage, false);
fail("Didn't get an exception!");
} catch (IOException ioe) {
- assertTrue("Expected FNFE, got: " + StringUtils.stringifyException(ioe),
- ioe instanceof FileNotFoundException);
+ Mockito.verify(mockStorage).reportErrorOnFile(localPath.get(0));
+ assertTrue(
+ "Unexpected exception: " + StringUtils.stringifyException(ioe),
+ ioe.getMessage().contains("Unable to download to any storage"));
+ } finally {
+ cluster.shutdown();
+ }
+ }
+
+ /**
+ * Similar to the above test, except that there are multiple local files
+ * and one of them can be saved.
+ */
+ @Test
+ public void testClientSideExceptionOnJustOneDir() throws IOException {
+ Configuration conf = new HdfsConfiguration();
+ MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf)
+ .numDataNodes(0).build();
+ NNStorage mockStorage = Mockito.mock(NNStorage.class);
+ List<File> localPaths = ImmutableList.of(
+ new File("/xxxxx-does-not-exist/blah"),
+ new File(TEST_DIR, "testfile")
+ );
+
+ try {
+ String fsName = NameNode.getHostPortString(
+ cluster.getNameNode().getHttpAddress());
+ String id = "getimage=1&txid=0";
+
+ TransferFsImage.getFileClient(fsName, id, localPaths, mockStorage, false);
+ Mockito.verify(mockStorage).reportErrorOnFile(localPaths.get(0));
+ assertTrue("The valid local file should get saved properly",
+ localPaths.get(1).length() > 0);
} finally {
cluster.shutdown();
}
Modified: hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/tools/offlineEditsViewer/TestOfflineEditsViewer.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/tools/offlineEditsViewer/TestOfflineEditsViewer.java?rev=1152295&r1=1152294&r2=1152295&view=diff
==============================================================================
--- hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/tools/offlineEditsViewer/TestOfflineEditsViewer.java (original)
+++ hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/tools/offlineEditsViewer/TestOfflineEditsViewer.java Fri Jul 29 16:28:45 2011
@@ -20,8 +20,6 @@ package org.apache.hadoop.hdfs.tools.off
import java.io.IOException;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.DataInputStream;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.HashMap;
@@ -32,15 +30,11 @@ import static org.junit.Assert.assertTru
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes;
import org.apache.hadoop.hdfs.tools.offlineEditsViewer.OfflineEditsViewer;
import org.apache.hadoop.hdfs.tools.offlineEditsViewer.TokenizerFactory;
import org.apache.hadoop.hdfs.tools.offlineEditsViewer.EditsVisitorFactory;
-import org.apache.hadoop.hdfs.tools.offlineEditsViewer.EditsVisitor;
-import org.apache.hadoop.hdfs.tools.offlineEditsViewer.XmlEditsVisitor;
-import org.apache.hadoop.hdfs.tools.offlineEditsViewer.BinaryEditsVisitor;
import org.apache.hadoop.hdfs.DFSTestUtil;
import org.apache.hadoop.hdfs.server.namenode.OfflineEditsViewerHelper;
@@ -58,7 +52,7 @@ public class TestOfflineEditsViewer {
System.getProperty("test.build.data", "build/test/data");
private static String cacheDir =
- System.getProperty("test.cache.data", "build/test/data/cache");
+ System.getProperty("test.cache.data", "build/test/cache");
// to create edits and get edits filename
private static final OfflineEditsViewerHelper nnHelper
@@ -81,11 +75,13 @@ public class TestOfflineEditsViewer {
obsoleteOpCodes.put(FSEditLogOpCodes.OP_DATANODE_REMOVE, true);
obsoleteOpCodes.put(FSEditLogOpCodes.OP_SET_NS_QUOTA, true);
obsoleteOpCodes.put(FSEditLogOpCodes.OP_CLEAR_NS_QUOTA, true);
- // these are not written to files
- obsoleteOpCodes.put(FSEditLogOpCodes.OP_JSPOOL_START, true);
- obsoleteOpCodes.put(FSEditLogOpCodes.OP_CHECKPOINT_TIME, true);
}
+ @Before
+ public void setup() {
+ new File(cacheDir).mkdirs();
+ }
+
/**
* Test the OfflineEditsViewer
*/
Modified: hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/tools/offlineEditsViewer/editsStored
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hdfs/src/test/hdfs/org/apache/hadoop/hdfs/tools/offlineEditsViewer/editsStored?rev=1152295&r1=1152294&r2=1152295&view=diff
==============================================================================
Binary files - no diff available.