1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under the BSD-style license found in the
3 // LICENSE file in the root directory of this source tree. An additional grant
4 // of patent rights can be found in the PATENTS file in the same directory.
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
10 // Logger implementation that can be shared by all environments
11 // where enough posix functionality is available.
16 #include "port/sys_time.h"
21 #ifndef FALLOC_FL_KEEP_SIZE
22 #include <linux/falloc.h>
27 #include "monitoring/iostats_context_imp.h"
28 #include "rocksdb/env.h"
29 #include "util/sync_point.h"
33 class PosixLogger
: public Logger
{
36 uint64_t (*gettid_
)(); // Return the thread id for the current thread
37 std::atomic_size_t log_size_
;
39 const static uint64_t flush_every_seconds_
= 5;
40 std::atomic_uint_fast64_t last_flush_micros_
;
44 PosixLogger(FILE* f
, uint64_t (*gettid
)(), Env
* env
,
45 const InfoLogLevel log_level
= InfoLogLevel::ERROR_LEVEL
)
51 last_flush_micros_(0),
53 flush_pending_(false) {}
54 virtual ~PosixLogger() {
57 virtual void Flush() override
{
58 TEST_SYNC_POINT("PosixLogger::Flush:Begin1");
59 TEST_SYNC_POINT("PosixLogger::Flush:Begin2");
61 flush_pending_
= false;
64 last_flush_micros_
= env_
->NowMicros();
68 virtual void Logv(const char* format
, va_list ap
) override
{
69 IOSTATS_TIMER_GUARD(logger_nanos
);
71 const uint64_t thread_id
= (*gettid_
)();
73 // We try twice: the first time with a fixed-size stack allocated buffer,
74 // and the second time with a much larger dynamically allocated buffer.
76 for (int iter
= 0; iter
< 2; iter
++) {
80 bufsize
= sizeof(buffer
);
84 base
= new char[bufsize
];
87 char* limit
= base
+ bufsize
;
89 struct timeval now_tv
;
90 gettimeofday(&now_tv
, nullptr);
91 const time_t seconds
= now_tv
.tv_sec
;
93 localtime_r(&seconds
, &t
);
94 p
+= snprintf(p
, limit
- p
,
95 "%04d/%02d/%02d-%02d:%02d:%02d.%06d %llx ",
102 static_cast<int>(now_tv
.tv_usec
),
103 static_cast<long long unsigned int>(thread_id
));
108 va_copy(backup_ap
, ap
);
109 p
+= vsnprintf(p
, limit
- p
, format
, backup_ap
);
113 // Truncate to available space if necessary
116 continue; // Try again with larger buffer
122 // Add newline if necessary
123 if (p
== base
|| p
[-1] != '\n') {
128 const size_t write_size
= p
- base
;
130 #ifdef ROCKSDB_FALLOCATE_PRESENT
131 const int kDebugLogChunkSize
= 128 * 1024;
133 // If this write would cross a boundary of kDebugLogChunkSize
134 // space, pre-allocate more space to avoid overly large
135 // allocations from filesystem allocsize options.
136 const size_t log_size
= log_size_
;
137 const size_t last_allocation_chunk
=
138 ((kDebugLogChunkSize
- 1 + log_size
) / kDebugLogChunkSize
);
139 const size_t desired_allocation_chunk
=
140 ((kDebugLogChunkSize
- 1 + log_size
+ write_size
) /
142 if (last_allocation_chunk
!= desired_allocation_chunk
) {
144 fd_
, FALLOC_FL_KEEP_SIZE
, 0,
145 static_cast<off_t
>(desired_allocation_chunk
* kDebugLogChunkSize
));
149 size_t sz
= fwrite(base
, 1, write_size
, file_
);
150 flush_pending_
= true;
151 assert(sz
== write_size
);
153 log_size_
+= write_size
;
155 uint64_t now_micros
= static_cast<uint64_t>(now_tv
.tv_sec
) * 1000000 +
157 if (now_micros
- last_flush_micros_
>= flush_every_seconds_
* 1000000) {
160 if (base
!= buffer
) {
166 size_t GetLogFileSize() const override
{ return log_size_
; }
169 } // namespace rocksdb