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.
This commit is contained in:
Dmitri Smirnov 2015-07-22 14:36:43 -07:00
parent fe09a6dae3
commit 555ca3e7b7
3 changed files with 30 additions and 12 deletions

View File

@ -1976,9 +1976,16 @@ class WinEnv : public Env {
}
virtual uint64_t NowMicros() override {
using namespace std::chrono;
return duration_cast<microseconds>(system_clock::now().time_since_epoch())
.count();
// all std::chrono clocks on windows have the same resolution that is only
// On Windows 8 and Windows 2012 Server
// 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 {

View File

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

View File

@ -23,7 +23,17 @@ namespace rocksdb {
class AutoRollLoggerTest : public testing::Test {
public:
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);
Env::Default()->CreateDir(kTestDir);
}
@ -296,17 +306,18 @@ TEST_F(AutoRollLoggerTest, InfoLogLevel) {
// Test the logger Header function for roll over logs
// 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 fname = path.substr(path.find_last_of("/") + 1);
vector<string> children;
std::vector<string> children;
Env::Default()->GetChildren(dirname, &children);
// We know that the old log files are named [path]<something>
// 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) {
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
int i = 0;
@ -376,11 +387,11 @@ TEST_F(AutoRollLoggerTest, LogHeaderTest) {
// Flush the log for the latest file
LogFlush(&logger);
const list<string> oldfiles = GetOldFileNames(newfname);
const auto oldfiles = GetOldFileNames(newfname);
ASSERT_EQ(oldfiles.size(), (size_t) 2);
for (auto oldfname : oldfiles) {
for (auto& oldfname : oldfiles) {
// verify that the files rolled over
ASSERT_NE(oldfname, newfname);
// verify that the old log contains all the header logs