HDFS-13468. Add erasure coding metrics into ReadStatistics. (Contributed by Lei (Eddy) Xu)
This commit is contained in:
parent
7ac0abdc13
commit
a8e428b2dc
|
@ -19,6 +19,7 @@ package org.apache.hadoop.hdfs;
|
|||
|
||||
import org.apache.hadoop.classification.InterfaceAudience;
|
||||
import org.apache.hadoop.fs.ReadOption;
|
||||
import org.apache.hadoop.hdfs.protocol.BlockType;
|
||||
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
|
||||
import org.apache.hadoop.hdfs.protocol.LocatedBlock;
|
||||
import org.apache.hadoop.hdfs.protocol.LocatedBlocks;
|
||||
|
@ -92,6 +93,7 @@ public class DFSStripedInputStream extends DFSInputStream {
|
|||
LocatedBlocks locatedBlocks) throws IOException {
|
||||
super(dfsClient, src, verifyChecksum, locatedBlocks);
|
||||
|
||||
this.readStatistics.setBlockType(BlockType.STRIPED);
|
||||
assert ecPolicy != null;
|
||||
this.ecPolicy = ecPolicy;
|
||||
this.cellSize = ecPolicy.getCellSize();
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
*/
|
||||
package org.apache.hadoop.hdfs;
|
||||
|
||||
import org.apache.hadoop.hdfs.protocol.BlockType;
|
||||
|
||||
/**
|
||||
* A utility class that maintains statistics for reading.
|
||||
*/
|
||||
|
@ -26,6 +28,9 @@ public class ReadStatistics {
|
|||
private long totalShortCircuitBytesRead;
|
||||
private long totalZeroCopyBytesRead;
|
||||
|
||||
private BlockType blockType = BlockType.CONTIGUOUS;
|
||||
private long totalEcDecodingTimeMillis;
|
||||
|
||||
public ReadStatistics() {
|
||||
clear();
|
||||
}
|
||||
|
@ -75,6 +80,21 @@ public class ReadStatistics {
|
|||
return totalBytesRead - totalLocalBytesRead;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return block type of the input stream. If block type != CONTIGUOUS,
|
||||
* it is reading erasure coded data.
|
||||
*/
|
||||
public synchronized BlockType getBlockType() {
|
||||
return blockType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total time in milliseconds used for erasure coding decoding.
|
||||
*/
|
||||
public synchronized long getTotalEcDecodingTimeMillis() {
|
||||
return totalEcDecodingTimeMillis;
|
||||
}
|
||||
|
||||
public synchronized void addRemoteBytes(long amt) {
|
||||
this.totalBytesRead += amt;
|
||||
}
|
||||
|
@ -97,10 +117,19 @@ public class ReadStatistics {
|
|||
this.totalZeroCopyBytesRead += amt;
|
||||
}
|
||||
|
||||
public synchronized void addErasureCodingDecodingTime(long millis) {
|
||||
this.totalEcDecodingTimeMillis += millis;
|
||||
}
|
||||
|
||||
synchronized void setBlockType(BlockType blockType) {
|
||||
this.blockType = blockType;
|
||||
}
|
||||
|
||||
public synchronized void clear() {
|
||||
this.totalBytesRead = 0;
|
||||
this.totalLocalBytesRead = 0;
|
||||
this.totalShortCircuitBytesRead = 0;
|
||||
this.totalZeroCopyBytesRead = 0;
|
||||
this.totalEcDecodingTimeMillis = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.apache.hadoop.hdfs.util.StripedBlockUtil.StripingChunkReadResult;
|
|||
import org.apache.hadoop.io.erasurecode.ECChunk;
|
||||
import org.apache.hadoop.io.erasurecode.rawcoder.RawErasureDecoder;
|
||||
import org.apache.hadoop.hdfs.DFSUtilClient.CorruptedBlocks;
|
||||
import org.apache.hadoop.util.Time;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
|
@ -419,6 +420,8 @@ abstract class StripeReader {
|
|||
outputs[i] = decodeInputs[decodeIndices[i]];
|
||||
decodeInputs[decodeIndices[i]] = null;
|
||||
}
|
||||
|
||||
long start = Time.monotonicNow();
|
||||
// Step 2: decode into prepared output buffers
|
||||
decoder.decode(decodeInputs, decodeIndices, outputs);
|
||||
|
||||
|
@ -432,6 +435,11 @@ abstract class StripeReader {
|
|||
}
|
||||
}
|
||||
}
|
||||
long end = Time.monotonicNow();
|
||||
// Decoding time includes CPU time on erasure coding and memory copying of
|
||||
// decoded data.
|
||||
dfsStripedInputStream.readStatistics.addErasureCodingDecodingTime(
|
||||
end - start);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,11 +36,16 @@ import org.apache.hadoop.hdfs.ClientContext;
|
|||
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||
import org.apache.hadoop.hdfs.DFSInputStream;
|
||||
import org.apache.hadoop.hdfs.DFSTestUtil;
|
||||
import org.apache.hadoop.hdfs.DistributedFileSystem;
|
||||
import org.apache.hadoop.hdfs.ExtendedBlockId;
|
||||
import org.apache.hadoop.hdfs.HdfsConfiguration;
|
||||
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
||||
import org.apache.hadoop.hdfs.ReadStatistics;
|
||||
import org.apache.hadoop.hdfs.StripedFileTestUtil;
|
||||
import org.apache.hadoop.hdfs.client.HdfsClientConfigKeys;
|
||||
import org.apache.hadoop.hdfs.client.HdfsDataInputStream;
|
||||
import org.apache.hadoop.hdfs.protocol.BlockType;
|
||||
import org.apache.hadoop.hdfs.protocol.ErasureCodingPolicy;
|
||||
import org.apache.hadoop.hdfs.protocol.ExtendedBlock;
|
||||
import org.apache.hadoop.hdfs.server.datanode.CachingStrategy;
|
||||
import org.apache.hadoop.hdfs.shortcircuit.ShortCircuitCache;
|
||||
|
@ -783,4 +788,59 @@ public class TestBlockReaderLocal {
|
|||
if (sockDir != null) sockDir.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 60000)
|
||||
public void testStatisticsForErasureCodingRead() throws IOException {
|
||||
HdfsConfiguration conf = new HdfsConfiguration();
|
||||
|
||||
final ErasureCodingPolicy ecPolicy =
|
||||
StripedFileTestUtil.getDefaultECPolicy();
|
||||
final int numDataNodes =
|
||||
ecPolicy.getNumDataUnits() + ecPolicy.getNumParityUnits();
|
||||
// The length of test file is one full strip + one partial stripe. And
|
||||
// it is not bound to the stripe cell size.
|
||||
final int length = ecPolicy.getCellSize() * (numDataNodes + 1) + 123;
|
||||
final long randomSeed = 4567L;
|
||||
final short repl = 1;
|
||||
try (MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf)
|
||||
.numDataNodes(numDataNodes).build()) {
|
||||
cluster.waitActive();
|
||||
DistributedFileSystem fs = cluster.getFileSystem();
|
||||
fs.enableErasureCodingPolicy(ecPolicy.getName());
|
||||
|
||||
Path ecDir = new Path("/ec");
|
||||
fs.mkdirs(ecDir);
|
||||
fs.setErasureCodingPolicy(ecDir, ecPolicy.getName());
|
||||
Path nonEcDir = new Path("/noEc");
|
||||
fs.mkdirs(nonEcDir);
|
||||
|
||||
byte[] buf = new byte[length];
|
||||
|
||||
Path nonEcFile = new Path(nonEcDir, "file1");
|
||||
DFSTestUtil.createFile(fs, nonEcFile, length, repl, randomSeed);
|
||||
try (HdfsDataInputStream in = (HdfsDataInputStream) fs.open(nonEcFile)) {
|
||||
IOUtils.readFully(in, buf, 0, length);
|
||||
|
||||
ReadStatistics stats = in.getReadStatistics();
|
||||
Assert.assertEquals(BlockType.CONTIGUOUS, stats.getBlockType());
|
||||
Assert.assertEquals(length, stats.getTotalBytesRead());
|
||||
Assert.assertEquals(length, stats.getTotalLocalBytesRead());
|
||||
}
|
||||
|
||||
Path ecFile = new Path(ecDir, "file2");
|
||||
DFSTestUtil.createFile(fs, ecFile, length, repl, randomSeed);
|
||||
// Shutdown one DataNode so that erasure coding decoding process can kick
|
||||
// in.
|
||||
cluster.shutdownDataNode(0);
|
||||
try (HdfsDataInputStream in = (HdfsDataInputStream) fs.open(ecFile)) {
|
||||
IOUtils.readFully(in, buf, 0, length);
|
||||
|
||||
ReadStatistics stats = in.getReadStatistics();
|
||||
Assert.assertEquals(BlockType.STRIPED, stats.getBlockType());
|
||||
Assert.assertEquals(length, stats.getTotalLocalBytesRead());
|
||||
Assert.assertEquals(length, stats.getTotalBytesRead());
|
||||
Assert.assertTrue(stats.getTotalEcDecodingTimeMillis() > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue