blob: 89c795df5956901287a8609bbe44c1cf02d7de9b [file] [log] [blame]
// 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.
#include "kudu/util/monotime.h"
#include <sys/time.h>
#include <ctime>
#include <limits>
#include <glog/logging.h>
#include "kudu/gutil/integral_types.h"
#include "kudu/gutil/port.h"
#include "kudu/gutil/stringprintf.h"
#include "kudu/gutil/sysinfo.h"
#include "kudu/util/thread_restrictions.h"
#if defined(__APPLE__)
#include "kudu/gutil/walltime.h"
#endif
namespace kudu {
#define MAX_MONOTONIC_SECONDS \
(((1ULL<<63) - 1ULL) /(int64_t)MonoTime::kNanosecondsPerSecond)
///
/// MonoDelta
///
const int64_t MonoDelta::kUninitialized = kint64min;
MonoDelta MonoDelta::FromSeconds(double seconds) {
int64_t delta = seconds * MonoTime::kNanosecondsPerSecond;
return MonoDelta(delta);
}
MonoDelta MonoDelta::FromMilliseconds(int64_t ms) {
return MonoDelta(ms * MonoTime::kNanosecondsPerMillisecond);
}
MonoDelta MonoDelta::FromMicroseconds(int64_t us) {
return MonoDelta(us * MonoTime::kNanosecondsPerMicrosecond);
}
MonoDelta MonoDelta::FromNanoseconds(int64_t ns) {
return MonoDelta(ns);
}
MonoDelta::MonoDelta()
: nano_delta_(kUninitialized) {
}
bool MonoDelta::Initialized() const {
return nano_delta_ != kUninitialized;
}
bool MonoDelta::LessThan(const MonoDelta &rhs) const {
DCHECK(Initialized());
DCHECK(rhs.Initialized());
return nano_delta_ < rhs.nano_delta_;
}
bool MonoDelta::MoreThan(const MonoDelta &rhs) const {
DCHECK(Initialized());
DCHECK(rhs.Initialized());
return nano_delta_ > rhs.nano_delta_;
}
bool MonoDelta::Equals(const MonoDelta &rhs) const {
DCHECK(Initialized());
DCHECK(rhs.Initialized());
return nano_delta_ == rhs.nano_delta_;
}
std::string MonoDelta::ToString() const {
return StringPrintf("%.3fs", ToSeconds());
}
MonoDelta::MonoDelta(int64_t delta)
: nano_delta_(delta) {
}
double MonoDelta::ToSeconds() const {
DCHECK(Initialized());
double d(nano_delta_);
d /= MonoTime::kNanosecondsPerSecond;
return d;
}
int64_t MonoDelta::ToNanoseconds() const {
DCHECK(Initialized());
return nano_delta_;
}
int64_t MonoDelta::ToMicroseconds() const {
DCHECK(Initialized());
return nano_delta_ / MonoTime::kNanosecondsPerMicrosecond;
}
int64_t MonoDelta::ToMilliseconds() const {
DCHECK(Initialized());
return nano_delta_ / MonoTime::kNanosecondsPerMillisecond;
}
void MonoDelta::ToTimeVal(struct timeval *tv) const {
DCHECK(Initialized());
tv->tv_sec = nano_delta_ / MonoTime::kNanosecondsPerSecond;
tv->tv_usec = (nano_delta_ - (tv->tv_sec * MonoTime::kNanosecondsPerSecond))
/ MonoTime::kNanosecondsPerMicrosecond;
// tv_usec must be between 0 and 999999.
// There is little use for negative timevals so wrap it in PREDICT_FALSE.
if (PREDICT_FALSE(tv->tv_usec < 0)) {
--(tv->tv_sec);
tv->tv_usec += 1000000;
}
// Catch positive corner case where we "round down" and could potentially set a timeout of 0.
// Make it 1 usec.
if (PREDICT_FALSE(tv->tv_usec == 0 && tv->tv_sec == 0 && nano_delta_ > 0)) {
tv->tv_usec = 1;
}
// Catch negative corner case where we "round down" and could potentially set a timeout of 0.
// Make it -1 usec (but normalized, so tv_usec is not negative).
if (PREDICT_FALSE(tv->tv_usec == 0 && tv->tv_sec == 0 && nano_delta_ < 0)) {
tv->tv_sec = -1;
tv->tv_usec = 999999;
}
}
void MonoDelta::NanosToTimeSpec(int64_t nanos, struct timespec* ts) {
ts->tv_sec = nanos / MonoTime::kNanosecondsPerSecond;
ts->tv_nsec = nanos - (ts->tv_sec * MonoTime::kNanosecondsPerSecond);
// tv_nsec must be between 0 and 999999999.
// There is little use for negative timespecs so wrap it in PREDICT_FALSE.
if (PREDICT_FALSE(ts->tv_nsec < 0)) {
--(ts->tv_sec);
ts->tv_nsec += MonoTime::kNanosecondsPerSecond;
}
}
void MonoDelta::ToTimeSpec(struct timespec *ts) const {
DCHECK(Initialized());
NanosToTimeSpec(nano_delta_, ts);
}
///
/// MonoTime
///
MonoTime MonoTime::Now() {
#if defined(__APPLE__)
return MonoTime(walltime_internal::GetMonoTimeNanos());
# else
struct timespec ts;
PCHECK(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
return MonoTime(ts);
#endif // defined(__APPLE__)
}
MonoTime MonoTime::Max() {
return MonoTime(std::numeric_limits<int64_t>::max());
}
MonoTime MonoTime::Min() {
return MonoTime(1);
}
const MonoTime& MonoTime::Earliest(const MonoTime& a, const MonoTime& b) {
if (b.nanos_ < a.nanos_) {
return b;
}
return a;
}
MonoTime::MonoTime()
: nanos_(0) {
}
bool MonoTime::Initialized() const {
return nanos_ != 0;
}
MonoDelta MonoTime::GetDeltaSince(const MonoTime &rhs) const {
DCHECK(Initialized());
DCHECK(rhs.Initialized());
int64_t delta(nanos_);
delta -= rhs.nanos_;
return MonoDelta(delta);
}
void MonoTime::AddDelta(const MonoDelta &delta) {
DCHECK(Initialized());
nanos_ += delta.nano_delta_;
}
bool MonoTime::ComesBefore(const MonoTime &rhs) const {
DCHECK(Initialized());
DCHECK(rhs.Initialized());
return nanos_ < rhs.nanos_;
}
std::string MonoTime::ToString() const {
return StringPrintf("%.3fs", ToSeconds());
}
void MonoTime::ToTimeSpec(struct timespec* ts) const {
DCHECK(Initialized());
MonoDelta::NanosToTimeSpec(nanos_, ts);
}
bool MonoTime::Equals(const MonoTime& other) const {
return nanos_ == other.nanos_;
}
MonoTime& MonoTime::operator+=(const MonoDelta& delta) {
this->AddDelta(delta);
return *this;
}
MonoTime& MonoTime::operator-=(const MonoDelta& delta) {
this->AddDelta(MonoDelta(-1 * delta.nano_delta_));
return *this;
}
MonoTime::MonoTime(const struct timespec &ts) {
// Monotonic time resets when the machine reboots. The 64-bit limitation
// means that we can't represent times larger than 292 years, which should be
// adequate.
CHECK_LT(ts.tv_sec, MAX_MONOTONIC_SECONDS);
nanos_ = ts.tv_sec;
nanos_ *= MonoTime::kNanosecondsPerSecond;
nanos_ += ts.tv_nsec;
}
MonoTime::MonoTime(int64_t nanos)
: nanos_(nanos) {
}
double MonoTime::ToSeconds() const {
double d(nanos_);
d /= MonoTime::kNanosecondsPerSecond;
return d;
}
void SleepFor(const MonoDelta& delta) {
ThreadRestrictions::AssertWaitAllowed();
base::SleepForNanoseconds(delta.ToNanoseconds());
}
bool operator==(const MonoDelta &lhs, const MonoDelta &rhs) {
return lhs.Equals(rhs);
}
bool operator!=(const MonoDelta &lhs, const MonoDelta &rhs) {
return !lhs.Equals(rhs);
}
bool operator<(const MonoDelta &lhs, const MonoDelta &rhs) {
return lhs.LessThan(rhs);
}
bool operator<=(const MonoDelta &lhs, const MonoDelta &rhs) {
return lhs.LessThan(rhs) || lhs.Equals(rhs);
}
bool operator>(const MonoDelta &lhs, const MonoDelta &rhs) {
return lhs.MoreThan(rhs);
}
bool operator>=(const MonoDelta &lhs, const MonoDelta &rhs) {
return lhs.MoreThan(rhs) || lhs.Equals(rhs);
}
bool operator==(const MonoTime& lhs, const MonoTime& rhs) {
return lhs.Equals(rhs);
}
bool operator!=(const MonoTime& lhs, const MonoTime& rhs) {
return !lhs.Equals(rhs);
}
bool operator<(const MonoTime& lhs, const MonoTime& rhs) {
return lhs.ComesBefore(rhs);
}
bool operator<=(const MonoTime& lhs, const MonoTime& rhs) {
return lhs.ComesBefore(rhs) || lhs.Equals(rhs);
}
bool operator>(const MonoTime& lhs, const MonoTime& rhs) {
return rhs.ComesBefore(lhs);
}
bool operator>=(const MonoTime& lhs, const MonoTime& rhs) {
return rhs.ComesBefore(lhs) || rhs.Equals(lhs);
}
MonoTime operator+(const MonoTime& t, const MonoDelta& delta) {
MonoTime tmp(t);
tmp.AddDelta(delta);
return tmp;
}
MonoTime operator-(const MonoTime& t, const MonoDelta& delta) {
MonoTime tmp(t);
tmp.AddDelta(MonoDelta::FromNanoseconds(-delta.ToNanoseconds()));
return tmp;
}
MonoDelta operator-(const MonoTime& t_end, const MonoTime& t_beg) {
return t_end.GetDeltaSince(t_beg);
}
} // namespace kudu