]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/util/auto_roll_logger.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rocksdb / util / auto_roll_logger.cc
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5 //
6 #include "util/auto_roll_logger.h"
7 #include "util/mutexlock.h"
8
9 namespace rocksdb {
10
11 #ifndef ROCKSDB_LITE
12 // -- AutoRollLogger
13 Status AutoRollLogger::ResetLogger() {
14 TEST_SYNC_POINT("AutoRollLogger::ResetLogger:BeforeNewLogger");
15 status_ = env_->NewLogger(log_fname_, &logger_);
16 TEST_SYNC_POINT("AutoRollLogger::ResetLogger:AfterNewLogger");
17
18 if (!status_.ok()) {
19 return status_;
20 }
21
22 if (logger_->GetLogFileSize() == Logger::kDoNotSupportGetLogFileSize) {
23 status_ = Status::NotSupported(
24 "The underlying logger doesn't support GetLogFileSize()");
25 }
26 if (status_.ok()) {
27 cached_now = static_cast<uint64_t>(env_->NowMicros() * 1e-6);
28 ctime_ = cached_now;
29 cached_now_access_count = 0;
30 }
31
32 return status_;
33 }
34
35 void AutoRollLogger::RollLogFile() {
36 // This function is called when log is rotating. Two rotations
37 // can happen quickly (NowMicro returns same value). To not overwrite
38 // previous log file we increment by one micro second and try again.
39 uint64_t now = env_->NowMicros();
40 std::string old_fname;
41 do {
42 old_fname = OldInfoLogFileName(
43 dbname_, now, db_absolute_path_, db_log_dir_);
44 now++;
45 } while (env_->FileExists(old_fname).ok());
46 env_->RenameFile(log_fname_, old_fname);
47 }
48
49 std::string AutoRollLogger::ValistToString(const char* format,
50 va_list args) const {
51 // Any log messages longer than 1024 will get truncated.
52 // The user is responsible for chopping longer messages into multi line log
53 static const int MAXBUFFERSIZE = 1024;
54 char buffer[MAXBUFFERSIZE];
55
56 int count = vsnprintf(buffer, MAXBUFFERSIZE, format, args);
57 (void) count;
58 assert(count >= 0);
59
60 return buffer;
61 }
62
63 void AutoRollLogger::LogInternal(const char* format, ...) {
64 mutex_.AssertHeld();
65 va_list args;
66 va_start(args, format);
67 logger_->Logv(format, args);
68 va_end(args);
69 }
70
71 void AutoRollLogger::Logv(const char* format, va_list ap) {
72 assert(GetStatus().ok());
73
74 std::shared_ptr<Logger> logger;
75 {
76 MutexLock l(&mutex_);
77 if ((kLogFileTimeToRoll > 0 && LogExpired()) ||
78 (kMaxLogFileSize > 0 && logger_->GetLogFileSize() >= kMaxLogFileSize)) {
79 RollLogFile();
80 Status s = ResetLogger();
81 if (!s.ok()) {
82 // can't really log the error if creating a new LOG file failed
83 return;
84 }
85
86 WriteHeaderInfo();
87 }
88
89 // pin down the current logger_ instance before releasing the mutex.
90 logger = logger_;
91 }
92
93 // Another thread could have put a new Logger instance into logger_ by now.
94 // However, since logger is still hanging on to the previous instance
95 // (reference count is not zero), we don't have to worry about it being
96 // deleted while we are accessing it.
97 // Note that logv itself is not mutex protected to allow maximum concurrency,
98 // as thread safety should have been handled by the underlying logger.
99 logger->Logv(format, ap);
100 }
101
102 void AutoRollLogger::WriteHeaderInfo() {
103 mutex_.AssertHeld();
104 for (auto& header : headers_) {
105 LogInternal("%s", header.c_str());
106 }
107 }
108
109 void AutoRollLogger::LogHeader(const char* format, va_list args) {
110 // header message are to be retained in memory. Since we cannot make any
111 // assumptions about the data contained in va_list, we will retain them as
112 // strings
113 va_list tmp;
114 va_copy(tmp, args);
115 std::string data = ValistToString(format, tmp);
116 va_end(tmp);
117
118 MutexLock l(&mutex_);
119 headers_.push_back(data);
120
121 // Log the original message to the current log
122 logger_->Logv(format, args);
123 }
124
125 bool AutoRollLogger::LogExpired() {
126 if (cached_now_access_count >= call_NowMicros_every_N_records_) {
127 cached_now = static_cast<uint64_t>(env_->NowMicros() * 1e-6);
128 cached_now_access_count = 0;
129 }
130
131 ++cached_now_access_count;
132 return cached_now >= ctime_ + kLogFileTimeToRoll;
133 }
134 #endif // !ROCKSDB_LITE
135
136 Status CreateLoggerFromOptions(const std::string& dbname,
137 const DBOptions& options,
138 std::shared_ptr<Logger>* logger) {
139 if (options.info_log) {
140 *logger = options.info_log;
141 return Status::OK();
142 }
143
144 Env* env = options.env;
145 std::string db_absolute_path;
146 env->GetAbsolutePath(dbname, &db_absolute_path);
147 std::string fname =
148 InfoLogFileName(dbname, db_absolute_path, options.db_log_dir);
149
150 env->CreateDirIfMissing(dbname); // In case it does not exist
151 // Currently we only support roll by time-to-roll and log size
152 #ifndef ROCKSDB_LITE
153 if (options.log_file_time_to_roll > 0 || options.max_log_file_size > 0) {
154 AutoRollLogger* result = new AutoRollLogger(
155 env, dbname, options.db_log_dir, options.max_log_file_size,
156 options.log_file_time_to_roll, options.info_log_level);
157 Status s = result->GetStatus();
158 if (!s.ok()) {
159 delete result;
160 } else {
161 logger->reset(result);
162 }
163 return s;
164 }
165 #endif // !ROCKSDB_LITE
166 // Open a log file in the same directory as the db
167 env->RenameFile(fname,
168 OldInfoLogFileName(dbname, env->NowMicros(), db_absolute_path,
169 options.db_log_dir));
170 auto s = env->NewLogger(fname, logger);
171 if (logger->get() != nullptr) {
172 (*logger)->SetInfoLogLevel(options.info_log_level);
173 }
174 return s;
175 }
176
177 } // namespace rocksdb