/**
* 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.protocol.LocatedBlocks;
import org.apache.hadoop.hdfs.server.namenode.AvatarNode;
import org.apache.hadoop.hdfs.server.namenode.FinalizeCheckpointException;
import org.apache.hadoop.util.InjectionHandler;
import org.junit.Test;
public class TestAvatarCheckpointingQJM extends TestAvatarCheckpointing {
@Test
public void testMergeWithCheckPoint() throws Exception {
TestAvatarCheckpointingHandler h = new TestAvatarCheckpointingHandler(null, null, false);
InjectionHandler.set(h);
setUp("testMergeWithCheckPoint", true);
long blockSize = TestFileCreation.blockSize;
long fileLen = TestFileCreation.blockSize * numDataBlocks;
// Create files
Path root = new Path("/user/");
Path rsFile = new Path(root, "rsFile");
long rsCRC = DFSTestUtil.createFile(fs, rsFile, fileLen, (short)1, 1, null,
blockSize);
Path xorFile = new Path(root, "xorFile");
long xorCRC = DFSTestUtil.createFile(fs, xorFile, fileLen, (short)2, 2, null,
blockSize);
// Create parity files
Path parityRoot = new Path("/raid/user/");
Path parityRSFile = new Path(parityRoot, "rsFile");
DFSTestUtil.createFile(fs, parityRSFile, blockSize * numRSParityBlocks,
(short)1, 3, null, blockSize);
Path parityXORFile = new Path(parityRoot, "xorFile");
DFSTestUtil.createFile(fs, parityXORFile, blockSize, (short)2, 4, null,
blockSize);
int checksums[] = new int[numDataBlocks];
for (int i = 0 ;i < numDataBlocks; i++) {
checksums[i] = i+1;
}
FileStatus rsStat = fs.getFileStatus(rsFile);
FileStatus xorStat = fs.getFileStatus(xorFile);
LocatedBlocks rsLbs = dfs.getLocatedBlocks(rsFile, 0, fileLen);
LocatedBlocks xorLbs = dfs.getLocatedBlocks(xorFile, 0, fileLen);
fs.setTimes(parityRSFile, rsStat.getModificationTime(), 0);
fs.setTimes(parityXORFile, xorStat.getModificationTime(), 0);
LOG.info("Merge source files and parity files");
((DistributedFileSystem)fs).merge(parityRSFile, rsFile, "rs", checksums);
((DistributedFileSystem)fs).merge(parityXORFile, xorFile, "xor", checksums);
assertTrue("Parity file doesn't exist", !dfs.exists(parityRSFile));
assertTrue("Parity file doesn't exist", !dfs.exists(parityXORFile));
LOG.info("Verify merge");
FileStatus xorStatBeforeRestart =
TestMergeFile.verifyMergeFiles(dfs, xorStat, xorLbs, xorFile, fileLen, xorCRC);
FileStatus rsStatBeforeRestart =
TestMergeFile.verifyMergeFiles(dfs, rsStat, rsLbs, rsFile, fileLen, rsCRC);
LOG.info("NN checkpointing");
h.doCheckpoint();
// Restart the namenode
LOG.info("NN restarting");
cluster.restartAvatarNodes();
// Verify merge again
LOG.info("Verify merge after the NN restarts");
assertTrue("Parity file doesn't exist", !dfs.exists(parityRSFile));
assertTrue("Parity file doesn't exist", !dfs.exists(parityXORFile));
FileStatus xorStatAfterRestart =
TestMergeFile.verifyMergeFiles(dfs, xorStat, xorLbs, xorFile, fileLen, xorCRC);
FileStatus rsStatAfterRestart =
TestMergeFile.verifyMergeFiles(dfs, rsStat, rsLbs, rsFile, fileLen, rsCRC);
assertEquals("Restarting doesn't change modificaiton time",
xorStatBeforeRestart.getModificationTime(),
xorStatAfterRestart.getModificationTime());
assertEquals("Restarting doesn't chagne modification time",
rsStatBeforeRestart.getModificationTime(),
rsStatAfterRestart.getModificationTime());
}
@Test
public void testFailSuccFailQuiesce() throws Exception {
doTestFailSuccFailQuiesce(true);
}
@Test
public void testFailCheckpointOnceAndRestartStandby() throws Exception {
doTestFailCheckpointOnceAndRestartStandby(true);
}
@Test
public void testFailCheckpointMultiAndCrash() throws Exception {
LOG.info("TEST: ----> testFailCheckpointMultiAndCrash");
TestAvatarCheckpointingHandler h = new TestAvatarCheckpointingHandler(null,
null, true);
InjectionHandler.set(h);
setUp("testFailCheckpointMultiAndCrash", true);
createEdits(20);
AvatarNode primary = cluster.getPrimaryAvatar(0).avatar;
AvatarNode standby = cluster.getStandbyAvatar(0).avatar;
try {
h.failNextCheckpoint = true;
h.doCheckpoint();
fail("Should get IOException here");
} catch (IOException e) {
// checkpoint fails during finalization (see the checkpointing handler)
assertTrue(e instanceof FinalizeCheckpointException);
assertTrue(AvatarSetupUtil.isIngestAlive(standby));
LOG.info("Expected: Checkpoint failed", e);
}
// current txid should be 20 + SLS + ENS + SLS + initial ckpt
assertEquals(25, getCurrentTxId(primary));
try {
h.doCheckpoint();
fail("Should get IOException here");
} catch (IOException e) {
// checkpoint fails during finalization (see the checkpointing handler)
assertTrue(e instanceof FinalizeCheckpointException);
assertTrue(AvatarSetupUtil.isIngestAlive(standby));
LOG.info("Expected: Checkpoint failed", e);
}
// roll adds 2 transactions
assertEquals(27, getCurrentTxId(primary));
try {
h.doCheckpoint();
fail("Should get IOException here");
} catch (Exception e) {
// checkpoint fails during finalization (see the checkpointing handler)
assertTrue(e instanceof FinalizeCheckpointException);
assertTrue(AvatarSetupUtil.isIngestAlive(standby));
LOG.info("Expected: Checkpoint failed", e);
}
// roll adds 2 transactions
assertEquals(29, getCurrentTxId(primary));
}
@Test
public void testHardLinkWithCheckPoint() throws Exception {
TestAvatarCheckpointingHandler h = new TestAvatarCheckpointingHandler(null, null, false);
InjectionHandler.set(h);
setUp("testHardLinkWithCheckPoint", true);
// Create a new file
Path root = new Path("/user/");
Path file10 = new Path(root, "file1");
FSDataOutputStream stm1 = TestFileCreation.createFile(fs, file10, 1);
byte[] content = TestFileCreation.writeFile(stm1);
stm1.close();
LOG.info("Create the hardlinks");
Path file11 = new Path(root, "file-11");
Path file12 = new Path(root, "file-12");
fs.hardLink(file10, file11);
fs.hardLink(file11, file12);
LOG.info("Verify the hardlinks");
TestFileHardLink.verifyLinkedFileIdenticial(fs, cluster.getPrimaryAvatar(0).avatar,
fs.getFileStatus(file10), fs.getFileStatus(file11), content);
TestFileHardLink.verifyLinkedFileIdenticial(fs, cluster.getPrimaryAvatar(0).avatar,
fs.getFileStatus(file10), fs.getFileStatus(file12), content);
LOG.info("NN checkpointing");
h.doCheckpoint();
// Restart the namenode
LOG.info("NN restarting");
cluster.restartAvatarNodes();
// Verify the hardlinks again
LOG.info("Verify the hardlinks again after the NN restarts");
TestFileHardLink.verifyLinkedFileIdenticial(fs, cluster.getPrimaryAvatar(0).avatar,
fs.getFileStatus(file10), fs.getFileStatus(file11), content);
TestFileHardLink.verifyLinkedFileIdenticial(fs, cluster.getPrimaryAvatar(0).avatar,
fs.getFileStatus(file10), fs.getFileStatus(file12), content);
}
@Test
public void testFailCheckpointOnCorruptImage() throws Exception {
LOG.info("TEST: ----> testFailCheckpointOnCorruptImage");
TestAvatarCheckpointingHandler h = new TestAvatarCheckpointingHandler(
null, null, false);
InjectionHandler.set(h);
// first checkpoint will succeed (most recent ckptxid = 1)
setUp(3600, "testFailCheckpointOnCorruptImage", true, true);
// image will be corrupted for second - manual checkpoint
h.corruptImage = true;
createEdits(20);
AvatarNode primary = cluster.getPrimaryAvatar(0).avatar;
AvatarNode standby = cluster.getStandbyAvatar(0).avatar;
// do second checkpoint
try {
h.doCheckpoint();
fail("Should get IOException here");
} catch (IOException e) {
// checkpoint fails during finalizations (see the checkpointing handler)
assertTrue(e instanceof FinalizeCheckpointException);
assertTrue(AvatarSetupUtil.isIngestAlive(standby));
}
assertEquals(1, primary.getCheckpointSignature().getMostRecentCheckpointTxId());
}
@Test
public void testCheckpointReprocessEdits() throws Exception {
LOG.info("TEST: ----> testCheckpointReprocessEdits");
TestAvatarCheckpointingHandler h = new TestAvatarCheckpointingHandler(null,
null, false);
setUp("testCheckpointReprocessEdits", true);
createEdits(20);
AvatarNode primary = cluster.getPrimaryAvatar(0).avatar;
AvatarNode standby = cluster.getStandbyAvatar(0).avatar;
h.reprocessIngest = true;
// set the handler later no to interfere with the previous checkpoint
InjectionHandler.set(h);
// checkpoint should be ok
h.doCheckpoint();
assertEquals(23, primary.getCheckpointSignature()
.getMostRecentCheckpointTxId());
}
}