/**
* 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 static org.junit.Assert.*;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
public class TestNNStorageFailures {
public static final Log LOG = LogFactory.getLog(TestNNStorageFailures.class);
private int editsPerformed = 0;
private MiniDFSCluster cluster;
private FileSystem fs;
@Before
public void setUpMiniCluster() throws IOException {
Configuration conf = new Configuration();
File baseDir = MiniDFSCluster.getBaseDirectory(conf);
File editDir1 = new File(baseDir, "edit1");
File editDir2 = new File(baseDir, "edit2");
conf.set("dfs.name.edits.dir",
editDir1.getPath() + "," + editDir2.getPath());
cluster = new MiniDFSCluster(conf, 0, true, null);
cluster.waitActive();
fs = cluster.getFileSystem();
}
@After
public void shutDownMiniCluster() throws IOException {
if (fs != null)
fs.close();
if (cluster != null)
cluster.shutdown();
}
/**
* Do a mutative metadata operation on the file system.
*
* @return true if the operation was successful, false otherwise.
*/
private boolean doAnEdit() throws IOException {
return fs.mkdirs(new Path("/tmp", Integer.toString(editsPerformed++)));
}
// check if exception is thrown when all image dirs fail
@Test
public void testAllImageDirsFailOnRoll() throws IOException {
assertTrue(doAnEdit());
Collection<File> namedirs = cluster.getNameDirs();
for (File f : namedirs) {
LOG.info("Changing permissions for directory " + f);
f.setExecutable(false);
}
try {
cluster.getNameNode().getNamesystem().rollEditLog();
fail("Should get an exception here");
} catch (IOException e) {
LOG.info(e);
assertTrue(e.toString()
.contains("No image locations are available"));
// image dirs are not writable
assertEquals(2, NameNode.getNameNodeMetrics().imagesFailed.get());
// journals are separate, and accessible
assertEquals(0, NameNode.getNameNodeMetrics().journalsFailed.get());
} finally {
for (File f : namedirs) {
LOG.info("Changing permissions for directory " + f);
f.setExecutable(true);
}
}
}
// check if image directories are restored at two consecutive SN,
// when one fails
@Test
public void testImageDirsRemainValidOnInodeMismatch() throws IOException {
for (int i = 0; i < 10; i++) {
assertTrue(doAnEdit());
}
// replace root dir with a spy
FSDirectory spyDir = spy(cluster.getNameNode().getNamesystem().dir);
long originalCount = spyDir.totalInodes();
cluster.getNameNode().getNamesystem().dir = spyDir;
doReturn(new Long(originalCount + 1)).when(spyDir).totalInodes();
// save namespace should fail, but not evict image directories
try {
cluster.getNameNode().getNamesystem().saveNamespace(true, false);
fail("Should get an exception here");
} catch (IOException e) {
LOG.info(e);
}
doReturn(new Long(originalCount)).when(spyDir).totalInodes();
cluster.getNameNode().getNamesystem().saveNamespace(true, false);
assertTrue(cluster.getNameNode().getNamesystem().getFSImage().storage.removedStorageDirs
.isEmpty());
assertEquals(0, NameNode.getNameNodeMetrics().imagesFailed.get());
assertEquals(0, NameNode.getNameNodeMetrics().journalsFailed.get());
}
}