Fix WinEnv::NowMicrosec

* std::chrono does not provide enough granularity for microsecs and periodically emits
    duplicates
  * the bug is manifested in log rotation logic where we get duplicate
   log file names and loose previous log content
  * msvc does not imlement COW on std::strings adjusted the test to use
    refs in the loops as auto does not retain ref info
  * adjust auto_log rotation test with Windows specific command to remove
    a folder. The test previously worked because we have unix utils installed
    in house but this may not be the case for everyone.
main
Dmitri Smirnov 9 years ago
parent fe09a6dae3
commit 555ca3e7b7
  1. 13
      port/win/env_win.cc
  2. 2
      util/auto_roll_logger.cc
  3. 27
      util/auto_roll_logger_test.cc

@ -1976,9 +1976,16 @@ class WinEnv : public Env {
} }
virtual uint64_t NowMicros() override { virtual uint64_t NowMicros() override {
using namespace std::chrono; // all std::chrono clocks on windows have the same resolution that is only
return duration_cast<microseconds>(system_clock::now().time_since_epoch()) // On Windows 8 and Windows 2012 Server
.count(); // GetSystemTimePreciseAsFileTime(&current_time) can be used
LARGE_INTEGER li;
QueryPerformanceCounter(&li);
// Convert to nanoseconds first to avoid loss of precision
// and divide by frequency
li.QuadPart *= std::micro::den;
li.QuadPart /= perf_counter_frequency_;
return li.QuadPart;
} }
virtual uint64_t NowNanos() override { virtual uint64_t NowNanos() override {

@ -91,7 +91,7 @@ void AutoRollLogger::Logv(const char* format, va_list ap) {
void AutoRollLogger::WriteHeaderInfo() { void AutoRollLogger::WriteHeaderInfo() {
mutex_.AssertHeld(); mutex_.AssertHeld();
for (auto header : headers_) { for (auto& header : headers_) {
LogInternal("%s", header.c_str()); LogInternal("%s", header.c_str());
} }
} }

@ -23,7 +23,17 @@ namespace rocksdb {
class AutoRollLoggerTest : public testing::Test { class AutoRollLoggerTest : public testing::Test {
public: public:
static void InitTestDb() { static void InitTestDb() {
string deleteCmd = "rm -rf " + kTestDir; #ifdef OS_WIN
// Replace all slashes in the path so windows CompSpec does not
// become confused
std::string testDir(kTestDir);
std::replace_if(testDir.begin(), testDir.end(),
[](char ch) { return ch == '/'; },
'\\');
std::string deleteCmd = "if exist " + testDir + " rd /s /q " + testDir;
#else
std::string deleteCmd = "rm -rf " + kTestDir;
#endif
ASSERT_TRUE(system(deleteCmd.c_str()) == 0); ASSERT_TRUE(system(deleteCmd.c_str()) == 0);
Env::Default()->CreateDir(kTestDir); Env::Default()->CreateDir(kTestDir);
} }
@ -296,17 +306,18 @@ TEST_F(AutoRollLoggerTest, InfoLogLevel) {
// Test the logger Header function for roll over logs // Test the logger Header function for roll over logs
// We expect the new logs creates as roll over to carry the headers specified // We expect the new logs creates as roll over to carry the headers specified
static list<string> GetOldFileNames(const string& path) { static std::vector<string> GetOldFileNames(const string& path) {
std::vector<string> ret;
const string dirname = path.substr(/*start=*/ 0, path.find_last_of("/")); const string dirname = path.substr(/*start=*/ 0, path.find_last_of("/"));
const string fname = path.substr(path.find_last_of("/") + 1); const string fname = path.substr(path.find_last_of("/") + 1);
vector<string> children; std::vector<string> children;
Env::Default()->GetChildren(dirname, &children); Env::Default()->GetChildren(dirname, &children);
// We know that the old log files are named [path]<something> // We know that the old log files are named [path]<something>
// Return all entities that match the pattern // Return all entities that match the pattern
list<string> ret; for (auto& child : children) {
for (auto child : children) {
if (fname != child && child.find(fname) == 0) { if (fname != child && child.find(fname) == 0) {
ret.push_back(dirname + "/" + child); ret.push_back(dirname + "/" + child);
} }
@ -360,7 +371,7 @@ TEST_F(AutoRollLoggerTest, LogHeaderTest) {
} }
} }
const string& newfname = logger.TEST_log_fname().c_str(); const string newfname = logger.TEST_log_fname();
// Log enough data to cause a roll over // Log enough data to cause a roll over
int i = 0; int i = 0;
@ -376,11 +387,11 @@ TEST_F(AutoRollLoggerTest, LogHeaderTest) {
// Flush the log for the latest file // Flush the log for the latest file
LogFlush(&logger); LogFlush(&logger);
const list<string> oldfiles = GetOldFileNames(newfname); const auto oldfiles = GetOldFileNames(newfname);
ASSERT_EQ(oldfiles.size(), (size_t) 2); ASSERT_EQ(oldfiles.size(), (size_t) 2);
for (auto oldfname : oldfiles) { for (auto& oldfname : oldfiles) {
// verify that the files rolled over // verify that the files rolled over
ASSERT_NE(oldfname, newfname); ASSERT_NE(oldfname, newfname);
// verify that the old log contains all the header logs // verify that the old log contains all the header logs

Loading…
Cancel
Save