Skip to content

Commit

Permalink
issue=1251, use clock_gettime(CLOCK_MONOTONIC) to get current time
Browse files Browse the repository at this point in the history
bug fix for system time rollback
  • Loading branch information
caijieming committed May 5, 2017
1 parent 98b337d commit 43a6b26
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 43 deletions.
22 changes: 14 additions & 8 deletions src/common/mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,10 +120,14 @@ class MutexLock {
class CondVar {
public:
explicit CondVar(Mutex* mu) : mu_(mu) {
PthreadCall("init condvar", pthread_cond_init(&cond_, NULL));
// use monotonic clock
PthreadCall("condattr init ", pthread_condattr_init(&attr_));
PthreadCall("condattr setclock ", pthread_condattr_setclock(&attr_, CLOCK_MONOTONIC));
PthreadCall("condvar init with attr", pthread_cond_init(&cond_, &attr_));
}
~CondVar() {
PthreadCall("destroy condvar", pthread_cond_destroy(&cond_));
PthreadCall("condvar destroy", pthread_cond_destroy(&cond_));
PthreadCall("condattr destroy", pthread_condattr_destroy(&attr_));
}
void Wait(const char* msg = NULL) {
int64_t msg_threshold = mu_->msg_threshold_;
Expand All @@ -134,12 +138,13 @@ class CondVar {
// Time wait in us
// timeout < 0 would cause ETIMEOUT and return false immediately
bool TimeWaitInUs(int timeout, const char* msg = NULL) {
timespec ts;
struct timeval tv;
gettimeofday(&tv, NULL);
int64_t usec = tv.tv_usec + timeout;
ts.tv_sec = tv.tv_sec + usec / 1000000;
ts.tv_nsec = (usec % 1000000) * 1000;
// ref: http://www.qnx.com/developers/docs/6.5.0SP1.update/com.qnx.doc.neutrino_lib_ref/p/pthread_cond_timedwait.html
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
int64_t nsec = ((int64_t)timeout) * 1000 + ts.tv_nsec;
ts.tv_sec += nsec / 1000000000;
ts.tv_nsec = nsec % 1000000000;

int64_t msg_threshold = mu_->msg_threshold_;
mu_->BeforeUnlock();
int ret = pthread_cond_timedwait(&cond_, &mu_->mu_, &ts);
Expand All @@ -163,6 +168,7 @@ class CondVar {
void operator=(const CondVar&);
Mutex* mu_;
pthread_cond_t cond_;
pthread_condattr_t attr_;
};
} // namespace common

Expand Down
10 changes: 4 additions & 6 deletions src/common/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,15 @@ static inline std::string get_curtime_str() {
}

static inline int64_t get_micros() {
struct timeval tv;
gettimeofday(&tv, NULL);
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<int64_t>(ts.tv_sec) * 1000000 + static_cast<int64_t>(ts.tv_nsec) / 1000;
}

static inline int64_t get_unique_micros(int64_t ref) {
struct timeval tv;
int64_t now;
do {
gettimeofday(&tv, NULL);
now = static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
now = get_micros();
} while (now == ref);
return now;
}
Expand Down
4 changes: 2 additions & 2 deletions src/leveldb/bench/tera_bench.cc
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ class Benchmark {
snprintf(msg, sizeof(msg), "(%d ops)", num_entries);
message_ = msg;
}
char ts[10];
snprintf(ts, sizeof(ts), "%d", FLAGS_value_seed);
char ts[20];
snprintf(ts, sizeof(ts), "%lld", ((long long int)FLAGS_value_seed) * 1000000);

// Write to database
int i = FLAGS_start_key;
Expand Down
29 changes: 18 additions & 11 deletions src/leveldb/port/port_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,32 +50,39 @@ void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); }

CondVar::CondVar(Mutex* mu)
: mu_(mu) {
PthreadCall("init cv", pthread_cond_init(&cv_, NULL));
// use monotonic clock
PthreadCall("condattr init ", pthread_condattr_init(&attr_));
PthreadCall("condattr setclock ", pthread_condattr_setclock(&attr_, CLOCK_MONOTONIC));
PthreadCall("condvar init with attr", pthread_cond_init(&cond_, &attr_));
}

CondVar::~CondVar() { PthreadCall("destroy cv", pthread_cond_destroy(&cv_)); }
CondVar::~CondVar() {
PthreadCall("condvar destroy", pthread_cond_destroy(&cond_));
PthreadCall("condattr destroy", pthread_condattr_destroy(&attr_));
}

void CondVar::Wait() {
PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_));
PthreadCall("condvar wait", pthread_cond_wait(&cond_, &mu_->mu_));
}

// wait in ms
bool CondVar::Wait(int64_t wait_millisec) {
assert(wait_millisec >= 0);
// ref: http://www.qnx.com/developers/docs/6.5.0SP1.update/com.qnx.doc.neutrino_lib_ref/p/pthread_cond_timedwait.html
struct timespec ts;
struct timeval tp;
gettimeofday(&tp, NULL);
uint64_t usec = tp.tv_usec + wait_millisec * 1000;
ts.tv_sec = tp.tv_sec + usec / 1000000;
ts.tv_nsec = (usec % 1000000) * 1000;
return (0 == pthread_cond_timedwait(&cv_, &mu_->mu_, &ts));
clock_gettime(CLOCK_MONOTONIC, &ts);
int64_t nsec = ((int64_t)wait_millisec) * 1000000 + ts.tv_nsec;
ts.tv_sec += nsec / 1000000000;
ts.tv_nsec = nsec % 1000000000;
return (0 == pthread_cond_timedwait(&cond_, &mu_->mu_, &ts));
}

void CondVar::Signal() {
PthreadCall("signal", pthread_cond_signal(&cv_));
PthreadCall("signal", pthread_cond_signal(&cond_));
}

void CondVar::SignalAll() {
PthreadCall("broadcast", pthread_cond_broadcast(&cv_));
PthreadCall("broadcast", pthread_cond_broadcast(&cond_));
}

void InitOnce(OnceType* once, void (*initializer)()) {
Expand Down
3 changes: 2 additions & 1 deletion src/leveldb/port/port_posix.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ class CondVar {
void Signal();
void SignalAll();
private:
pthread_cond_t cv_;
pthread_cond_t cond_;
pthread_condattr_t attr_;
Mutex* mu_;
};

Expand Down
6 changes: 3 additions & 3 deletions src/leveldb/util/env_posix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -809,9 +809,9 @@ class PosixEnv : public Env {
}

virtual uint64_t NowMicros() {
struct timeval tv;
gettimeofday(&tv, NULL);
return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<int64_t>(ts.tv_sec) * 1000000 + static_cast<int64_t>(ts.tv_nsec) / 1000;
}

virtual void SleepForMicroseconds(int micros) {
Expand Down
6 changes: 3 additions & 3 deletions src/leveldb/util/raw_key_operator_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ void print_bytes(const char* str, int len) {
}

int64_t get_micros() {
struct timeval tv;
gettimeofday(&tv, NULL);
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<int64_t>(ts.tv_sec) * 1000000 + static_cast<int64_t>(ts.tv_nsec) / 1000;
}

class RawKeyOperatorTest {};
Expand Down
14 changes: 5 additions & 9 deletions src/utils/timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,23 +27,19 @@ static inline std::string get_curtime_str_plain() {
}

static inline int64_t get_micros() {
struct timeval tv;
gettimeofday(&tv, NULL);
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return static_cast<int64_t>(ts.tv_sec) * 1000000 + static_cast<int64_t>(ts.tv_nsec) / 1000;
}

static inline int64_t get_millis() {
struct timeval tv;
gettimeofday(&tv, NULL);
return static_cast<int64_t>(tv.tv_sec) * 1000 + tv.tv_usec / 1000;
return get_micros() / 1000;
}

static inline int64_t get_unique_micros(int64_t ref) {
struct timeval tv;
int64_t now;
do {
gettimeofday(&tv, NULL);
now = static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
now = get_micros();
} while (now == ref);
return now;
}
Expand Down

0 comments on commit 43a6b26

Please sign in to comment.