]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
common/ceph_time: add parse_timespan
authorSage Weil <sage@redhat.com>
Wed, 19 Dec 2018 19:23:42 +0000 (13:23 -0600)
committerSage Weil <sage@redhat.com>
Thu, 3 Jan 2019 13:19:20 +0000 (07:19 -0600)
Make it understand units like 'hours', 'minute', 'm', 'w', etc.

Signed-off-by: Sage Weil <sage@redhat.com>
src/common/ceph_time.cc
src/common/ceph_time.h
src/test/common/test_config.cc

index b292697bc5eb7bdb1360921eb4c67a92c6fa3fe4..2993b8f4960b9d99b6026f657546d943a77be9d1 100644 (file)
@@ -16,6 +16,7 @@
 #include "ceph_time.h"
 #include "log/LogClock.h"
 #include "config.h"
+#include "strtol.h"
 
 #if defined(__APPLE__)
 #include <mach/mach.h>
@@ -231,4 +232,87 @@ namespace ceph {
     }
     return ss.str();
   }
+
+  std::chrono::seconds parse_timespan(const std::string& s)
+  {
+    static std::map<string,int> units = {
+      { "s", 1 },
+      { "sec", 1 },
+      { "second", 1 },
+      { "seconds", 1 },
+      { "m", 60 },
+      { "min", 60 },
+      { "minute", 60 },
+      { "minutes", 60 },
+      { "h", 60*60 },
+      { "hr", 60*60 },
+      { "hour", 60*60 },
+      { "hours", 60*60 },
+      { "d", 24*60*60 },
+      { "day", 24*60*60 },
+      { "days", 24*60*60 },
+      { "w", 7*24*60*60 },
+      { "wk", 7*24*60*60 },
+      { "week", 7*24*60*60 },
+      { "weeks", 7*24*60*60 },
+      { "M", 30*24*60*60 },
+      { "month", 30*24*60*60 },
+      { "months", 30*24*60*60 },
+      { "y", 365*24*60*60 },
+      { "yr", 365*24*60*60 },
+      { "year", 365*24*60*60 },
+      { "years", 365*24*60*60 },
+    };
+
+    auto r = 0s;
+    auto pos = 0u;
+    while (pos < s.size()) {
+      // skip whitespace
+      while (std::isspace(s[pos])) {
+       ++pos;
+      }
+      if (pos >= s.size()) {
+       break;
+      }
+
+      // consume any digits
+      auto val_start = pos;
+      while (std::isdigit(s[pos])) {
+       ++pos;
+      }
+      if (val_start == pos) {
+       throw invalid_argument("expected digit");
+      }
+      string n = s.substr(val_start, pos - val_start);
+      string err;
+      auto val = strict_strtoll(n.c_str(), 10, &err);
+      if (err.size()) {
+       throw invalid_argument(err);
+      }
+
+      // skip whitespace
+      while (std::isspace(s[pos])) {
+       ++pos;
+      }
+
+      // consume unit
+      auto unit_start = pos;
+      while (std::isalpha(s[pos])) {
+       ++pos;
+      }
+      if (unit_start != pos) {
+       string unit = s.substr(unit_start, pos - unit_start);
+       auto p = units.find(unit);
+       if (p == units.end()) {
+         throw invalid_argument("unrecogized unit '"s + unit + "'");
+       }
+       val *= p->second;
+      } else if (pos < s.size()) {
+       throw invalid_argument("unexpected trailing '"s + s.substr(pos) + "'");
+      }
+      r += chrono::seconds(val);
+    }
+    return r;
+  }
+
 }
index ca9f88b1ec7dc46653eb951d1559784c5d8e6b2a..74236bfd4ef288f64b4bf0263f0a27edeed9b862 100644 (file)
@@ -488,6 +488,7 @@ inline timespan to_timespan(signedspan z) {
 
 std::string timespan_str(timespan t);
 std::string exact_timespan_str(timespan t);
+std::chrono::seconds parse_timespan(const std::string& s);
 
 // detects presence of Clock::to_timespec() and from_timespec()
 template <typename Clock, typename = std::void_t<>>
index 19dab10a81bc2a46aebeba7dda52d2d5473e922e..116ddbb3880f0da41fc36066ac8810a0dfa9e511 100644 (file)
@@ -167,6 +167,14 @@ TEST(md_config_t, set_val)
     EXPECT_EQ(-EINVAL, conf.set_val("mgr_tick_period", "21 centuries", nullptr));
     EXPECT_EQ(expected.count(), conf.get_val<seconds>("mgr_tick_period").count());
   }
+
+  for (int i = 0; i < 100; ++i) {
+    std::chrono::seconds j = std::chrono::seconds(rand());
+    string s = exact_timespan_str(j);
+    std::chrono::seconds k = parse_timespan(s);
+    cout << "rt: " << j.count() << " -> " << s << " -> " << k.count() << std::endl;
+    EXPECT_EQ(j.count(), k.count());
+  }
 }
 
 TEST(Option, validation)