Explorar el Código

HADOOP-774(YARN-2251). Avoid negative elapsed time in JHS/MRAM web UI and services (Contributed by Zhijie Shen)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1607834 13f79535-47bb-0310-9956-ffa450edef68

Conflicts:
	hadoop-yarn-project/CHANGES.txt
	hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/util/Times.java
	hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/TestTimes.java
Junping Du hace 11 años
padre
commit
e9325e66dc

+ 3 - 0
HDP-CHANGES.txt

@@ -117,3 +117,6 @@ The changes also include jiras that are yet to become available in later apache
 
     HADOOP-10840. Fix OutOfMemoryError caused by metrics system in Azure File
     System. (Shanyu Zhao via cnauroth)
+
+    YARN-2251. Avoid negative elapsed time in JHS/MRAM web UI and services.
+    (Zhijie Shen via junping_du)

+ 25 - 3
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<SimpleDateFormat> dateFormat =
       new ThreadLocal<SimpleDateFormat>() {
         @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) {
-      return finished - started;
+    if (finished > 0 && started > 0) {
+      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;
     }

+ 64 - 0
hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/test/java/org/apache/hadoop/yarn/util/TestTimes.java

@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.yarn.util;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestTimes {
+
+  @Test
+  public void testNegativeStartTimes() {
+    long elapsed = Times.elapsed(-5, 10, true);
+    Assert.assertEquals("Elapsed time is not 0", 0, elapsed);
+    elapsed = Times.elapsed(-5, 10, false);
+    Assert.assertEquals("Elapsed time is not -1", -1, elapsed);
+  }
+
+  @Test
+  public void testNegativeFinishTimes() {
+    long elapsed = Times.elapsed(5, -10, false);
+    Assert.assertEquals("Elapsed time is not -1", -1, elapsed);
+  }
+
+  @Test
+  public void testNegativeStartandFinishTimes() {
+    long elapsed = Times.elapsed(-5, -10, false);
+    Assert.assertEquals("Elapsed time is not -1", -1, elapsed);
+  }
+
+  @Test
+  public void testPositiveStartandFinishTimes() {
+    long elapsed = Times.elapsed(5, 10, true);
+    Assert.assertEquals("Elapsed time is not 5", 5, elapsed);
+    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);
+  }
+}