package org.apache.hadoop.hdfs;
import java.io.IOException;
import java.util.Random;
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.AvatarNode;
import org.apache.hadoop.hdfs.server.namenode.CheckpointSignature;
import org.apache.hadoop.hdfs.util.InjectionEvent;
import org.apache.hadoop.hdfs.util.InjectionHandler;
import org.apache.hadoop.fs.ChecksumException;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.junit.After;
import org.junit.AfterClass;
import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestAvatarIngesting {
final static Log LOG = LogFactory.getLog(TestAvatarCheckpointing.class);
private MiniAvatarCluster cluster;
private Configuration conf;
private FileSystem fs;
private Random random = new Random();
@BeforeClass
public static void setUpBeforeClass() throws Exception {
MiniAvatarCluster.createAndStartZooKeeper();
}
private void setUp(long ckptPeriod) throws Exception {
conf = new Configuration();
conf.setBoolean("fs.ha.retrywrites", true);
conf.setBoolean("fs.checkpoint.enabled", false);
conf.setLong("fs.checkpoint.period", 3600);
cluster = new MiniAvatarCluster(conf, 2, true, null, null);
fs = cluster.getFileSystem();
}
@After
public void tearDown() throws Exception {
fs.close();
cluster.shutDown();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
MiniAvatarCluster.shutDownZooKeeper();
}
public void createEdits(int nEdits) throws IOException {
for (int i = 0; i < nEdits / 2; i++) {
// Create file ends up logging two edits to the edit log, one for create
// file and one for bumping up the generation stamp
fs.create(new Path("/" + random.nextInt()));
}
}
public long getCurrentTxId(AvatarNode avatar) {
return avatar.getFSImage().getEditLog().getCurrentTxId();
}
// ////////////////////////////
private void testIngestFailure(InjectionEvent event)
throws Exception {
LOG.info("TEST Ingest Failure : " + event);
TestAvatarIngestingHandler h = new TestAvatarIngestingHandler(event);
InjectionHandler.set(h);
setUp(3); // simulate interruption, no ckpt failure
AvatarNode primary = cluster.getPrimaryAvatar(0).avatar;
AvatarNode standby = cluster.getStandbyAvatar(0).avatar;
h.setDisabled(false);
createEdits(20);
try {
Thread.sleep(10000);
} catch (Exception e) {
}
h.setDisabled(true);
standby.quiesceStandby(getCurrentTxId(primary) - 1);
assertEquals(20, getCurrentTxId(primary));
assertEquals(getCurrentTxId(primary), getCurrentTxId(standby));
tearDown();
}
/*
* Simulate exception when reading from edits
*/
@Test
public void testIngestFailure() throws Exception {
testIngestFailure(InjectionEvent.INGEST_READ_OP);
}
class TestAvatarIngestingHandler extends InjectionHandler {
private InjectionEvent synchronizationPoint;
int simulatedFailure = 0;
boolean disabled = true;
public TestAvatarIngestingHandler(InjectionEvent se) {
synchronizationPoint = se;
}
public void setDisabled(boolean v){
disabled = v;
}
@Override
protected void _processEventIO(InjectionEvent event, Object... args)
throws IOException {
if (synchronizationPoint == event) {
if(disabled)
return;
LOG.info("PROCESSING EVENT: " + synchronizationPoint + " counter: " + simulatedFailure);
simulatedFailure++;
if(event == InjectionEvent.INGEST_READ_OP && ((simulatedFailure % 3) == 1)){
LOG.info("Throwing checksum exception");
throw new ChecksumException("Testing checksum exception...", 0);
}
if(event == InjectionEvent.INGEST_READ_OP && ((simulatedFailure % 7) == 1)){
LOG.info("Throwing IO exception");
throw new IOException("Testing IO exception...");
}
}
}
}
}