diff --git a/hadoop-common-project/hadoop-common/CHANGES.txt b/hadoop-common-project/hadoop-common/CHANGES.txt index 96c13eb080..dc4c80f1ec 100644 --- a/hadoop-common-project/hadoop-common/CHANGES.txt +++ b/hadoop-common-project/hadoop-common/CHANGES.txt @@ -166,6 +166,8 @@ Trunk (Unreleased) HADOOP-9486. Promoted Windows and Shell related utils from YARN to Hadoop Common. (Chris Nauroth via vinodkv) + HADOOP-8608. Add Configuration API for parsing time durations. (cdouglas) + BUG FIXES HADOOP-9451. Fault single-layer config if node group topology is enabled. diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java index 67befcc323..8317c9e22d 100644 --- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java +++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/conf/Configuration.java @@ -54,6 +54,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import java.util.concurrent.TimeUnit; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -1145,6 +1146,93 @@ public class Configuration implements Iterable>, : Enum.valueOf(defaultValue.getDeclaringClass(), val); } + enum ParsedTimeDuration { + NS { + TimeUnit unit() { return TimeUnit.NANOSECONDS; } + String suffix() { return "ns"; } + }, + US { + TimeUnit unit() { return TimeUnit.MICROSECONDS; } + String suffix() { return "us"; } + }, + MS { + TimeUnit unit() { return TimeUnit.MILLISECONDS; } + String suffix() { return "ms"; } + }, + S { + TimeUnit unit() { return TimeUnit.SECONDS; } + String suffix() { return "s"; } + }, + M { + TimeUnit unit() { return TimeUnit.MINUTES; } + String suffix() { return "m"; } + }, + H { + TimeUnit unit() { return TimeUnit.HOURS; } + String suffix() { return "h"; } + }, + D { + TimeUnit unit() { return TimeUnit.DAYS; } + String suffix() { return "d"; } + }; + abstract TimeUnit unit(); + abstract String suffix(); + static ParsedTimeDuration unitFor(String s) { + for (ParsedTimeDuration ptd : values()) { + // iteration order is in decl order, so SECONDS matched last + if (s.endsWith(ptd.suffix())) { + return ptd; + } + } + return null; + } + static ParsedTimeDuration unitFor(TimeUnit unit) { + for (ParsedTimeDuration ptd : values()) { + if (ptd.unit() == unit) { + return ptd; + } + } + return null; + } + } + + /** + * Set the value of name to the given time duration. This + * is equivalent to set(<name>, value + <time suffix>). + * @param name Property name + * @param value Time duration + * @param unit Unit of time + */ + public void setTimeDuration(String name, long value, TimeUnit unit) { + set(name, value + ParsedTimeDuration.unitFor(unit).suffix()); + } + + /** + * Return time duration in the given time unit. Valid units are encoded in + * properties as suffixes: nanoseconds (ns), microseconds (us), milliseconds + * (ms), seconds (s), minutes (m), hours (h), and days (d). + * @param name Property name + * @param defaultValue Value returned if no mapping exists. + * @param unit Unit to convert the stored property, if it exists. + * @throws NumberFormatException If the property stripped of its unit is not + * a number + */ + public long getTimeDuration(String name, long defaultValue, TimeUnit unit) { + String vStr = get(name); + if (null == vStr) { + return defaultValue; + } + vStr = vStr.trim(); + ParsedTimeDuration vUnit = ParsedTimeDuration.unitFor(vStr); + if (null == vUnit) { + LOG.warn("No unit for " + name + "(" + vStr + ") assuming " + unit); + vUnit = ParsedTimeDuration.unitFor(unit); + } else { + vStr = vStr.substring(0, vStr.lastIndexOf(vUnit.suffix())); + } + return unit.convert(Long.parseLong(vStr), vUnit.unit()); + } + /** * Get the value of the name property as a Pattern. * If no such property is specified, or if the specified value is not a valid diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/conf/TestConfiguration.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/conf/TestConfiguration.java index 19ff6c6c99..cc5903ffea 100644 --- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/conf/TestConfiguration.java +++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/conf/TestConfiguration.java @@ -36,6 +36,7 @@ import java.util.Map; import java.util.Random; import java.util.Set; import java.util.regex.Pattern; +import static java.util.concurrent.TimeUnit.*; import junit.framework.TestCase; import static org.junit.Assert.assertArrayEquals; @@ -693,6 +694,37 @@ public class TestConfiguration extends TestCase { assertTrue(fail); } + public void testTimeDuration() { + Configuration conf = new Configuration(false); + conf.setTimeDuration("test.time.a", 7L, SECONDS); + assertEquals("7s", conf.get("test.time.a")); + assertEquals(0L, conf.getTimeDuration("test.time.a", 30, MINUTES)); + assertEquals(7L, conf.getTimeDuration("test.time.a", 30, SECONDS)); + assertEquals(7000L, conf.getTimeDuration("test.time.a", 30, MILLISECONDS)); + assertEquals(7000000L, + conf.getTimeDuration("test.time.a", 30, MICROSECONDS)); + assertEquals(7000000000L, + conf.getTimeDuration("test.time.a", 30, NANOSECONDS)); + conf.setTimeDuration("test.time.b", 1, DAYS); + assertEquals("1d", conf.get("test.time.b")); + assertEquals(1, conf.getTimeDuration("test.time.b", 1, DAYS)); + assertEquals(24, conf.getTimeDuration("test.time.b", 1, HOURS)); + assertEquals(MINUTES.convert(1, DAYS), + conf.getTimeDuration("test.time.b", 1, MINUTES)); + + // check default + assertEquals(30L, conf.getTimeDuration("test.time.X", 30, SECONDS)); + conf.set("test.time.X", "30"); + assertEquals(30L, conf.getTimeDuration("test.time.X", 40, SECONDS)); + + for (Configuration.ParsedTimeDuration ptd : + Configuration.ParsedTimeDuration.values()) { + conf.setTimeDuration("test.time.unit", 1, ptd.unit()); + assertEquals(1 + ptd.suffix(), conf.get("test.time.unit")); + assertEquals(1, conf.getTimeDuration("test.time.unit", 2, ptd.unit())); + } + } + public void testPattern() throws IOException { out = new BufferedWriter(new FileWriter(CONFIG)); startConfig();