summaryrefslogtreecommitdiffstats
path: root/src/rocksdb/logging/auto_roll_logger.h
blob: 805925e5a8ad1c6b8ca7eac76983509e98f453f7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
//  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).
//
// Logger implementation that can be shared by all environments
// where enough posix functionality is available.

#pragma once
#include <list>
#include <queue>
#include <string>

#include "file/filename.h"
#include "port/port.h"
#include "port/util_logger.h"
#include "test_util/sync_point.h"
#include "util/mutexlock.h"

namespace ROCKSDB_NAMESPACE {
class FileSystem;
class SystemClock;

#ifndef ROCKSDB_LITE
// Rolls the log file by size and/or time
class AutoRollLogger : public Logger {
 public:
  AutoRollLogger(const std::shared_ptr<FileSystem>& fs,
                 const std::shared_ptr<SystemClock>& clock,
                 const std::string& dbname, const std::string& db_log_dir,
                 size_t log_max_size, size_t log_file_time_to_roll,
                 size_t keep_log_file_num,
                 const InfoLogLevel log_level = InfoLogLevel::INFO_LEVEL);

  using Logger::Logv;
  void Logv(const char* format, va_list ap) override;

  // Write a header entry to the log. All header information will be written
  // again every time the log rolls over.
  virtual void LogHeader(const char* format, va_list ap) override;

  // check if the logger has encountered any problem.
  Status GetStatus() { return status_; }

  size_t GetLogFileSize() const override {
    if (!logger_) {
      return 0;
    }

    std::shared_ptr<Logger> logger;
    {
      MutexLock l(&mutex_);
      // pin down the current logger_ instance before releasing the mutex.
      logger = logger_;
    }
    return logger->GetLogFileSize();
  }

  void Flush() override {
    std::shared_ptr<Logger> logger;
    {
      MutexLock l(&mutex_);
      // pin down the current logger_ instance before releasing the mutex.
      logger = logger_;
    }
    TEST_SYNC_POINT("AutoRollLogger::Flush:PinnedLogger");
    if (logger) {
      logger->Flush();
    }
  }

  virtual ~AutoRollLogger() {
    if (logger_ && !closed_) {
      logger_->Close().PermitUncheckedError();
    }
    status_.PermitUncheckedError();
  }

  using Logger::GetInfoLogLevel;
  InfoLogLevel GetInfoLogLevel() const override {
    MutexLock l(&mutex_);
    if (!logger_) {
      return Logger::GetInfoLogLevel();
    }
    return logger_->GetInfoLogLevel();
  }

  using Logger::SetInfoLogLevel;
  void SetInfoLogLevel(const InfoLogLevel log_level) override {
    MutexLock lock(&mutex_);
    Logger::SetInfoLogLevel(log_level);
    if (logger_) {
      logger_->SetInfoLogLevel(log_level);
    }
  }

  void SetCallNowMicrosEveryNRecords(uint64_t call_NowMicros_every_N_records) {
    call_NowMicros_every_N_records_ = call_NowMicros_every_N_records;
  }

  // Expose the log file path for testing purpose
  std::string TEST_log_fname() const { return log_fname_; }

  uint64_t TEST_ctime() const { return ctime_; }

  Logger* TEST_inner_logger() const { return logger_.get(); }

 protected:
  // Implementation of Close()
  virtual Status CloseImpl() override {
    if (logger_) {
      return logger_->Close();
    } else {
      return Status::OK();
    }
  }

 private:
  bool LogExpired();
  Status ResetLogger();
  void RollLogFile();
  // Read all names of old log files into old_log_files_
  // If there is any error, put the error code in status_
  void GetExistingFiles();
  // Delete old log files if it excceeds the limit.
  Status TrimOldLogFiles();
  // Log message to logger without rolling
  void LogInternal(const char* format, ...);
  // Serialize the va_list to a string
  std::string ValistToString(const char* format, va_list args) const;
  // Write the logs marked as headers to the new log file
  void WriteHeaderInfo();
  std::string log_fname_;  // Current active info log's file name.
  std::string dbname_;
  std::string db_log_dir_;
  std::string db_absolute_path_;
  std::shared_ptr<FileSystem> fs_;
  std::shared_ptr<SystemClock> clock_;
  std::shared_ptr<Logger> logger_;
  // current status of the logger
  Status status_;
  const size_t kMaxLogFileSize;
  const size_t kLogFileTimeToRoll;
  const size_t kKeepLogFileNum;
  // header information
  std::list<std::string> headers_;
  // List of all existing info log files. Used for enforcing number of
  // info log files.
  // Full path is stored here. It consumes signifianctly more memory
  // than only storing file name. Can optimize if it causes a problem.
  std::queue<std::string> old_log_files_;
  // to avoid frequent clock->NowMicros() calls, we cached the current time
  uint64_t cached_now;
  uint64_t ctime_;
  uint64_t cached_now_access_count;
  uint64_t call_NowMicros_every_N_records_;
  IOOptions io_options_;
  IODebugContext io_context_;
  mutable port::Mutex mutex_;
};
#endif  // !ROCKSDB_LITE

// Facade to craete logger automatically
Status CreateLoggerFromOptions(const std::string& dbname,
                               const DBOptions& options,
                               std::shared_ptr<Logger>* logger);

}  // namespace ROCKSDB_NAMESPACE