YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/yb/rocksdb/util/posix_logger.h
Line
Count
Source (jump to first uncovered line)
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.
5
//
6
// The following only applies to changes made to this file as part of YugaByte development.
7
//
8
// Portions Copyright (c) YugaByte, Inc.
9
//
10
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
11
// in compliance with the License.  You may obtain a copy of the License at
12
//
13
// http://www.apache.org/licenses/LICENSE-2.0
14
//
15
// Unless required by applicable law or agreed to in writing, software distributed under the License
16
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17
// or implied.  See the License for the specific language governing permissions and limitations
18
// under the License.
19
//
20
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
21
// Use of this source code is governed by a BSD-style license that can be
22
// found in the LICENSE file. See the AUTHORS file for names of contributors.
23
//
24
// Logger implementation that can be shared by all environments
25
// where enough posix functionality is available.
26
27
#ifndef YB_ROCKSDB_UTIL_POSIX_LOGGER_H
28
#define YB_ROCKSDB_UTIL_POSIX_LOGGER_H
29
30
#include <stdio.h>
31
#include <time.h>
32
#include <fcntl.h>
33
34
#include <algorithm>
35
#include <atomic>
36
37
#ifdef __linux__
38
#ifndef FALLOC_FL_KEEP_SIZE
39
#include <linux/falloc.h>
40
#endif
41
#endif
42
43
#include "yb/rocksdb/port/sys_time.h"
44
45
#include "yb/rocksdb/env.h"
46
#include "yb/util/stats/iostats_context_imp.h"
47
#include "yb/rocksdb/util/sync_point.h"
48
49
namespace rocksdb {
50
51
const int kDebugLogChunkSize = 128 * 1024;
52
53
class PosixLogger : public Logger {
54
 private:
55
  FILE* file_;
56
  uint64_t (*gettid_)();  // Return the thread id for the current thread
57
  std::atomic_size_t log_size_;
58
  int fd_;
59
  static const uint64_t flush_every_seconds_ = 5;
60
  std::atomic_uint_fast64_t last_flush_micros_;
61
  Env* env_;
62
  std::atomic<bool> flush_pending_;
63
 public:
64
  PosixLogger(FILE* f, uint64_t (*gettid)(), Env* env,
65
              const InfoLogLevel log_level = InfoLogLevel::ERROR_LEVEL)
66
      : Logger(log_level),
67
        file_(f),
68
        gettid_(gettid),
69
        log_size_(0),
70
        fd_(fileno(f)),
71
        last_flush_micros_(0),
72
        env_(env),
73
21.0k
        flush_pending_(false) {}
74
21.0k
  virtual ~PosixLogger() {
75
21.0k
    fclose(file_);
76
21.0k
  }
77
336k
  virtual void Flush() override {
78
336k
    TEST_SYNC_POINT_CALLBACK("PosixLogger::Flush:BeginCallback", nullptr);
79
336k
    {
80
336k
      bool expected_flush_pending = true;
81
      // TODO: use a weaker memory order?
82
336k
      if (flush_pending_.compare_exchange_strong(expected_flush_pending, false)) {
83
257k
        fflush(file_);
84
257k
      }
85
336k
    }
86
336k
    last_flush_micros_ = env_->NowMicros();
87
336k
  }
88
89
  using Logger::Logv;
90
1.95M
  virtual void Logv(const char* format, va_list ap) override {
91
1.95M
    IOSTATS_TIMER_GUARD(logger_nanos);
92
93
1.95M
    const uint64_t thread_id = (*gettid_)();
94
95
    // We try twice: the first time with a fixed-size stack allocated buffer,
96
    // and the second time with a much larger dynamically allocated buffer.
97
1.95M
    char buffer[500];
98
2.02M
    for (int iter = 0; 
iter < 22.02M
;
iter++62.9k
) {
99
2.02M
      char* base;
100
2.02M
      int bufsize;
101
2.02M
      if (iter == 0) {
102
1.95M
        bufsize = sizeof(buffer);
103
1.95M
        base = buffer;
104
1.95M
      } else {
105
62.9k
        bufsize = 30000;
106
62.9k
        base = new char[bufsize];
107
62.9k
      }
108
2.02M
      char* p = base;
109
2.02M
      char* limit = base + bufsize;
110
111
2.02M
      struct timeval now_tv;
112
2.02M
      gettimeofday(&now_tv, nullptr);
113
2.02M
      const time_t seconds = now_tv.tv_sec;
114
2.02M
      struct tm t;
115
2.02M
      localtime_r(&seconds, &t);
116
2.02M
      p += snprintf(p, limit - p,
117
2.02M
                    "%04d/%02d/%02d-%02d:%02d:%02d.%06d %" PRIx64 " ",
118
2.02M
                    t.tm_year + 1900,
119
2.02M
                    t.tm_mon + 1,
120
2.02M
                    t.tm_mday,
121
2.02M
                    t.tm_hour,
122
2.02M
                    t.tm_min,
123
2.02M
                    t.tm_sec,
124
2.02M
                    static_cast<int>(now_tv.tv_usec),
125
2.02M
                    thread_id);
126
127
      // Print the message
128
2.02M
      if (
p < limit2.02M
) {
129
2.02M
        va_list backup_ap;
130
2.02M
        va_copy(backup_ap, ap);
131
2.02M
        p += vsnprintf(p, limit - p, format, backup_ap);
132
2.02M
        va_end(backup_ap);
133
2.02M
      }
134
135
      // Truncate to available space if necessary
136
2.02M
      if (p >= limit) {
137
62.9k
        if (iter == 0) {
138
62.9k
          continue;       // Try again with larger buffer
139
62.9k
        } else {
140
1
          p = limit - 1;
141
1
        }
142
62.9k
      }
143
144
      // Add newline if necessary
145
1.95M
      
if (1.95M
p == base1.95M
|| p[-1] != '\n') {
146
1.62M
        *p++ = '\n';
147
1.62M
      }
148
149
1.95M
      assert(p <= limit);
150
0
      const size_t write_size = p - base;
151
152
#ifdef ROCKSDB_FALLOCATE_PRESENT
153
      // If this write would cross a boundary of kDebugLogChunkSize
154
      // space, pre-allocate more space to avoid overly large
155
      // allocations from filesystem allocsize options.
156
      const size_t log_size = log_size_;
157
      const size_t last_allocation_chunk =
158
        ((kDebugLogChunkSize - 1 + log_size) / kDebugLogChunkSize);
159
      const size_t desired_allocation_chunk =
160
        ((kDebugLogChunkSize - 1 + log_size + write_size) /
161
           kDebugLogChunkSize);
162
      if (last_allocation_chunk != desired_allocation_chunk) {
163
        fallocate(
164
            fd_, FALLOC_FL_KEEP_SIZE, 0,
165
            static_cast<off_t>(desired_allocation_chunk * kDebugLogChunkSize));
166
      }
167
#endif
168
169
1.95M
      size_t sz = fwrite(base, 1, write_size, file_);
170
      // TODO: use a weaker memory order?
171
1.95M
      flush_pending_.store(true);
172
1.95M
      assert(sz == write_size);
173
1.95M
      if (
sz > 01.95M
) {
174
1.95M
        log_size_ += write_size;
175
1.95M
      }
176
1.95M
      uint64_t now_micros = static_cast<uint64_t>(now_tv.tv_sec) * 1000000 +
177
1.95M
        now_tv.tv_usec;
178
1.95M
      if (now_micros - last_flush_micros_ >= flush_every_seconds_ * 1000000) {
179
25.9k
        Flush();
180
25.9k
      }
181
1.95M
      if (base != buffer) {
182
62.9k
        delete[] base;
183
62.9k
      }
184
1.95M
      break;
185
2.02M
    }
186
1.95M
  }
187
897
  size_t GetLogFileSize() const override { return log_size_; }
188
};
189
190
}  // namespace rocksdb
191
192
#endif // YB_ROCKSDB_UTIL_POSIX_LOGGER_H