Skip to content

Commit 607c981

Browse files
authored
HDFS-17262. Fixed the verbose log.warn in DFSUtil.addTransferRateMetric(). (#6290). Contributed by Xing Lin.
Reviewed-by: Ravindra Dingankar <[email protected]> Reviewed-by: Simbarashe Dzinamarira <[email protected]> Reviewed-by: Tao Li <[email protected]> Signed-off-by: He Xiaoqiao <[email protected]>
1 parent 6a22bea commit 607c981

File tree

3 files changed

+64
-21
lines changed

3 files changed

+64
-21
lines changed

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSUtil.java

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import java.util.Set;
6161
import java.util.SortedSet;
6262

63+
import java.util.concurrent.TimeUnit;
6364
import org.apache.commons.cli.CommandLine;
6465
import org.apache.commons.cli.CommandLineParser;
6566
import org.apache.commons.cli.Option;
@@ -1970,16 +1971,36 @@ public static boolean isParentEntry(final String path, final String parent) {
19701971
}
19711972

19721973
/**
1973-
* Add transfer rate metrics for valid data read and duration values.
1974+
* Add transfer rate metrics in bytes per second.
19741975
* @param metrics metrics for datanodes
19751976
* @param read bytes read
1976-
* @param duration read duration
1977+
* @param durationInNS read duration in nanoseconds
19771978
*/
1978-
public static void addTransferRateMetric(final DataNodeMetrics metrics, final long read, final long duration) {
1979-
if (read >= 0 && duration > 0) {
1980-
metrics.addReadTransferRate(read * 1000 / duration);
1981-
} else {
1982-
LOG.warn("Unexpected value for data transfer bytes={} duration={}", read, duration);
1983-
}
1979+
public static void addTransferRateMetric(final DataNodeMetrics metrics, final long read,
1980+
final long durationInNS) {
1981+
metrics.addReadTransferRate(getTransferRateInBytesPerSecond(read, durationInNS));
1982+
}
1983+
1984+
/**
1985+
* Calculate the transfer rate in bytes per second.
1986+
*
1987+
* We have the read duration in nanoseconds for precision for transfers taking a few nanoseconds.
1988+
* We treat shorter durations below 1 ns as 1 ns as we also want to capture reads taking less
1989+
* than a nanosecond. To calculate transferRate in bytes per second, we avoid multiplying bytes
1990+
* read by 10^9 to avoid overflow. Instead, we first calculate the duration in seconds in double
1991+
* to keep the decimal values for smaller durations. We then divide bytes read by
1992+
* durationInSeconds to get the transferRate in bytes per second.
1993+
*
1994+
* We also replace a negative value for transferred bytes with 0 byte.
1995+
*
1996+
* @param bytes bytes read
1997+
* @param durationInNS read duration in nanoseconds
1998+
* @return bytes per second
1999+
*/
2000+
public static long getTransferRateInBytesPerSecond(long bytes, long durationInNS) {
2001+
bytes = Math.max(bytes, 0);
2002+
durationInNS = Math.max(durationInNS, 1);
2003+
double durationInSeconds = (double) durationInNS / TimeUnit.SECONDS.toNanos(1);
2004+
return (long) (bytes / durationInSeconds);
19842005
}
19852006
}

hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/datanode/DataXceiver.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -607,10 +607,10 @@ public void readBlock(final ExtendedBlock block,
607607
// send op status
608608
writeSuccessWithChecksumInfo(blockSender, new DataOutputStream(getOutputStream()));
609609

610-
long beginRead = Time.monotonicNow();
610+
long beginReadInNS = Time.monotonicNowNanos();
611611
// send data
612612
read = blockSender.sendBlock(out, baseStream, dataXceiverServer.getReadThrottler());
613-
long duration = Time.monotonicNow() - beginRead;
613+
long durationInNS = Time.monotonicNowNanos() - beginReadInNS;
614614
if (blockSender.didSendEntireByteRange()) {
615615
// If we sent the entire range, then we should expect the client
616616
// to respond with a Status enum.
@@ -633,8 +633,8 @@ public void readBlock(final ExtendedBlock block,
633633
}
634634
datanode.metrics.incrBytesRead((int) read);
635635
datanode.metrics.incrBlocksRead();
636-
datanode.metrics.incrTotalReadTime(duration);
637-
DFSUtil.addTransferRateMetric(datanode.metrics, read, duration);
636+
datanode.metrics.incrTotalReadTime(TimeUnit.NANOSECONDS.toMillis(durationInNS));
637+
DFSUtil.addTransferRateMetric(datanode.metrics, read, durationInNS);
638638
} catch ( SocketException ignored ) {
639639
LOG.trace("{}:Ignoring exception while serving {} to {}",
640640
dnR, block, remoteAddress, ignored);
@@ -1117,15 +1117,15 @@ public void copyBlock(final ExtendedBlock block,
11171117
// send status first
11181118
writeSuccessWithChecksumInfo(blockSender, reply);
11191119

1120-
long beginRead = Time.monotonicNow();
1120+
long beginReadInNS = Time.monotonicNowNanos();
11211121
// send block content to the target
11221122
long read = blockSender.sendBlock(reply, baseStream,
11231123
dataXceiverServer.balanceThrottler);
1124-
long duration = Time.monotonicNow() - beginRead;
1124+
long durationInNS = Time.monotonicNowNanos() - beginReadInNS;
11251125
datanode.metrics.incrBytesRead((int) read);
11261126
datanode.metrics.incrBlocksRead();
1127-
datanode.metrics.incrTotalReadTime(duration);
1128-
DFSUtil.addTransferRateMetric(datanode.metrics, read, duration);
1127+
datanode.metrics.incrTotalReadTime(TimeUnit.NANOSECONDS.toMillis(durationInNS));
1128+
DFSUtil.addTransferRateMetric(datanode.metrics, read, durationInNS);
11291129

11301130
LOG.info("Copied {} to {}", block, peer.getRemoteAddressString());
11311131
} catch (IOException ioe) {

hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDFSUtil.java

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,14 +1127,36 @@ public void testErrorMessageForInvalidNameservice() throws Exception {
11271127
@Test
11281128
public void testAddTransferRateMetricForValidValues() {
11291129
DataNodeMetrics mockMetrics = mock(DataNodeMetrics.class);
1130-
DFSUtil.addTransferRateMetric(mockMetrics, 100, 10);
1131-
verify(mockMetrics).addReadTransferRate(10000);
1130+
DFSUtil.addTransferRateMetric(mockMetrics, 3_251_854_872L, 129_593_000_000L);
1131+
verify(mockMetrics).addReadTransferRate(250_92_828L);
11321132
}
11331133

11341134
@Test
1135-
public void testAddTransferRateMetricForInvalidValue() {
1135+
public void testAddTransferRateMetricForZeroNSTransferDuration() {
11361136
DataNodeMetrics mockMetrics = mock(DataNodeMetrics.class);
1137-
DFSUtil.addTransferRateMetric(mockMetrics, 100, 0);
1138-
verify(mockMetrics, times(0)).addReadTransferRate(anyLong());
1137+
DFSUtil.addTransferRateMetric(mockMetrics, 1L, 0);
1138+
verify(mockMetrics).addReadTransferRate(999_999_999L);
1139+
}
1140+
1141+
@Test
1142+
public void testAddTransferRateMetricNegativeTransferBytes() {
1143+
DataNodeMetrics mockMetrics = mock(DataNodeMetrics.class);
1144+
DFSUtil.addTransferRateMetric(mockMetrics, -1L, 0);
1145+
verify(mockMetrics).addReadTransferRate(0L);
1146+
}
1147+
1148+
@Test
1149+
public void testAddTransferRateMetricZeroTransferBytes() {
1150+
DataNodeMetrics mockMetrics = mock(DataNodeMetrics.class);
1151+
DFSUtil.addTransferRateMetric(mockMetrics, -1L, 0);
1152+
verify(mockMetrics).addReadTransferRate(0L);
1153+
}
1154+
1155+
@Test
1156+
public void testGetTransferRateInBytesPerSecond() {
1157+
assertEquals(999_999_999, DFSUtil.getTransferRateInBytesPerSecond(1L, 1L));
1158+
assertEquals(999_999_999, DFSUtil.getTransferRateInBytesPerSecond(1L, 0L));
1159+
assertEquals(102_400_000,
1160+
DFSUtil.getTransferRateInBytesPerSecond(512_000_000L, 5_000_000_000L));
11391161
}
11401162
}

0 commit comments

Comments
 (0)