| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685 | //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.//  This source code is licensed under both the GPLv2 (found in the//  COPYING file in the root directory) and Apache 2.0 License//  (found in the LICENSE.Apache file in the root directory).//#ifndef ROCKSDB_LITE#include "logging/auto_roll_logger.h"#include <errno.h>#include <sys/stat.h>#include <algorithm>#include <cmath>#include <fstream>#include <iostream>#include <iterator>#include <string>#include <thread>#include <vector>#include "logging/logging.h"#include "port/port.h"#include "rocksdb/db.h"#include "test_util/sync_point.h"#include "test_util/testharness.h"#include "test_util/testutil.h"namespace ROCKSDB_NAMESPACE {namespace {class NoSleepEnv : public EnvWrapper { public:  NoSleepEnv(Env* base) : EnvWrapper(base) {}  void SleepForMicroseconds(int micros) override {    fake_time_ += static_cast<uint64_t>(micros);  }  uint64_t NowNanos() override { return fake_time_ * 1000; }  uint64_t NowMicros() override { return fake_time_; } private:  uint64_t fake_time_ = 6666666666;};}  // namespace// In this test we only want to Log some simple log message with// no format. LogMessage() provides such a simple interface and// avoids the [format-security] warning which occurs when you// call ROCKS_LOG_INFO(logger, log_message) directly.namespace {void LogMessage(Logger* logger, const char* message) {  ROCKS_LOG_INFO(logger, "%s", message);}void LogMessage(const InfoLogLevel log_level, Logger* logger,                const char* message) {  Log(log_level, logger, "%s", message);}}  // namespaceclass AutoRollLoggerTest : public testing::Test { public:  static void InitTestDb() {#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);  }  void RollLogFileBySizeTest(AutoRollLogger* logger, size_t log_max_size,                             const std::string& log_message);  void RollLogFileByTimeTest(Env*, AutoRollLogger* logger, size_t time,                             const std::string& log_message);  // return list of files under kTestDir that contains "LOG"  std::vector<std::string> GetLogFiles() {    std::vector<std::string> ret;    std::vector<std::string> files;    Status s = default_env->GetChildren(kTestDir, &files);    // Should call ASSERT_OK() here but it doesn't compile. It's not    // worth the time figuring out why.    EXPECT_TRUE(s.ok());    for (const auto& f : files) {      if (f.find("LOG") != std::string::npos) {        ret.push_back(f);      }    }    return ret;  }  // Delete all log files under kTestDir  void CleanupLogFiles() {    for (const std::string& f : GetLogFiles()) {      ASSERT_OK(default_env->DeleteFile(kTestDir + "/" + f));    }  }  void RollNTimesBySize(Logger* auto_roll_logger, size_t file_num,                        size_t max_log_file_size) {    // Roll the log 4 times, and it will trim to 3 files.    std::string dummy_large_string;    dummy_large_string.assign(max_log_file_size, '=');    auto_roll_logger->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);    for (size_t i = 0; i < file_num + 1; i++) {      // Log enough bytes to trigger at least one roll.      LogMessage(auto_roll_logger, dummy_large_string.c_str());      LogMessage(auto_roll_logger, "");    }  }  static const std::string kSampleMessage;  static const std::string kTestDir;  static const std::string kLogFile;  static Env* default_env;};const std::string AutoRollLoggerTest::kSampleMessage(    "this is the message to be written to the log file!!");const std::string AutoRollLoggerTest::kTestDir(    test::PerThreadDBPath("db_log_test"));const std::string AutoRollLoggerTest::kLogFile(    test::PerThreadDBPath("db_log_test") + "/LOG");Env* AutoRollLoggerTest::default_env = Env::Default();void AutoRollLoggerTest::RollLogFileBySizeTest(AutoRollLogger* logger,                                               size_t log_max_size,                                               const std::string& log_message) {  logger->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);  ASSERT_EQ(InfoLogLevel::INFO_LEVEL, logger->GetInfoLogLevel());  ASSERT_EQ(InfoLogLevel::INFO_LEVEL,            logger->TEST_inner_logger()->GetInfoLogLevel());  // measure the size of each message, which is supposed  // to be equal or greater than log_message.size()  LogMessage(logger, log_message.c_str());  size_t message_size = logger->GetLogFileSize();  size_t current_log_size = message_size;  // Test the cases when the log file will not be rolled.  while (current_log_size + message_size < log_max_size) {    LogMessage(logger, log_message.c_str());    current_log_size += message_size;    ASSERT_EQ(current_log_size, logger->GetLogFileSize());  }  // Now the log file will be rolled  LogMessage(logger, log_message.c_str());  // Since rotation is checked before actual logging, we need to  // trigger the rotation by logging another message.  LogMessage(logger, log_message.c_str());  ASSERT_TRUE(message_size == logger->GetLogFileSize());}void AutoRollLoggerTest::RollLogFileByTimeTest(Env* env, AutoRollLogger* logger,                                               size_t time,                                               const std::string& log_message) {  uint64_t expected_ctime;  uint64_t actual_ctime;  uint64_t total_log_size;  EXPECT_OK(env->GetFileSize(kLogFile, &total_log_size));  expected_ctime = logger->TEST_ctime();  logger->SetCallNowMicrosEveryNRecords(0);  // -- Write to the log for several times, which is supposed  // to be finished before time.  for (int i = 0; i < 10; ++i) {    env->SleepForMicroseconds(50000);    LogMessage(logger, log_message.c_str());    EXPECT_OK(logger->GetStatus());    // Make sure we always write to the same log file (by    // checking the create time);    actual_ctime = logger->TEST_ctime();    // Also make sure the log size is increasing.    EXPECT_EQ(expected_ctime, actual_ctime);    EXPECT_GT(logger->GetLogFileSize(), total_log_size);    total_log_size = logger->GetLogFileSize();  }  // -- Make the log file expire  env->SleepForMicroseconds(static_cast<int>(time * 1000000));  LogMessage(logger, log_message.c_str());  // At this time, the new log file should be created.  actual_ctime = logger->TEST_ctime();  EXPECT_LT(expected_ctime, actual_ctime);  EXPECT_LT(logger->GetLogFileSize(), total_log_size);}TEST_F(AutoRollLoggerTest, RollLogFileBySize) {    InitTestDb();    size_t log_max_size = 1024 * 5;    size_t keep_log_file_num = 10;    AutoRollLogger logger(Env::Default(), kTestDir, "", log_max_size, 0,                          keep_log_file_num);    RollLogFileBySizeTest(&logger, log_max_size,                          kSampleMessage + ":RollLogFileBySize");}TEST_F(AutoRollLoggerTest, RollLogFileByTime) {  NoSleepEnv nse(Env::Default());  size_t time = 2;  size_t log_size = 1024 * 5;  size_t keep_log_file_num = 10;  InitTestDb();  // -- Test the existence of file during the server restart.  ASSERT_EQ(Status::NotFound(), default_env->FileExists(kLogFile));  AutoRollLogger logger(&nse, kTestDir, "", log_size, time, keep_log_file_num);  ASSERT_OK(default_env->FileExists(kLogFile));  RollLogFileByTimeTest(&nse, &logger, time,                        kSampleMessage + ":RollLogFileByTime");}TEST_F(AutoRollLoggerTest, SetInfoLogLevel) {  InitTestDb();  Options options;  options.info_log_level = InfoLogLevel::FATAL_LEVEL;  options.max_log_file_size = 1024;  std::shared_ptr<Logger> logger;  ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));  auto* auto_roll_logger = dynamic_cast<AutoRollLogger*>(logger.get());  ASSERT_NE(nullptr, auto_roll_logger);  ASSERT_EQ(InfoLogLevel::FATAL_LEVEL, auto_roll_logger->GetInfoLogLevel());  ASSERT_EQ(InfoLogLevel::FATAL_LEVEL,            auto_roll_logger->TEST_inner_logger()->GetInfoLogLevel());  auto_roll_logger->SetInfoLogLevel(InfoLogLevel::DEBUG_LEVEL);  ASSERT_EQ(InfoLogLevel::DEBUG_LEVEL, auto_roll_logger->GetInfoLogLevel());  ASSERT_EQ(InfoLogLevel::DEBUG_LEVEL, logger->GetInfoLogLevel());  ASSERT_EQ(InfoLogLevel::DEBUG_LEVEL,            auto_roll_logger->TEST_inner_logger()->GetInfoLogLevel());}TEST_F(AutoRollLoggerTest, OpenLogFilesMultipleTimesWithOptionLog_max_size) {  // If only 'log_max_size' options is specified, then every time  // when rocksdb is restarted, a new empty log file will be created.  InitTestDb();  // WORKAROUND:  // avoid complier's complaint of "comparison between signed  // and unsigned integer expressions" because literal 0 is  // treated as "singed".  size_t kZero = 0;  size_t log_size = 1024;  size_t keep_log_file_num = 10;  AutoRollLogger* logger = new AutoRollLogger(Env::Default(), kTestDir, "",                                              log_size, 0, keep_log_file_num);  LogMessage(logger, kSampleMessage.c_str());  ASSERT_GT(logger->GetLogFileSize(), kZero);  delete logger;  // reopens the log file and an empty log file will be created.  logger = new AutoRollLogger(Env::Default(), kTestDir, "", log_size, 0, 10);  ASSERT_EQ(logger->GetLogFileSize(), kZero);  delete logger;}TEST_F(AutoRollLoggerTest, CompositeRollByTimeAndSizeLogger) {  size_t time = 2, log_max_size = 1024 * 5;  size_t keep_log_file_num = 10;  InitTestDb();  NoSleepEnv nse(Env::Default());  AutoRollLogger logger(&nse, kTestDir, "", log_max_size, time,                        keep_log_file_num);  // Test the ability to roll by size  RollLogFileBySizeTest(&logger, log_max_size,                        kSampleMessage + ":CompositeRollByTimeAndSizeLogger");  // Test the ability to roll by Time  RollLogFileByTimeTest(&nse, &logger, time,                        kSampleMessage + ":CompositeRollByTimeAndSizeLogger");}#ifndef OS_WIN// TODO: does not build for Windows because of PosixLogger use below. Need to// portTEST_F(AutoRollLoggerTest, CreateLoggerFromOptions) {  DBOptions options;  NoSleepEnv nse(Env::Default());  std::shared_ptr<Logger> logger;  // Normal logger  ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));  ASSERT_TRUE(dynamic_cast<PosixLogger*>(logger.get()));  // Only roll by size  InitTestDb();  options.max_log_file_size = 1024;  ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));  AutoRollLogger* auto_roll_logger =    dynamic_cast<AutoRollLogger*>(logger.get());  ASSERT_TRUE(auto_roll_logger);  RollLogFileBySizeTest(      auto_roll_logger, options.max_log_file_size,      kSampleMessage + ":CreateLoggerFromOptions - size");  // Only roll by Time  options.env = &nse;  InitTestDb();  options.max_log_file_size = 0;  options.log_file_time_to_roll = 2;  ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));  auto_roll_logger =    dynamic_cast<AutoRollLogger*>(logger.get());  RollLogFileByTimeTest(&nse, auto_roll_logger, options.log_file_time_to_roll,                        kSampleMessage + ":CreateLoggerFromOptions - time");  // roll by both Time and size  InitTestDb();  options.max_log_file_size = 1024 * 5;  options.log_file_time_to_roll = 2;  ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));  auto_roll_logger =    dynamic_cast<AutoRollLogger*>(logger.get());  RollLogFileBySizeTest(auto_roll_logger, options.max_log_file_size,                        kSampleMessage + ":CreateLoggerFromOptions - both");  RollLogFileByTimeTest(&nse, auto_roll_logger, options.log_file_time_to_roll,                        kSampleMessage + ":CreateLoggerFromOptions - both");  // Set keep_log_file_num  {    const size_t kFileNum = 3;    InitTestDb();    options.max_log_file_size = 512;    options.log_file_time_to_roll = 2;    options.keep_log_file_num = kFileNum;    ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));    auto_roll_logger = dynamic_cast<AutoRollLogger*>(logger.get());    // Roll the log 4 times, and it will trim to 3 files.    std::string dummy_large_string;    dummy_large_string.assign(options.max_log_file_size, '=');    auto_roll_logger->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);    for (size_t i = 0; i < kFileNum + 1; i++) {      // Log enough bytes to trigger at least one roll.      LogMessage(auto_roll_logger, dummy_large_string.c_str());      LogMessage(auto_roll_logger, "");    }    std::vector<std::string> files = GetLogFiles();    ASSERT_EQ(kFileNum, files.size());    CleanupLogFiles();  }  // Set keep_log_file_num and dbname is different from  // db_log_dir.  {    const size_t kFileNum = 3;    InitTestDb();    options.max_log_file_size = 512;    options.log_file_time_to_roll = 2;    options.keep_log_file_num = kFileNum;    options.db_log_dir = kTestDir;    ASSERT_OK(CreateLoggerFromOptions("/dummy/db/name", options, &logger));    auto_roll_logger = dynamic_cast<AutoRollLogger*>(logger.get());    // Roll the log 4 times, and it will trim to 3 files.    std::string dummy_large_string;    dummy_large_string.assign(options.max_log_file_size, '=');    auto_roll_logger->SetInfoLogLevel(InfoLogLevel::INFO_LEVEL);    for (size_t i = 0; i < kFileNum + 1; i++) {      // Log enough bytes to trigger at least one roll.      LogMessage(auto_roll_logger, dummy_large_string.c_str());      LogMessage(auto_roll_logger, "");    }    std::vector<std::string> files = GetLogFiles();    ASSERT_EQ(kFileNum, files.size());    for (const auto& f : files) {      ASSERT_TRUE(f.find("dummy") != std::string::npos);    }    // Cleaning up those files.    CleanupLogFiles();  }}TEST_F(AutoRollLoggerTest, AutoDeleting) {  for (int attempt = 0; attempt < 2; attempt++) {    // In the first attemp, db_log_dir is not set, while in the    // second it is set.    std::string dbname = (attempt == 0) ? kTestDir : "/test/dummy/dir";    std::string db_log_dir = (attempt == 0) ? "" : kTestDir;    InitTestDb();    const size_t kMaxFileSize = 512;    {      size_t log_num = 8;      AutoRollLogger logger(Env::Default(), dbname, db_log_dir, kMaxFileSize, 0,                            log_num);      RollNTimesBySize(&logger, log_num, kMaxFileSize);      ASSERT_EQ(log_num, GetLogFiles().size());    }    // Shrink number of files    {      size_t log_num = 5;      AutoRollLogger logger(Env::Default(), dbname, db_log_dir, kMaxFileSize, 0,                            log_num);      ASSERT_EQ(log_num, GetLogFiles().size());      RollNTimesBySize(&logger, 3, kMaxFileSize);      ASSERT_EQ(log_num, GetLogFiles().size());    }    // Increase number of files again.    {      size_t log_num = 7;      AutoRollLogger logger(Env::Default(), dbname, db_log_dir, kMaxFileSize, 0,                            log_num);      ASSERT_EQ(6, GetLogFiles().size());      RollNTimesBySize(&logger, 3, kMaxFileSize);      ASSERT_EQ(log_num, GetLogFiles().size());    }    CleanupLogFiles();  }}TEST_F(AutoRollLoggerTest, LogFlushWhileRolling) {  DBOptions options;  std::shared_ptr<Logger> logger;  InitTestDb();  options.max_log_file_size = 1024 * 5;  ASSERT_OK(CreateLoggerFromOptions(kTestDir, options, &logger));  AutoRollLogger* auto_roll_logger =      dynamic_cast<AutoRollLogger*>(logger.get());  ASSERT_TRUE(auto_roll_logger);  ROCKSDB_NAMESPACE::port::Thread flush_thread;  // Notes:  // (1) Need to pin the old logger before beginning the roll, as rolling grabs  //     the mutex, which would prevent us from accessing the old logger. This  //     also marks flush_thread with AutoRollLogger::Flush:PinnedLogger.  // (2) Need to reset logger during PosixLogger::Flush() to exercise a race  //     condition case, which is executing the flush with the pinned (old)  //     logger after auto-roll logger has cut over to a new logger.  // (3) PosixLogger::Flush() happens in both threads but its SyncPoints only  //     are enabled in flush_thread (the one pinning the old logger).  ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependencyAndMarkers(      {{"AutoRollLogger::Flush:PinnedLogger",        "AutoRollLoggerTest::LogFlushWhileRolling:PreRollAndPostThreadInit"},       {"PosixLogger::Flush:Begin1",        "AutoRollLogger::ResetLogger:BeforeNewLogger"},       {"AutoRollLogger::ResetLogger:AfterNewLogger",        "PosixLogger::Flush:Begin2"}},      {{"AutoRollLogger::Flush:PinnedLogger", "PosixLogger::Flush:Begin1"},       {"AutoRollLogger::Flush:PinnedLogger", "PosixLogger::Flush:Begin2"}});  ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();  flush_thread = port::Thread([&]() { auto_roll_logger->Flush(); });  TEST_SYNC_POINT(      "AutoRollLoggerTest::LogFlushWhileRolling:PreRollAndPostThreadInit");  RollLogFileBySizeTest(auto_roll_logger, options.max_log_file_size,                        kSampleMessage + ":LogFlushWhileRolling");  flush_thread.join();  ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();}#endif  // OS_WINTEST_F(AutoRollLoggerTest, InfoLogLevel) {  InitTestDb();  size_t log_size = 8192;  size_t log_lines = 0;  // an extra-scope to force the AutoRollLogger to flush the log file when it  // becomes out of scope.  {    AutoRollLogger logger(Env::Default(), kTestDir, "", log_size, 0, 10);    for (int log_level = InfoLogLevel::HEADER_LEVEL;         log_level >= InfoLogLevel::DEBUG_LEVEL; log_level--) {      logger.SetInfoLogLevel((InfoLogLevel)log_level);      for (int log_type = InfoLogLevel::DEBUG_LEVEL;           log_type <= InfoLogLevel::HEADER_LEVEL; log_type++) {        // log messages with log level smaller than log_level will not be        // logged.        LogMessage((InfoLogLevel)log_type, &logger, kSampleMessage.c_str());      }      log_lines += InfoLogLevel::HEADER_LEVEL - log_level + 1;    }    for (int log_level = InfoLogLevel::HEADER_LEVEL;         log_level >= InfoLogLevel::DEBUG_LEVEL; log_level--) {      logger.SetInfoLogLevel((InfoLogLevel)log_level);      // again, messages with level smaller than log_level will not be logged.      ROCKS_LOG_HEADER(&logger, "%s", kSampleMessage.c_str());      ROCKS_LOG_DEBUG(&logger, "%s", kSampleMessage.c_str());      ROCKS_LOG_INFO(&logger, "%s", kSampleMessage.c_str());      ROCKS_LOG_WARN(&logger, "%s", kSampleMessage.c_str());      ROCKS_LOG_ERROR(&logger, "%s", kSampleMessage.c_str());      ROCKS_LOG_FATAL(&logger, "%s", kSampleMessage.c_str());      log_lines += InfoLogLevel::HEADER_LEVEL - log_level + 1;    }  }  std::ifstream inFile(AutoRollLoggerTest::kLogFile.c_str());  size_t lines = std::count(std::istreambuf_iterator<char>(inFile),                         std::istreambuf_iterator<char>(), '\n');  ASSERT_EQ(log_lines, lines);  inFile.close();}TEST_F(AutoRollLoggerTest, Close) {  InitTestDb();  size_t log_size = 8192;  size_t log_lines = 0;  AutoRollLogger logger(Env::Default(), kTestDir, "", log_size, 0, 10);  for (int log_level = InfoLogLevel::HEADER_LEVEL;       log_level >= InfoLogLevel::DEBUG_LEVEL; log_level--) {    logger.SetInfoLogLevel((InfoLogLevel)log_level);    for (int log_type = InfoLogLevel::DEBUG_LEVEL;         log_type <= InfoLogLevel::HEADER_LEVEL; log_type++) {      // log messages with log level smaller than log_level will not be      // logged.      LogMessage((InfoLogLevel)log_type, &logger, kSampleMessage.c_str());    }    log_lines += InfoLogLevel::HEADER_LEVEL - log_level + 1;  }  for (int log_level = InfoLogLevel::HEADER_LEVEL;       log_level >= InfoLogLevel::DEBUG_LEVEL; log_level--) {    logger.SetInfoLogLevel((InfoLogLevel)log_level);    // again, messages with level smaller than log_level will not be logged.    ROCKS_LOG_HEADER(&logger, "%s", kSampleMessage.c_str());    ROCKS_LOG_DEBUG(&logger, "%s", kSampleMessage.c_str());    ROCKS_LOG_INFO(&logger, "%s", kSampleMessage.c_str());    ROCKS_LOG_WARN(&logger, "%s", kSampleMessage.c_str());    ROCKS_LOG_ERROR(&logger, "%s", kSampleMessage.c_str());    ROCKS_LOG_FATAL(&logger, "%s", kSampleMessage.c_str());    log_lines += InfoLogLevel::HEADER_LEVEL - log_level + 1;  }  ASSERT_EQ(logger.Close(), Status::OK());  std::ifstream inFile(AutoRollLoggerTest::kLogFile.c_str());  size_t lines = std::count(std::istreambuf_iterator<char>(inFile),                         std::istreambuf_iterator<char>(), '\n');  ASSERT_EQ(log_lines, lines);  inFile.close();}// Test the logger Header function for roll over logs// We expect the new logs creates as roll over to carry the headers specifiedstatic std::vector<std::string> GetOldFileNames(const std::string& path) {  std::vector<std::string> ret;  const std::string dirname = path.substr(/*start=*/0, path.find_last_of("/"));  const std::string fname = path.substr(path.find_last_of("/") + 1);  std::vector<std::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  for (auto& child : children) {    if (fname != child && child.find(fname) == 0) {      ret.push_back(dirname + "/" + child);    }  }  return ret;}TEST_F(AutoRollLoggerTest, LogHeaderTest) {  static const size_t MAX_HEADERS = 10;  static const size_t LOG_MAX_SIZE = 1024 * 5;  static const std::string HEADER_STR = "Log header line";  // test_num == 0 -> standard call to Header()  // test_num == 1 -> call to Log() with InfoLogLevel::HEADER_LEVEL  for (int test_num = 0; test_num < 2; test_num++) {    InitTestDb();    AutoRollLogger logger(Env::Default(), kTestDir, /*db_log_dir=*/"",                          LOG_MAX_SIZE, /*log_file_time_to_roll=*/0,                          /*keep_log_file_num=*/10);    if (test_num == 0) {      // Log some headers explicitly using Header()      for (size_t i = 0; i < MAX_HEADERS; i++) {        Header(&logger, "%s %" ROCKSDB_PRIszt, HEADER_STR.c_str(), i);      }    } else if (test_num == 1) {      // HEADER_LEVEL should make this behave like calling Header()      for (size_t i = 0; i < MAX_HEADERS; i++) {        ROCKS_LOG_HEADER(&logger, "%s %" ROCKSDB_PRIszt, HEADER_STR.c_str(), i);      }    }    const std::string newfname = logger.TEST_log_fname();    // Log enough data to cause a roll over    int i = 0;    for (size_t iter = 0; iter < 2; iter++) {      while (logger.GetLogFileSize() < LOG_MAX_SIZE) {        Info(&logger, (kSampleMessage + ":LogHeaderTest line %d").c_str(), i);        ++i;      }      Info(&logger, "Rollover");    }    // Flush the log for the latest file    LogFlush(&logger);    const auto oldfiles = GetOldFileNames(newfname);    ASSERT_EQ(oldfiles.size(), (size_t) 2);    for (auto& oldfname : oldfiles) {      // verify that the files rolled over      ASSERT_NE(oldfname, newfname);      // verify that the old log contains all the header logs      ASSERT_EQ(test::GetLinesCount(oldfname, HEADER_STR), MAX_HEADERS);    }  }}TEST_F(AutoRollLoggerTest, LogFileExistence) {  ROCKSDB_NAMESPACE::DB* db;  ROCKSDB_NAMESPACE::Options options;#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_EQ(system(deleteCmd.c_str()), 0);  options.max_log_file_size = 100 * 1024 * 1024;  options.create_if_missing = true;  ASSERT_OK(ROCKSDB_NAMESPACE::DB::Open(options, kTestDir, &db));  ASSERT_OK(default_env->FileExists(kLogFile));  delete db;}TEST_F(AutoRollLoggerTest, FileCreateFailure) {  Options options;  options.max_log_file_size = 100 * 1024 * 1024;  options.db_log_dir = "/a/dir/does/not/exist/at/all";  std::shared_ptr<Logger> logger;  ASSERT_NOK(CreateLoggerFromOptions("", options, &logger));  ASSERT_TRUE(!logger);}}  // namespace ROCKSDB_NAMESPACEint main(int argc, char** argv) {  ::testing::InitGoogleTest(&argc, argv);  return RUN_ALL_TESTS();}#else#include <stdio.h>int main(int /*argc*/, char** /*argv*/) {  fprintf(stderr,          "SKIPPED as AutoRollLogger is not supported in ROCKSDB_LITE\n");  return 0;}#endif  // !ROCKSDB_LITE
 |