|
@@ -21,7 +21,9 @@ import java.io.DataOutputStream;
|
|
|
import java.io.File;
|
|
|
import java.io.FileOutputStream;
|
|
|
import java.io.IOException;
|
|
|
+import java.io.RandomAccessFile;
|
|
|
|
|
|
+import org.apache.hadoop.conf.Configuration;
|
|
|
import org.apache.hadoop.fs.StorageType;
|
|
|
import org.apache.hadoop.hdfs.HdfsConfiguration;
|
|
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
|
@@ -38,6 +40,7 @@ import org.apache.hadoop.hdfs.server.datanode.ReplicaInfo;
|
|
|
import org.apache.hadoop.hdfs.server.datanode.ReplicaNotFoundException;
|
|
|
import org.apache.hadoop.hdfs.server.datanode.ReplicaUnderRecovery;
|
|
|
import org.apache.hadoop.hdfs.server.datanode.ReplicaWaitingToBeRecovered;
|
|
|
+import org.apache.hadoop.test.GenericTestUtils;
|
|
|
import org.apache.hadoop.util.DataChecksum;
|
|
|
import org.apache.hadoop.util.DiskChecker.DiskOutOfSpaceException;
|
|
|
import org.junit.Assert;
|
|
@@ -158,7 +161,7 @@ public class TestWriteToReplica {
|
|
|
|
|
|
ExtendedBlock[] blocks = new ExtendedBlock[] {
|
|
|
new ExtendedBlock(bpid, 1, 1, 2001), new ExtendedBlock(bpid, 2, 1, 2002),
|
|
|
- new ExtendedBlock(bpid, 3, 1, 2003), new ExtendedBlock(bpid, 4, 1, 2004),
|
|
|
+ new ExtendedBlock(bpid, 3, 2, 2003), new ExtendedBlock(bpid, 4, 1, 2004),
|
|
|
new ExtendedBlock(bpid, 5, 1, 2005), new ExtendedBlock(bpid, 6, 1, 2006)
|
|
|
};
|
|
|
|
|
@@ -182,6 +185,12 @@ public class TestWriteToReplica {
|
|
|
replicasMap.add(bpid, replicaInfo);
|
|
|
replicaInfo.getBlockFile().createNewFile();
|
|
|
replicaInfo.getMetaFile().createNewFile();
|
|
|
+ try (RandomAccessFile blockRAF =
|
|
|
+ new RandomAccessFile(replicaInfo.getBlockFile(), "rw")) {
|
|
|
+ //extend blockFile
|
|
|
+ blockRAF.setLength(blocks[RBW].getNumBytes());
|
|
|
+ }
|
|
|
+ saveMetaFileHeader(replicaInfo.getMetaFile());
|
|
|
|
|
|
replicasMap.add(bpid, new ReplicaWaitingToBeRecovered(
|
|
|
blocks[RWR].getLocalBlock(), vol, vol.createRbwFile(bpid,
|
|
@@ -516,4 +525,49 @@ public class TestWriteToReplica {
|
|
|
+ "genstamp and replaced it with the newer one: " + blocks[NON_EXISTENT]);
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test that we can successfully recover a {@link ReplicaBeingWritten}
|
|
|
+ * which has inconsistent metadata (bytes were written to disk but bytesOnDisk
|
|
|
+ * was not updated) but that recovery fails when the block is actually
|
|
|
+ * corrupt (bytes are not present on disk).
|
|
|
+ */
|
|
|
+ @Test
|
|
|
+ public void testRecoverInconsistentRbw() throws IOException {
|
|
|
+ Configuration conf = new HdfsConfiguration();
|
|
|
+ MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf).build();
|
|
|
+ cluster.waitActive();
|
|
|
+ DataNode dn = cluster.getDataNodes().get(0);
|
|
|
+ FsDatasetImpl fsDataset = (FsDatasetImpl)DataNodeTestUtils.getFSDataset(dn);
|
|
|
+
|
|
|
+ // set up replicasMap
|
|
|
+ String bpid = cluster.getNamesystem().getBlockPoolId();
|
|
|
+ ExtendedBlock[] blocks = setup(bpid, fsDataset);
|
|
|
+
|
|
|
+ ReplicaBeingWritten rbw = (ReplicaBeingWritten)fsDataset.
|
|
|
+ getReplicaInfo(blocks[RBW]);
|
|
|
+ long bytesOnDisk = rbw.getBytesOnDisk();
|
|
|
+ // simulate an inconsistent replica length update by reducing in-memory
|
|
|
+ // value of on disk length
|
|
|
+ rbw.setLastChecksumAndDataLen(bytesOnDisk - 1, null);
|
|
|
+ fsDataset.recoverRbw(blocks[RBW], blocks[RBW].getGenerationStamp(), 0L,
|
|
|
+ rbw.getNumBytes());
|
|
|
+ // after the recovery, on disk length should equal acknowledged length.
|
|
|
+ Assert.assertTrue(rbw.getBytesOnDisk() == rbw.getBytesAcked());
|
|
|
+
|
|
|
+ // reduce on disk length again; this time actually truncate the file to
|
|
|
+ // simulate the data not being present
|
|
|
+ rbw.setLastChecksumAndDataLen(bytesOnDisk - 1, null);
|
|
|
+ try (RandomAccessFile blockRAF =
|
|
|
+ new RandomAccessFile(rbw.getBlockFile(), "rw")) {
|
|
|
+ // truncate blockFile
|
|
|
+ blockRAF.setLength(bytesOnDisk - 1);
|
|
|
+ fsDataset.recoverRbw(blocks[RBW], blocks[RBW].getGenerationStamp(), 0L,
|
|
|
+ rbw.getNumBytes());
|
|
|
+ Assert.fail("recovery should have failed");
|
|
|
+ } catch (ReplicaNotFoundException rnfe) {
|
|
|
+ GenericTestUtils.assertExceptionContains("Found fewer bytesOnDisk than " +
|
|
|
+ "bytesAcked for replica", rnfe);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|