diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt index f4189eb0c7a..3f3c5af6faf 100644 --- a/hadoop-yarn-project/CHANGES.txt +++ b/hadoop-yarn-project/CHANGES.txt @@ -15,6 +15,9 @@ Release 2.6.0 - UNRELEASED BUG FIXES + YARN-2251. Avoid negative elapsed time in JHS/MRAM web UI and services. + (Zhijie Shen via junping_du) + Release 2.5.0 - UNRELEASED INCOMPATIBLE CHANGES diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/Times.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/Times.java index b36edecfabe..92cc72ae1d7 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/Times.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/Times.java @@ -21,10 +21,14 @@ package org.apache.hadoop.yarn.util; import java.text.SimpleDateFormat; import java.util.Date; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.hadoop.classification.InterfaceAudience.Private; @Private public class Times { + private static final Log LOG = LogFactory.getLog(Times.class); + static final ThreadLocal dateFormat = new ThreadLocal() { @Override protected SimpleDateFormat initialValue() { @@ -36,12 +40,30 @@ public class Times { return Times.elapsed(started, finished, true); } + // A valid elapsed is supposed to be non-negative. If finished/current time + // is ahead of the started time, return -1 to indicate invalid elapsed time, + // and record a warning log. public static long elapsed(long started, long finished, boolean isRunning) { if (finished > 0 && started > 0) { - return finished - started; + long elapsed = finished - started; + if (elapsed >= 0) { + return elapsed; + } else { + LOG.warn("Finished time " + finished + + " is ahead of started time " + started); + return -1; + } } if (isRunning) { - return started > 0 ? System.currentTimeMillis() - started : 0; + long current = System.currentTimeMillis(); + long elapsed = started > 0 ? current - started : 0; + if (elapsed >= 0) { + return elapsed; + } else { + LOG.warn("Current time " + current + + " is ahead of started time " + started); + return -1; + } } else { return -1; } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/TestTimes.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/TestTimes.java index 350b38995c4..918743d02ff 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/TestTimes.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/TestTimes.java @@ -50,4 +50,15 @@ public class TestTimes { elapsed = Times.elapsed(5, 10, false); Assert.assertEquals("Elapsed time is not 5", 5, elapsed); } + + @Test + public void testFinishTimesAheadOfStartTimes() { + long elapsed = Times.elapsed(10, 5, true); + Assert.assertEquals("Elapsed time is not -1", -1, elapsed); + elapsed = Times.elapsed(10, 5, false); + Assert.assertEquals("Elapsed time is not -1", -1, elapsed); + // use Long.MAX_VALUE to ensure started time is after the current one + elapsed = Times.elapsed(Long.MAX_VALUE, 0, true); + Assert.assertEquals("Elapsed time is not -1", -1, elapsed); + } } \ No newline at end of file