blob: 6fdf1ac9f32dff865cb00bf93a8cf2ae9a8ac6a3 [file] [log] [blame]
/**
* 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;
import java.io.File;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.protocol.HdfsConstants.RollingUpgradeAction;
import org.apache.hadoop.hdfs.protocol.HdfsConstants.SafeModeAction;
import org.apache.hadoop.hdfs.protocol.RollingUpgradeInfo;
import org.apache.hadoop.hdfs.qjournal.MiniJournalCluster;
import org.apache.hadoop.hdfs.qjournal.MiniQJMHACluster;
import org.apache.hadoop.hdfs.server.namenode.INode;
import org.apache.hadoop.hdfs.server.namenode.NNStorage;
import org.apache.hadoop.hdfs.server.namenode.NameNode;
import org.apache.hadoop.hdfs.tools.DFSAdmin;
import org.junit.Assert;
import org.junit.Test;
/**
* This class tests rollback for rolling upgrade.
*/
public class TestRollingUpgradeRollback {
private static final int NUM_JOURNAL_NODES = 3;
private static final String JOURNAL_ID = "myjournal";
private static boolean fileExists(List<File> files) {
for (File file : files) {
if (file.exists()) {
return true;
}
}
return false;
}
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 checkJNStorage(File dir, long discardStartTxId,
long discardEndTxId) {
File finalizedEdits = new File(dir, NNStorage.getFinalizedEditsFileName(1,
discardStartTxId - 1));
Assert.assertTrue(finalizedEdits.exists());
File trashEdits = new File(dir, NNStorage.getFinalizedEditsFileName(
discardStartTxId, discardEndTxId) + ".trash");
Assert.assertTrue(trashEdits.exists());
}
@Test
public void testRollbackCommand() throws Exception {
final Configuration conf = new HdfsConfiguration();
MiniDFSCluster cluster = null;
final Path foo = new Path("/foo");
final Path bar = new Path("/bar");
try {
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(0).build();
cluster.waitActive();
final DistributedFileSystem dfs = cluster.getFileSystem();
final DFSAdmin dfsadmin = new DFSAdmin(conf);
dfs.mkdirs(foo);
// start rolling upgrade
dfs.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
Assert.assertEquals(0,
dfsadmin.run(new String[] { "-rollingUpgrade", "prepare" }));
dfs.setSafeMode(SafeModeAction.SAFEMODE_LEAVE);
// create new directory
dfs.mkdirs(bar);
// check NNStorage
NNStorage storage = cluster.getNamesystem().getFSImage().getStorage();
checkNNStorage(storage, 3, -1); // (startSegment, mkdir, endSegment)
} finally {
if (cluster != null) {
cluster.shutdown();
}
}
NameNode nn = null;
try {
nn = NameNode.createNameNode(new String[] { "-rollingUpgrade",
"rollback" }, conf);
// make sure /foo is still there, but /bar is not
INode fooNode = nn.getNamesystem().getFSDirectory()
.getINode4Write(foo.toString());
Assert.assertNotNull(fooNode);
INode barNode = nn.getNamesystem().getFSDirectory()
.getINode4Write(bar.toString());
Assert.assertNull(barNode);
// check the details of NNStorage
NNStorage storage = nn.getNamesystem().getFSImage().getStorage();
// (startSegment, upgrade marker, mkdir, endSegment)
checkNNStorage(storage, 3, 7);
} finally {
if (nn != null) {
nn.stop();
nn.join();
}
}
}
@Test
public void testRollbackWithQJM() throws Exception {
final Configuration conf = new HdfsConfiguration();
MiniJournalCluster mjc = null;
MiniDFSCluster cluster = null;
final Path foo = new Path("/foo");
final Path bar = new Path("/bar");
try {
mjc = new MiniJournalCluster.Builder(conf).numJournalNodes(
NUM_JOURNAL_NODES).build();
mjc.waitActive();
conf.set(DFSConfigKeys.DFS_NAMENODE_EDITS_DIR_KEY, mjc
.getQuorumJournalURI(JOURNAL_ID).toString());
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(0).build();
cluster.waitActive();
DistributedFileSystem dfs = cluster.getFileSystem();
final DFSAdmin dfsadmin = new DFSAdmin(conf);
dfs.mkdirs(foo);
// start rolling upgrade
dfs.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
Assert.assertEquals(0,
dfsadmin.run(new String[] { "-rollingUpgrade", "prepare" }));
dfs.setSafeMode(SafeModeAction.SAFEMODE_LEAVE);
// create new directory
dfs.mkdirs(bar);
dfs.close();
// rollback
cluster.restartNameNode("-rollingUpgrade", "rollback");
// make sure /foo is still there, but /bar is not
dfs = cluster.getFileSystem();
Assert.assertTrue(dfs.exists(foo));
Assert.assertFalse(dfs.exists(bar));
// check storage in JNs
for (int i = 0; i < NUM_JOURNAL_NODES; i++) {
File dir = mjc.getCurrentDir(0, JOURNAL_ID);
// segments:(startSegment, mkdir, endSegment), (startSegment, upgrade
// marker, mkdir, endSegment)
checkJNStorage(dir, 4, 7);
}
} finally {
if (cluster != null) {
cluster.shutdown();
}
if (mjc != null) {
mjc.shutdown();
}
}
}
/**
* Test rollback scenarios where StandbyNameNode does checkpoints during
* rolling upgrade.
*/
@Test
public void testRollbackWithHAQJM() throws Exception {
final Configuration conf = new HdfsConfiguration();
MiniQJMHACluster cluster = null;
final Path foo = new Path("/foo");
final Path bar = new Path("/bar");
try {
cluster = new MiniQJMHACluster.Builder(conf).build();
MiniDFSCluster dfsCluster = cluster.getDfsCluster();
dfsCluster.waitActive();
// let NN1 tail editlog every 1s
dfsCluster.getConfiguration(1).setInt(
DFSConfigKeys.DFS_HA_TAILEDITS_PERIOD_KEY, 1);
dfsCluster.restartNameNode(1);
dfsCluster.transitionToActive(0);
DistributedFileSystem dfs = dfsCluster.getFileSystem(0);
dfs.mkdirs(foo);
// start rolling upgrade
RollingUpgradeInfo info = dfs.rollingUpgrade(RollingUpgradeAction.PREPARE);
Assert.assertTrue(info.isStarted());
// create new directory
dfs.mkdirs(bar);
dfs.close();
TestRollingUpgrade.queryForPreparation(dfs);
// If the query returns true, both active and the standby NN should have
// rollback fsimage ready.
Assert.assertTrue(dfsCluster.getNameNode(0).getFSImage()
.hasRollbackFSImage());
Assert.assertTrue(dfsCluster.getNameNode(1).getFSImage()
.hasRollbackFSImage());
// rollback NN0
dfsCluster.restartNameNode(0, true, "-rollingUpgrade",
"rollback");
// shutdown NN1
dfsCluster.shutdownNameNode(1);
dfsCluster.transitionToActive(0);
// make sure /foo is still there, but /bar is not
dfs = dfsCluster.getFileSystem(0);
Assert.assertTrue(dfs.exists(foo));
Assert.assertFalse(dfs.exists(bar));
// check the details of NNStorage
NNStorage storage = dfsCluster.getNamesystem(0).getFSImage()
.getStorage();
// segments:(startSegment, mkdir, start upgrade endSegment),
// (startSegment, mkdir, endSegment)
checkNNStorage(storage, 4, 7);
// check storage in JNs
for (int i = 0; i < NUM_JOURNAL_NODES; i++) {
File dir = cluster.getJournalCluster().getCurrentDir(0,
MiniQJMHACluster.NAMESERVICE);
checkJNStorage(dir, 5, 7);
}
// restart NN0 again to make sure we can start using the new fsimage and
// the corresponding md5 checksum
dfsCluster.restartNameNode(0);
// start the rolling upgrade again to make sure we do not load upgrade
// status after the rollback
dfsCluster.transitionToActive(0);
dfs.rollingUpgrade(RollingUpgradeAction.PREPARE);
} finally {
if (cluster != null) {
cluster.shutdown();
}
}
}
// TODO: rollback could not succeed in all JN
}