Fix potential ambiguities in/around port/sys_time.h (#10045)

Summary:
There are some time-related POSIX APIs that are not available on Windows
(e.g. `localtime_r`), which we have worked around by providing our own
implementations in `port/sys_time.h`. This workaround actually relies on
some ambiguity: on Windows, a call to `localtime_r` calls
`ROCKSDB_NAMESPACE::port::localtime_r` (which is pulled into
`ROCKSDB_NAMESPACE` by a using-declaration), while on other platforms
it calls the global `localtime_r`. This works fine as long as there is only one
candidate function; however, it breaks down when there is more than one
`localtime_r` visible in a scope.

The patch fixes this by introducing `ROCKSDB_NAMESPACE::port::{TimeVal, GetTimeOfDay, LocalTimeR}`
to eliminate any ambiguity.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/10045

Test Plan: `make check`

Reviewed By: riversand963

Differential Revision: D36639372

Pulled By: ltamasi

fbshipit-source-id: fc13dbfa421b7c8918111a6d9e24ce77e91a7c50
This commit is contained in:
Levi Tamasi 2022-05-24 18:20:17 -07:00
parent f80bac500e
commit 07a00828af
12 changed files with 57 additions and 39 deletions

6
env/env_posix.cc vendored
View File

@ -134,8 +134,8 @@ class PosixClock : public SystemClock {
const char* NickName() const override { return kClassName(); } const char* NickName() const override { return kClassName(); }
uint64_t NowMicros() override { uint64_t NowMicros() override {
struct timeval tv; port::TimeVal tv;
gettimeofday(&tv, nullptr); port::GetTimeOfDay(&tv, nullptr);
return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec; return static_cast<uint64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
} }
@ -200,7 +200,7 @@ class PosixClock : public SystemClock {
dummy.reserve(maxsize); dummy.reserve(maxsize);
dummy.resize(maxsize); dummy.resize(maxsize);
char* p = &dummy[0]; char* p = &dummy[0];
localtime_r(&seconds, &t); port::LocalTimeR(&seconds, &t);
snprintf(p, maxsize, "%04d/%02d/%02d-%02d:%02d:%02d ", t.tm_year + 1900, snprintf(p, maxsize, "%04d/%02d/%02d-%02d:%02d:%02d ", t.tm_year + 1900,
t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec); t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
return dummy; return dummy;

10
env/env_test.cc vendored
View File

@ -1604,9 +1604,9 @@ class TestLogger : public Logger {
if (new_format[0] == '[') { if (new_format[0] == '[') {
// "[DEBUG] " // "[DEBUG] "
ASSERT_TRUE(n <= 56 + (512 - static_cast<int>(sizeof(struct timeval)))); ASSERT_TRUE(n <= 56 + (512 - static_cast<int>(sizeof(port::TimeVal))));
} else { } else {
ASSERT_TRUE(n <= 48 + (512 - static_cast<int>(sizeof(struct timeval)))); ASSERT_TRUE(n <= 48 + (512 - static_cast<int>(sizeof(port::TimeVal))));
} }
va_end(backup_ap); va_end(backup_ap);
} }
@ -1674,9 +1674,9 @@ class TestLogger2 : public Logger {
va_copy(backup_ap, ap); va_copy(backup_ap, ap);
int n = vsnprintf(new_format, sizeof(new_format) - 1, format, backup_ap); int n = vsnprintf(new_format, sizeof(new_format) - 1, format, backup_ap);
// 48 bytes for extra information + bytes allocated // 48 bytes for extra information + bytes allocated
ASSERT_TRUE( ASSERT_TRUE(n <=
n <= 48 + static_cast<int>(max_log_size_ - sizeof(struct timeval))); 48 + static_cast<int>(max_log_size_ - sizeof(port::TimeVal)));
ASSERT_TRUE(n > static_cast<int>(max_log_size_ - sizeof(struct timeval))); ASSERT_TRUE(n > static_cast<int>(max_log_size_ - sizeof(port::TimeVal)));
va_end(backup_ap); va_end(backup_ap);
} }
} }

6
env/mock_env.cc vendored
View File

@ -509,13 +509,13 @@ class TestMemLogger : public Logger {
char* p = base; char* p = base;
char* limit = base + bufsize; char* limit = base + bufsize;
struct timeval now_tv; port::TimeVal now_tv;
gettimeofday(&now_tv, nullptr); port::GetTimeOfDay(&now_tv, nullptr);
const time_t seconds = now_tv.tv_sec; const time_t seconds = now_tv.tv_sec;
struct tm t; struct tm t;
memset(&t, 0, sizeof(t)); memset(&t, 0, sizeof(t));
struct tm* ret __attribute__((__unused__)); struct tm* ret __attribute__((__unused__));
ret = localtime_r(&seconds, &t); ret = port::LocalTimeR(&seconds, &t);
assert(ret); assert(ret);
p += snprintf(p, limit - p, "%04d/%02d/%02d-%02d:%02d:%02d.%06d ", p += snprintf(p, limit - p, "%04d/%02d/%02d-%02d:%02d:%02d.%06d ",
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,

View File

@ -100,11 +100,11 @@ class EnvLogger : public Logger {
char* p = base; char* p = base;
char* limit = base + bufsize; char* limit = base + bufsize;
struct timeval now_tv; port::TimeVal now_tv;
gettimeofday(&now_tv, nullptr); port::GetTimeOfDay(&now_tv, nullptr);
const time_t seconds = now_tv.tv_sec; const time_t seconds = now_tv.tv_sec;
struct tm t; struct tm t;
localtime_r(&seconds, &t); port::LocalTimeR(&seconds, &t);
p += snprintf(p, limit - p, "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ", p += snprintf(p, limit - p, "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
t.tm_min, t.tm_sec, static_cast<int>(now_tv.tv_usec), t.tm_min, t.tm_sec, static_cast<int>(now_tv.tv_usec),

View File

@ -27,7 +27,7 @@ void LogBuffer::AddLogToBuffer(size_t max_log_size, const char* format,
char* limit = alloc_mem + max_log_size - 1; char* limit = alloc_mem + max_log_size - 1;
// store the time // store the time
gettimeofday(&(buffered_log->now_tv), nullptr); port::GetTimeOfDay(&(buffered_log->now_tv), nullptr);
// Print the message // Print the message
if (p < limit) { if (p < limit) {
@ -60,7 +60,7 @@ void LogBuffer::FlushBufferToLog() {
for (BufferedLog* log : logs_) { for (BufferedLog* log : logs_) {
const time_t seconds = log->now_tv.tv_sec; const time_t seconds = log->now_tv.tv_sec;
struct tm t; struct tm t;
if (localtime_r(&seconds, &t) != nullptr) { if (port::LocalTimeR(&seconds, &t) != nullptr) {
Log(log_level_, info_log_, Log(log_level_, info_log_,
"(Original Log Time %04d/%02d/%02d-%02d:%02d:%02d.%06d) %s", "(Original Log Time %04d/%02d/%02d-%02d:%02d:%02d.%06d) %s",
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min,

View File

@ -35,7 +35,7 @@ class LogBuffer {
private: private:
// One log entry with its timestamp // One log entry with its timestamp
struct BufferedLog { struct BufferedLog {
struct timeval now_tv; // Timestamp of the log port::TimeVal now_tv; // Timestamp of the log
char message[1]; // Beginning of log message char message[1]; // Beginning of log message
}; };

View File

@ -103,11 +103,11 @@ class PosixLogger : public Logger {
char* p = base; char* p = base;
char* limit = base + bufsize; char* limit = base + bufsize;
struct timeval now_tv; port::TimeVal now_tv;
gettimeofday(&now_tv, nullptr); port::GetTimeOfDay(&now_tv, nullptr);
const time_t seconds = now_tv.tv_sec; const time_t seconds = now_tv.tv_sec;
struct tm t; struct tm t;
localtime_r(&seconds, &t); port::LocalTimeR(&seconds, &t);
p += snprintf(p, limit - p, "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llu ", p += snprintf(p, limit - p, "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llu ",
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour,
t.tm_min, t.tm_sec, static_cast<int>(now_tv.tv_usec), t.tm_min, t.tm_sec, static_cast<int>(now_tv.tv_usec),

View File

@ -12,36 +12,52 @@
#pragma once #pragma once
#if defined(OS_WIN) && defined(_MSC_VER) #include "rocksdb/rocksdb_namespace.h"
#if defined(OS_WIN) && (defined(_MSC_VER) || defined(__MINGW32__))
#include <time.h> #include <time.h>
#include "rocksdb/rocksdb_namespace.h"
namespace ROCKSDB_NAMESPACE { namespace ROCKSDB_NAMESPACE {
namespace port { namespace port {
// Avoid including winsock2.h for this definition struct TimeVal {
struct timeval {
long tv_sec; long tv_sec;
long tv_usec; long tv_usec;
}; };
void gettimeofday(struct timeval* tv, struct timezone* tz); void GetTimeOfDay(TimeVal* tv, struct timezone* tz);
inline struct tm* localtime_r(const time_t* timep, struct tm* result) { inline struct tm* LocalTimeR(const time_t* timep, struct tm* result) {
errno_t ret = localtime_s(result, timep); errno_t ret = localtime_s(result, timep);
return (ret == 0) ? result : NULL; return (ret == 0) ? result : NULL;
} }
}
using port::timeval; } // namespace port
using port::gettimeofday;
using port::localtime_r;
} // namespace ROCKSDB_NAMESPACE } // namespace ROCKSDB_NAMESPACE
#else #else
#include <time.h> #include <time.h>
#include <sys/time.h> #include <sys/time.h>
namespace ROCKSDB_NAMESPACE {
namespace port {
using TimeVal = struct timeval;
inline void GetTimeOfDay(TimeVal* tv, struct timezone* tz) {
gettimeofday(tv, tz);
}
inline struct tm* LocalTimeR(const time_t* timep, struct tm* result) {
return localtime_r(timep, result);
}
} // namespace port
} // namespace ROCKSDB_NAMESPACE
#endif #endif

View File

@ -52,7 +52,7 @@ std::wstring utf8_to_utf16(const std::string& utf8) {
} }
#endif #endif
void gettimeofday(struct timeval* tv, struct timezone* /* tz */) { void GetTimeOfDay(TimeVal* tv, struct timezone* /* tz */) {
std::chrono::microseconds usNow( std::chrono::microseconds usNow(
std::chrono::duration_cast<std::chrono::microseconds>( std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now().time_since_epoch())); std::chrono::system_clock::now().time_since_epoch()));

View File

@ -118,8 +118,8 @@ void WinLogger::Logv(const char* format, va_list ap) {
char* p = base; char* p = base;
char* limit = base + bufsize; char* limit = base + bufsize;
struct timeval now_tv; port::TimeVal now_tv;
gettimeofday(&now_tv, nullptr); port::GetTimeOfDay(&now_tv, nullptr);
const time_t seconds = now_tv.tv_sec; const time_t seconds = now_tv.tv_sec;
struct tm t; struct tm t;
localtime_s(&t, &seconds); localtime_s(&t, &seconds);

View File

@ -150,7 +150,7 @@ std::string TimeToHumanString(int unixtime) {
char time_buffer[80]; char time_buffer[80];
time_t rawtime = unixtime; time_t rawtime = unixtime;
struct tm tInfo; struct tm tInfo;
struct tm* timeinfo = localtime_r(&rawtime, &tInfo); struct tm* timeinfo = port::LocalTimeR(&rawtime, &tInfo);
assert(timeinfo == &tInfo); assert(timeinfo == &tInfo);
strftime(time_buffer, 80, "%c", timeinfo); strftime(time_buffer, 80, "%c", timeinfo);
return std::string(time_buffer); return std::string(time_buffer);

View File

@ -11,14 +11,16 @@
int main() { fprintf(stderr, "Please install gflags to run tools\n"); } int main() { fprintf(stderr, "Please install gflags to run tools\n"); }
#else #else
#include <sys/time.h>
#include <unistd.h>
#include <atomic> #include <atomic>
#include <functional> #include <functional>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <unistd.h>
#include <sys/time.h>
#include "port/port_posix.h" #include "port/port_posix.h"
#include "port/sys_time.h"
#include "rocksdb/env.h" #include "rocksdb/env.h"
#include "util/gflags_compat.h" #include "util/gflags_compat.h"
#include "util/mutexlock.h" #include "util/mutexlock.h"
@ -152,8 +154,8 @@ class HashTableBenchmark {
} }
static uint64_t NowInMillSec() { static uint64_t NowInMillSec() {
timeval tv; port::TimeVal tv;
gettimeofday(&tv, /*tz=*/nullptr); port::GetTimeOfDay(&tv, /*tz=*/nullptr);
return tv.tv_sec * 1000 + tv.tv_usec / 1000; return tv.tv_sec * 1000 + tv.tv_usec / 1000;
} }