Coverage Report

Created: 2024-09-08 07:17

/src/rocksdb/db/internal_stats.cc
Line
Count
Source (jump to first uncovered line)
1
//  This source code is licensed under both the GPLv2 (found in the
2
//  COPYING file in the root directory) and Apache 2.0 License
3
//  (found in the LICENSE.Apache file in the root directory).
4
//
5
// Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
6
//
7
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
8
// Use of this source code is governed by a BSD-style license that can be
9
// found in the LICENSE file. See the AUTHORS file for names of contributors.
10
11
#include "db/internal_stats.h"
12
13
#include <algorithm>
14
#include <cinttypes>
15
#include <cstddef>
16
#include <limits>
17
#include <sstream>
18
#include <string>
19
#include <unordered_map>
20
#include <utility>
21
#include <vector>
22
23
#include "cache/cache_entry_roles.h"
24
#include "cache/cache_entry_stats.h"
25
#include "db/column_family.h"
26
#include "db/db_impl/db_impl.h"
27
#include "db/write_stall_stats.h"
28
#include "port/port.h"
29
#include "rocksdb/system_clock.h"
30
#include "rocksdb/table.h"
31
#include "table/block_based/cachable_entry.h"
32
#include "util/hash_containers.h"
33
#include "util/string_util.h"
34
35
namespace ROCKSDB_NAMESPACE {
36
37
const std::map<LevelStatType, LevelStat> InternalStats::compaction_level_stats =
38
    {
39
        {LevelStatType::NUM_FILES, LevelStat{"NumFiles", "Files"}},
40
        {LevelStatType::COMPACTED_FILES,
41
         LevelStat{"CompactedFiles", "CompactedFiles"}},
42
        {LevelStatType::SIZE_BYTES, LevelStat{"SizeBytes", "Size"}},
43
        {LevelStatType::SCORE, LevelStat{"Score", "Score"}},
44
        {LevelStatType::READ_GB, LevelStat{"ReadGB", "Read(GB)"}},
45
        {LevelStatType::RN_GB, LevelStat{"RnGB", "Rn(GB)"}},
46
        {LevelStatType::RNP1_GB, LevelStat{"Rnp1GB", "Rnp1(GB)"}},
47
        {LevelStatType::WRITE_GB, LevelStat{"WriteGB", "Write(GB)"}},
48
        {LevelStatType::W_NEW_GB, LevelStat{"WnewGB", "Wnew(GB)"}},
49
        {LevelStatType::MOVED_GB, LevelStat{"MovedGB", "Moved(GB)"}},
50
        {LevelStatType::WRITE_AMP, LevelStat{"WriteAmp", "W-Amp"}},
51
        {LevelStatType::READ_MBPS, LevelStat{"ReadMBps", "Rd(MB/s)"}},
52
        {LevelStatType::WRITE_MBPS, LevelStat{"WriteMBps", "Wr(MB/s)"}},
53
        {LevelStatType::COMP_SEC, LevelStat{"CompSec", "Comp(sec)"}},
54
        {LevelStatType::COMP_CPU_SEC,
55
         LevelStat{"CompMergeCPU", "CompMergeCPU(sec)"}},
56
        {LevelStatType::COMP_COUNT, LevelStat{"CompCount", "Comp(cnt)"}},
57
        {LevelStatType::AVG_SEC, LevelStat{"AvgSec", "Avg(sec)"}},
58
        {LevelStatType::KEY_IN, LevelStat{"KeyIn", "KeyIn"}},
59
        {LevelStatType::KEY_DROP, LevelStat{"KeyDrop", "KeyDrop"}},
60
        {LevelStatType::R_BLOB_GB, LevelStat{"RblobGB", "Rblob(GB)"}},
61
        {LevelStatType::W_BLOB_GB, LevelStat{"WblobGB", "Wblob(GB)"}},
62
};
63
64
const std::map<InternalStats::InternalDBStatsType, DBStatInfo>
65
    InternalStats::db_stats_type_to_info = {
66
        {InternalStats::kIntStatsWalFileBytes,
67
         DBStatInfo{"db.wal_bytes_written"}},
68
        {InternalStats::kIntStatsWalFileSynced, DBStatInfo{"db.wal_syncs"}},
69
        {InternalStats::kIntStatsBytesWritten,
70
         DBStatInfo{"db.user_bytes_written"}},
71
        {InternalStats::kIntStatsNumKeysWritten,
72
         DBStatInfo{"db.user_keys_written"}},
73
        {InternalStats::kIntStatsWriteDoneByOther,
74
         DBStatInfo{"db.user_writes_by_other"}},
75
        {InternalStats::kIntStatsWriteDoneBySelf,
76
         DBStatInfo{"db.user_writes_by_self"}},
77
        {InternalStats::kIntStatsWriteWithWal,
78
         DBStatInfo{"db.user_writes_with_wal"}},
79
        {InternalStats::kIntStatsWriteStallMicros,
80
         DBStatInfo{"db.user_write_stall_micros"}},
81
        {InternalStats::kIntStatsWriteBufferManagerLimitStopsCounts,
82
         DBStatInfo{WriteStallStatsMapKeys::CauseConditionCount(
83
             WriteStallCause::kWriteBufferManagerLimit,
84
             WriteStallCondition::kStopped)}},
85
};
86
87
namespace {
88
const double kMB = 1048576.0;
89
const double kGB = kMB * 1024;
90
const double kMicrosInSec = 1000000.0;
91
92
void PrintLevelStatsHeader(char* buf, size_t len, const std::string& cf_name,
93
120
                           const std::string& group_by) {
94
120
  int written_size =
95
120
      snprintf(buf, len, "\n** Compaction Stats [%s] **\n", cf_name.c_str());
96
120
  written_size = std::min(written_size, static_cast<int>(len));
97
2.40k
  auto hdr = [](LevelStatType t) {
98
2.40k
    return InternalStats::compaction_level_stats.at(t).header_name.c_str();
99
2.40k
  };
100
120
  int line_size = snprintf(
101
120
      buf + written_size, len - written_size,
102
120
      "%s    %s   %s     %s %s  %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s "
103
120
      "%s\n",
104
      // Note that we skip COMPACTED_FILES and merge it with Files column
105
120
      group_by.c_str(), hdr(LevelStatType::NUM_FILES),
106
120
      hdr(LevelStatType::SIZE_BYTES), hdr(LevelStatType::SCORE),
107
120
      hdr(LevelStatType::READ_GB), hdr(LevelStatType::RN_GB),
108
120
      hdr(LevelStatType::RNP1_GB), hdr(LevelStatType::WRITE_GB),
109
120
      hdr(LevelStatType::W_NEW_GB), hdr(LevelStatType::MOVED_GB),
110
120
      hdr(LevelStatType::WRITE_AMP), hdr(LevelStatType::READ_MBPS),
111
120
      hdr(LevelStatType::WRITE_MBPS), hdr(LevelStatType::COMP_SEC),
112
120
      hdr(LevelStatType::COMP_CPU_SEC), hdr(LevelStatType::COMP_COUNT),
113
120
      hdr(LevelStatType::AVG_SEC), hdr(LevelStatType::KEY_IN),
114
120
      hdr(LevelStatType::KEY_DROP), hdr(LevelStatType::R_BLOB_GB),
115
120
      hdr(LevelStatType::W_BLOB_GB));
116
117
120
  written_size += line_size;
118
120
  written_size = std::min(written_size, static_cast<int>(len));
119
120
  snprintf(buf + written_size, len - written_size, "%s\n",
120
120
           std::string(line_size, '-').c_str());
121
120
}
122
123
void PrepareLevelStats(std::map<LevelStatType, double>* level_stats,
124
                       int num_files, int being_compacted,
125
                       double total_file_size, double score, double w_amp,
126
130
                       const InternalStats::CompactionStats& stats) {
127
130
  const uint64_t bytes_read = stats.bytes_read_non_output_levels +
128
130
                              stats.bytes_read_output_level +
129
130
                              stats.bytes_read_blob;
130
130
  const uint64_t bytes_written = stats.bytes_written + stats.bytes_written_blob;
131
130
  const int64_t bytes_new = stats.bytes_written - stats.bytes_read_output_level;
132
130
  const double elapsed = (stats.micros + 1) / kMicrosInSec;
133
134
130
  (*level_stats)[LevelStatType::NUM_FILES] = num_files;
135
130
  (*level_stats)[LevelStatType::COMPACTED_FILES] = being_compacted;
136
130
  (*level_stats)[LevelStatType::SIZE_BYTES] = total_file_size;
137
130
  (*level_stats)[LevelStatType::SCORE] = score;
138
130
  (*level_stats)[LevelStatType::READ_GB] = bytes_read / kGB;
139
130
  (*level_stats)[LevelStatType::RN_GB] =
140
130
      stats.bytes_read_non_output_levels / kGB;
141
130
  (*level_stats)[LevelStatType::RNP1_GB] = stats.bytes_read_output_level / kGB;
142
130
  (*level_stats)[LevelStatType::WRITE_GB] = stats.bytes_written / kGB;
143
130
  (*level_stats)[LevelStatType::W_NEW_GB] = bytes_new / kGB;
144
130
  (*level_stats)[LevelStatType::MOVED_GB] = stats.bytes_moved / kGB;
145
130
  (*level_stats)[LevelStatType::WRITE_AMP] = w_amp;
146
130
  (*level_stats)[LevelStatType::READ_MBPS] = bytes_read / kMB / elapsed;
147
130
  (*level_stats)[LevelStatType::WRITE_MBPS] = bytes_written / kMB / elapsed;
148
130
  (*level_stats)[LevelStatType::COMP_SEC] = stats.micros / kMicrosInSec;
149
130
  (*level_stats)[LevelStatType::COMP_CPU_SEC] = stats.cpu_micros / kMicrosInSec;
150
130
  (*level_stats)[LevelStatType::COMP_COUNT] = stats.count;
151
130
  (*level_stats)[LevelStatType::AVG_SEC] =
152
130
      stats.count == 0 ? 0 : stats.micros / kMicrosInSec / stats.count;
153
130
  (*level_stats)[LevelStatType::KEY_IN] =
154
130
      static_cast<double>(stats.num_input_records);
155
130
  (*level_stats)[LevelStatType::KEY_DROP] =
156
130
      static_cast<double>(stats.num_dropped_records);
157
130
  (*level_stats)[LevelStatType::R_BLOB_GB] = stats.bytes_read_blob / kGB;
158
130
  (*level_stats)[LevelStatType::W_BLOB_GB] = stats.bytes_written_blob / kGB;
159
130
}
160
161
void PrintLevelStats(char* buf, size_t len, const std::string& name,
162
130
                     const std::map<LevelStatType, double>& stat_value) {
163
130
  snprintf(
164
130
      buf, len,
165
130
      "%4s "      /*  Level */
166
130
      "%6d/%-3d " /*  Files */
167
130
      "%8s "      /*  Size */
168
130
      "%5.1f "    /*  Score */
169
130
      "%8.1f "    /*  Read(GB) */
170
130
      "%7.1f "    /*  Rn(GB) */
171
130
      "%8.1f "    /*  Rnp1(GB) */
172
130
      "%9.1f "    /*  Write(GB) */
173
130
      "%8.1f "    /*  Wnew(GB) */
174
130
      "%9.1f "    /*  Moved(GB) */
175
130
      "%5.1f "    /*  W-Amp */
176
130
      "%8.1f "    /*  Rd(MB/s) */
177
130
      "%8.1f "    /*  Wr(MB/s) */
178
130
      "%9.2f "    /*  Comp(sec) */
179
130
      "%17.2f "   /*  CompMergeCPU(sec) */
180
130
      "%9d "      /*  Comp(cnt) */
181
130
      "%8.3f "    /*  Avg(sec) */
182
130
      "%7s "      /*  KeyIn */
183
130
      "%6s "      /*  KeyDrop */
184
130
      "%9.1f "    /*  Rblob(GB) */
185
130
      "%9.1f\n",  /*  Wblob(GB) */
186
130
      name.c_str(), static_cast<int>(stat_value.at(LevelStatType::NUM_FILES)),
187
130
      static_cast<int>(stat_value.at(LevelStatType::COMPACTED_FILES)),
188
130
      BytesToHumanString(
189
130
          static_cast<uint64_t>(stat_value.at(LevelStatType::SIZE_BYTES)))
190
130
          .c_str(),
191
130
      stat_value.at(LevelStatType::SCORE),
192
130
      stat_value.at(LevelStatType::READ_GB),
193
130
      stat_value.at(LevelStatType::RN_GB),
194
130
      stat_value.at(LevelStatType::RNP1_GB),
195
130
      stat_value.at(LevelStatType::WRITE_GB),
196
130
      stat_value.at(LevelStatType::W_NEW_GB),
197
130
      stat_value.at(LevelStatType::MOVED_GB),
198
130
      stat_value.at(LevelStatType::WRITE_AMP),
199
130
      stat_value.at(LevelStatType::READ_MBPS),
200
130
      stat_value.at(LevelStatType::WRITE_MBPS),
201
130
      stat_value.at(LevelStatType::COMP_SEC),
202
130
      stat_value.at(LevelStatType::COMP_CPU_SEC),
203
130
      static_cast<int>(stat_value.at(LevelStatType::COMP_COUNT)),
204
130
      stat_value.at(LevelStatType::AVG_SEC),
205
130
      NumberToHumanString(
206
130
          static_cast<std::int64_t>(stat_value.at(LevelStatType::KEY_IN)))
207
130
          .c_str(),
208
130
      NumberToHumanString(
209
130
          static_cast<std::int64_t>(stat_value.at(LevelStatType::KEY_DROP)))
210
130
          .c_str(),
211
130
      stat_value.at(LevelStatType::R_BLOB_GB),
212
130
      stat_value.at(LevelStatType::W_BLOB_GB));
213
130
}
214
215
void PrintLevelStats(char* buf, size_t len, const std::string& name,
216
                     int num_files, int being_compacted, double total_file_size,
217
                     double score, double w_amp,
218
60
                     const InternalStats::CompactionStats& stats) {
219
60
  std::map<LevelStatType, double> level_stats;
220
60
  PrepareLevelStats(&level_stats, num_files, being_compacted, total_file_size,
221
60
                    score, w_amp, stats);
222
60
  PrintLevelStats(buf, len, name, level_stats);
223
60
}
224
225
// Assumes that trailing numbers represent an optional argument. This requires
226
// property names to not end with numbers.
227
498
std::pair<Slice, Slice> GetPropertyNameAndArg(const Slice& property) {
228
498
  Slice name = property, arg = property;
229
498
  size_t sfx_len = 0;
230
501
  while (sfx_len < property.size() &&
231
501
         isdigit(property[property.size() - sfx_len - 1])) {
232
3
    ++sfx_len;
233
3
  }
234
498
  name.remove_suffix(sfx_len);
235
498
  arg.remove_prefix(property.size() - sfx_len);
236
498
  return {name, arg};
237
498
}
238
}  // anonymous namespace
239
240
static const std::string rocksdb_prefix = "rocksdb.";
241
242
static const std::string num_files_at_level_prefix = "num-files-at-level";
243
static const std::string compression_ratio_at_level_prefix =
244
    "compression-ratio-at-level";
245
static const std::string allstats = "stats";
246
static const std::string sstables = "sstables";
247
static const std::string cfstats = "cfstats";
248
static const std::string cfstats_no_file_histogram =
249
    "cfstats-no-file-histogram";
250
static const std::string cf_file_histogram = "cf-file-histogram";
251
static const std::string cf_write_stall_stats = "cf-write-stall-stats";
252
static const std::string dbstats = "dbstats";
253
static const std::string db_write_stall_stats = "db-write-stall-stats";
254
static const std::string levelstats = "levelstats";
255
static const std::string block_cache_entry_stats = "block-cache-entry-stats";
256
static const std::string fast_block_cache_entry_stats =
257
    "fast-block-cache-entry-stats";
258
static const std::string num_immutable_mem_table = "num-immutable-mem-table";
259
static const std::string num_immutable_mem_table_flushed =
260
    "num-immutable-mem-table-flushed";
261
static const std::string mem_table_flush_pending = "mem-table-flush-pending";
262
static const std::string compaction_pending = "compaction-pending";
263
static const std::string background_errors = "background-errors";
264
static const std::string cur_size_active_mem_table =
265
    "cur-size-active-mem-table";
266
static const std::string cur_size_all_mem_tables = "cur-size-all-mem-tables";
267
static const std::string size_all_mem_tables = "size-all-mem-tables";
268
static const std::string num_entries_active_mem_table =
269
    "num-entries-active-mem-table";
270
static const std::string num_entries_imm_mem_tables =
271
    "num-entries-imm-mem-tables";
272
static const std::string num_deletes_active_mem_table =
273
    "num-deletes-active-mem-table";
274
static const std::string num_deletes_imm_mem_tables =
275
    "num-deletes-imm-mem-tables";
276
static const std::string estimate_num_keys = "estimate-num-keys";
277
static const std::string estimate_table_readers_mem =
278
    "estimate-table-readers-mem";
279
static const std::string is_file_deletions_enabled =
280
    "is-file-deletions-enabled";
281
static const std::string num_snapshots = "num-snapshots";
282
static const std::string oldest_snapshot_time = "oldest-snapshot-time";
283
static const std::string oldest_snapshot_sequence = "oldest-snapshot-sequence";
284
static const std::string num_live_versions = "num-live-versions";
285
static const std::string current_version_number =
286
    "current-super-version-number";
287
static const std::string estimate_live_data_size = "estimate-live-data-size";
288
static const std::string min_log_number_to_keep_str = "min-log-number-to-keep";
289
static const std::string min_obsolete_sst_number_to_keep_str =
290
    "min-obsolete-sst-number-to-keep";
291
static const std::string base_level_str = "base-level";
292
static const std::string total_sst_files_size = "total-sst-files-size";
293
static const std::string live_sst_files_size = "live-sst-files-size";
294
static const std::string obsolete_sst_files_size = "obsolete-sst-files-size";
295
static const std::string live_sst_files_size_at_temperature =
296
    "live-sst-files-size-at-temperature";
297
static const std::string estimate_pending_comp_bytes =
298
    "estimate-pending-compaction-bytes";
299
static const std::string aggregated_table_properties =
300
    "aggregated-table-properties";
301
static const std::string aggregated_table_properties_at_level =
302
    aggregated_table_properties + "-at-level";
303
static const std::string num_running_compactions = "num-running-compactions";
304
static const std::string num_running_flushes = "num-running-flushes";
305
static const std::string actual_delayed_write_rate =
306
    "actual-delayed-write-rate";
307
static const std::string is_write_stopped = "is-write-stopped";
308
static const std::string estimate_oldest_key_time = "estimate-oldest-key-time";
309
static const std::string block_cache_capacity = "block-cache-capacity";
310
static const std::string block_cache_usage = "block-cache-usage";
311
static const std::string block_cache_pinned_usage = "block-cache-pinned-usage";
312
static const std::string options_statistics = "options-statistics";
313
static const std::string num_blob_files = "num-blob-files";
314
static const std::string blob_stats = "blob-stats";
315
static const std::string total_blob_file_size = "total-blob-file-size";
316
static const std::string live_blob_file_size = "live-blob-file-size";
317
static const std::string live_blob_file_garbage_size =
318
    "live-blob-file-garbage-size";
319
static const std::string blob_cache_capacity = "blob-cache-capacity";
320
static const std::string blob_cache_usage = "blob-cache-usage";
321
static const std::string blob_cache_pinned_usage = "blob-cache-pinned-usage";
322
323
const std::string DB::Properties::kNumFilesAtLevelPrefix =
324
    rocksdb_prefix + num_files_at_level_prefix;
325
const std::string DB::Properties::kCompressionRatioAtLevelPrefix =
326
    rocksdb_prefix + compression_ratio_at_level_prefix;
327
const std::string DB::Properties::kStats = rocksdb_prefix + allstats;
328
const std::string DB::Properties::kSSTables = rocksdb_prefix + sstables;
329
const std::string DB::Properties::kCFStats = rocksdb_prefix + cfstats;
330
const std::string DB::Properties::kCFStatsNoFileHistogram =
331
    rocksdb_prefix + cfstats_no_file_histogram;
332
const std::string DB::Properties::kCFFileHistogram =
333
    rocksdb_prefix + cf_file_histogram;
334
const std::string DB::Properties::kCFWriteStallStats =
335
    rocksdb_prefix + cf_write_stall_stats;
336
const std::string DB::Properties::kDBWriteStallStats =
337
    rocksdb_prefix + db_write_stall_stats;
338
const std::string DB::Properties::kDBStats = rocksdb_prefix + dbstats;
339
const std::string DB::Properties::kLevelStats = rocksdb_prefix + levelstats;
340
const std::string DB::Properties::kBlockCacheEntryStats =
341
    rocksdb_prefix + block_cache_entry_stats;
342
const std::string DB::Properties::kFastBlockCacheEntryStats =
343
    rocksdb_prefix + fast_block_cache_entry_stats;
344
const std::string DB::Properties::kNumImmutableMemTable =
345
    rocksdb_prefix + num_immutable_mem_table;
346
const std::string DB::Properties::kNumImmutableMemTableFlushed =
347
    rocksdb_prefix + num_immutable_mem_table_flushed;
348
const std::string DB::Properties::kMemTableFlushPending =
349
    rocksdb_prefix + mem_table_flush_pending;
350
const std::string DB::Properties::kCompactionPending =
351
    rocksdb_prefix + compaction_pending;
352
const std::string DB::Properties::kNumRunningCompactions =
353
    rocksdb_prefix + num_running_compactions;
354
const std::string DB::Properties::kNumRunningFlushes =
355
    rocksdb_prefix + num_running_flushes;
356
const std::string DB::Properties::kBackgroundErrors =
357
    rocksdb_prefix + background_errors;
358
const std::string DB::Properties::kCurSizeActiveMemTable =
359
    rocksdb_prefix + cur_size_active_mem_table;
360
const std::string DB::Properties::kCurSizeAllMemTables =
361
    rocksdb_prefix + cur_size_all_mem_tables;
362
const std::string DB::Properties::kSizeAllMemTables =
363
    rocksdb_prefix + size_all_mem_tables;
364
const std::string DB::Properties::kNumEntriesActiveMemTable =
365
    rocksdb_prefix + num_entries_active_mem_table;
366
const std::string DB::Properties::kNumEntriesImmMemTables =
367
    rocksdb_prefix + num_entries_imm_mem_tables;
368
const std::string DB::Properties::kNumDeletesActiveMemTable =
369
    rocksdb_prefix + num_deletes_active_mem_table;
370
const std::string DB::Properties::kNumDeletesImmMemTables =
371
    rocksdb_prefix + num_deletes_imm_mem_tables;
372
const std::string DB::Properties::kEstimateNumKeys =
373
    rocksdb_prefix + estimate_num_keys;
374
const std::string DB::Properties::kEstimateTableReadersMem =
375
    rocksdb_prefix + estimate_table_readers_mem;
376
const std::string DB::Properties::kIsFileDeletionsEnabled =
377
    rocksdb_prefix + is_file_deletions_enabled;
378
const std::string DB::Properties::kNumSnapshots =
379
    rocksdb_prefix + num_snapshots;
380
const std::string DB::Properties::kOldestSnapshotTime =
381
    rocksdb_prefix + oldest_snapshot_time;
382
const std::string DB::Properties::kOldestSnapshotSequence =
383
    rocksdb_prefix + oldest_snapshot_sequence;
384
const std::string DB::Properties::kNumLiveVersions =
385
    rocksdb_prefix + num_live_versions;
386
const std::string DB::Properties::kCurrentSuperVersionNumber =
387
    rocksdb_prefix + current_version_number;
388
const std::string DB::Properties::kEstimateLiveDataSize =
389
    rocksdb_prefix + estimate_live_data_size;
390
const std::string DB::Properties::kMinLogNumberToKeep =
391
    rocksdb_prefix + min_log_number_to_keep_str;
392
const std::string DB::Properties::kMinObsoleteSstNumberToKeep =
393
    rocksdb_prefix + min_obsolete_sst_number_to_keep_str;
394
const std::string DB::Properties::kTotalSstFilesSize =
395
    rocksdb_prefix + total_sst_files_size;
396
const std::string DB::Properties::kLiveSstFilesSize =
397
    rocksdb_prefix + live_sst_files_size;
398
const std::string DB::Properties::kObsoleteSstFilesSize =
399
    rocksdb_prefix + obsolete_sst_files_size;
400
const std::string DB::Properties::kBaseLevel = rocksdb_prefix + base_level_str;
401
const std::string DB::Properties::kEstimatePendingCompactionBytes =
402
    rocksdb_prefix + estimate_pending_comp_bytes;
403
const std::string DB::Properties::kAggregatedTableProperties =
404
    rocksdb_prefix + aggregated_table_properties;
405
const std::string DB::Properties::kAggregatedTablePropertiesAtLevel =
406
    rocksdb_prefix + aggregated_table_properties_at_level;
407
const std::string DB::Properties::kActualDelayedWriteRate =
408
    rocksdb_prefix + actual_delayed_write_rate;
409
const std::string DB::Properties::kIsWriteStopped =
410
    rocksdb_prefix + is_write_stopped;
411
const std::string DB::Properties::kEstimateOldestKeyTime =
412
    rocksdb_prefix + estimate_oldest_key_time;
413
const std::string DB::Properties::kBlockCacheCapacity =
414
    rocksdb_prefix + block_cache_capacity;
415
const std::string DB::Properties::kBlockCacheUsage =
416
    rocksdb_prefix + block_cache_usage;
417
const std::string DB::Properties::kBlockCachePinnedUsage =
418
    rocksdb_prefix + block_cache_pinned_usage;
419
const std::string DB::Properties::kOptionsStatistics =
420
    rocksdb_prefix + options_statistics;
421
const std::string DB::Properties::kLiveSstFilesSizeAtTemperature =
422
    rocksdb_prefix + live_sst_files_size_at_temperature;
423
const std::string DB::Properties::kNumBlobFiles =
424
    rocksdb_prefix + num_blob_files;
425
const std::string DB::Properties::kBlobStats = rocksdb_prefix + blob_stats;
426
const std::string DB::Properties::kTotalBlobFileSize =
427
    rocksdb_prefix + total_blob_file_size;
428
const std::string DB::Properties::kLiveBlobFileSize =
429
    rocksdb_prefix + live_blob_file_size;
430
const std::string DB::Properties::kLiveBlobFileGarbageSize =
431
    rocksdb_prefix + live_blob_file_garbage_size;
432
const std::string DB::Properties::kBlobCacheCapacity =
433
    rocksdb_prefix + blob_cache_capacity;
434
const std::string DB::Properties::kBlobCacheUsage =
435
    rocksdb_prefix + blob_cache_usage;
436
const std::string DB::Properties::kBlobCachePinnedUsage =
437
    rocksdb_prefix + blob_cache_pinned_usage;
438
439
const std::string InternalStats::kPeriodicCFStats =
440
    DB::Properties::kCFStats + ".periodic";
441
const int InternalStats::kMaxNoChangePeriodSinceDump = 8;
442
443
const UnorderedMap<std::string, DBPropertyInfo>
444
    InternalStats::ppt_name_to_info = {
445
        {DB::Properties::kNumFilesAtLevelPrefix,
446
         {false, &InternalStats::HandleNumFilesAtLevel, nullptr, nullptr,
447
          nullptr}},
448
        {DB::Properties::kCompressionRatioAtLevelPrefix,
449
         {false, &InternalStats::HandleCompressionRatioAtLevelPrefix, nullptr,
450
          nullptr, nullptr}},
451
        {DB::Properties::kLevelStats,
452
         {false, &InternalStats::HandleLevelStats, nullptr, nullptr, nullptr}},
453
        {DB::Properties::kStats,
454
         {false, &InternalStats::HandleStats, nullptr, nullptr, nullptr}},
455
        {DB::Properties::kCFStats,
456
         {false, &InternalStats::HandleCFStats, nullptr,
457
          &InternalStats::HandleCFMapStats, nullptr}},
458
        {InternalStats::kPeriodicCFStats,
459
         {false, &InternalStats::HandleCFStatsPeriodic, nullptr, nullptr,
460
          nullptr}},
461
        {DB::Properties::kCFStatsNoFileHistogram,
462
         {false, &InternalStats::HandleCFStatsNoFileHistogram, nullptr, nullptr,
463
          nullptr}},
464
        {DB::Properties::kCFFileHistogram,
465
         {false, &InternalStats::HandleCFFileHistogram, nullptr, nullptr,
466
          nullptr}},
467
        {DB::Properties::kCFWriteStallStats,
468
         {false, &InternalStats::HandleCFWriteStallStats, nullptr,
469
          &InternalStats::HandleCFWriteStallStatsMap, nullptr}},
470
        {DB::Properties::kDBStats,
471
         {false, &InternalStats::HandleDBStats, nullptr,
472
          &InternalStats::HandleDBMapStats, nullptr}},
473
        {DB::Properties::kDBWriteStallStats,
474
         {false, &InternalStats::HandleDBWriteStallStats, nullptr,
475
          &InternalStats::HandleDBWriteStallStatsMap, nullptr}},
476
        {DB::Properties::kBlockCacheEntryStats,
477
         {true, &InternalStats::HandleBlockCacheEntryStats, nullptr,
478
          &InternalStats::HandleBlockCacheEntryStatsMap, nullptr}},
479
        {DB::Properties::kFastBlockCacheEntryStats,
480
         {true, &InternalStats::HandleFastBlockCacheEntryStats, nullptr,
481
          &InternalStats::HandleFastBlockCacheEntryStatsMap, nullptr}},
482
        {DB::Properties::kSSTables,
483
         {false, &InternalStats::HandleSsTables, nullptr, nullptr, nullptr}},
484
        {DB::Properties::kAggregatedTableProperties,
485
         {false, &InternalStats::HandleAggregatedTableProperties, nullptr,
486
          &InternalStats::HandleAggregatedTablePropertiesMap, nullptr}},
487
        {DB::Properties::kAggregatedTablePropertiesAtLevel,
488
         {false, &InternalStats::HandleAggregatedTablePropertiesAtLevel,
489
          nullptr, &InternalStats::HandleAggregatedTablePropertiesAtLevelMap,
490
          nullptr}},
491
        {DB::Properties::kNumImmutableMemTable,
492
         {false, nullptr, &InternalStats::HandleNumImmutableMemTable, nullptr,
493
          nullptr}},
494
        {DB::Properties::kNumImmutableMemTableFlushed,
495
         {false, nullptr, &InternalStats::HandleNumImmutableMemTableFlushed,
496
          nullptr, nullptr}},
497
        {DB::Properties::kMemTableFlushPending,
498
         {false, nullptr, &InternalStats::HandleMemTableFlushPending, nullptr,
499
          nullptr}},
500
        {DB::Properties::kCompactionPending,
501
         {false, nullptr, &InternalStats::HandleCompactionPending, nullptr,
502
          nullptr}},
503
        {DB::Properties::kBackgroundErrors,
504
         {false, nullptr, &InternalStats::HandleBackgroundErrors, nullptr,
505
          nullptr}},
506
        {DB::Properties::kCurSizeActiveMemTable,
507
         {false, nullptr, &InternalStats::HandleCurSizeActiveMemTable, nullptr,
508
          nullptr}},
509
        {DB::Properties::kCurSizeAllMemTables,
510
         {false, nullptr, &InternalStats::HandleCurSizeAllMemTables, nullptr,
511
          nullptr}},
512
        {DB::Properties::kSizeAllMemTables,
513
         {false, nullptr, &InternalStats::HandleSizeAllMemTables, nullptr,
514
          nullptr}},
515
        {DB::Properties::kNumEntriesActiveMemTable,
516
         {false, nullptr, &InternalStats::HandleNumEntriesActiveMemTable,
517
          nullptr, nullptr}},
518
        {DB::Properties::kNumEntriesImmMemTables,
519
         {false, nullptr, &InternalStats::HandleNumEntriesImmMemTables, nullptr,
520
          nullptr}},
521
        {DB::Properties::kNumDeletesActiveMemTable,
522
         {false, nullptr, &InternalStats::HandleNumDeletesActiveMemTable,
523
          nullptr, nullptr}},
524
        {DB::Properties::kNumDeletesImmMemTables,
525
         {false, nullptr, &InternalStats::HandleNumDeletesImmMemTables, nullptr,
526
          nullptr}},
527
        {DB::Properties::kEstimateNumKeys,
528
         {false, nullptr, &InternalStats::HandleEstimateNumKeys, nullptr,
529
          nullptr}},
530
        {DB::Properties::kEstimateTableReadersMem,
531
         {true, nullptr, &InternalStats::HandleEstimateTableReadersMem, nullptr,
532
          nullptr}},
533
        {DB::Properties::kIsFileDeletionsEnabled,
534
         {false, nullptr, &InternalStats::HandleIsFileDeletionsEnabled, nullptr,
535
          nullptr}},
536
        {DB::Properties::kNumSnapshots,
537
         {false, nullptr, &InternalStats::HandleNumSnapshots, nullptr,
538
          nullptr}},
539
        {DB::Properties::kOldestSnapshotTime,
540
         {false, nullptr, &InternalStats::HandleOldestSnapshotTime, nullptr,
541
          nullptr}},
542
        {DB::Properties::kOldestSnapshotSequence,
543
         {false, nullptr, &InternalStats::HandleOldestSnapshotSequence, nullptr,
544
          nullptr}},
545
        {DB::Properties::kNumLiveVersions,
546
         {false, nullptr, &InternalStats::HandleNumLiveVersions, nullptr,
547
          nullptr}},
548
        {DB::Properties::kCurrentSuperVersionNumber,
549
         {false, nullptr, &InternalStats::HandleCurrentSuperVersionNumber,
550
          nullptr, nullptr}},
551
        {DB::Properties::kEstimateLiveDataSize,
552
         {true, nullptr, &InternalStats::HandleEstimateLiveDataSize, nullptr,
553
          nullptr}},
554
        {DB::Properties::kMinLogNumberToKeep,
555
         {false, nullptr, &InternalStats::HandleMinLogNumberToKeep, nullptr,
556
          nullptr}},
557
        {DB::Properties::kMinObsoleteSstNumberToKeep,
558
         {false, nullptr, &InternalStats::HandleMinObsoleteSstNumberToKeep,
559
          nullptr, nullptr}},
560
        {DB::Properties::kBaseLevel,
561
         {false, nullptr, &InternalStats::HandleBaseLevel, nullptr, nullptr}},
562
        {DB::Properties::kTotalSstFilesSize,
563
         {false, nullptr, &InternalStats::HandleTotalSstFilesSize, nullptr,
564
          nullptr}},
565
        {DB::Properties::kLiveSstFilesSize,
566
         {false, nullptr, &InternalStats::HandleLiveSstFilesSize, nullptr,
567
          nullptr}},
568
        {DB::Properties::kLiveSstFilesSizeAtTemperature,
569
         {false, &InternalStats::HandleLiveSstFilesSizeAtTemperature, nullptr,
570
          nullptr, nullptr}},
571
        {DB::Properties::kObsoleteSstFilesSize,
572
         {false, nullptr, &InternalStats::HandleObsoleteSstFilesSize, nullptr,
573
          nullptr}},
574
        {DB::Properties::kEstimatePendingCompactionBytes,
575
         {false, nullptr, &InternalStats::HandleEstimatePendingCompactionBytes,
576
          nullptr, nullptr}},
577
        {DB::Properties::kNumRunningFlushes,
578
         {false, nullptr, &InternalStats::HandleNumRunningFlushes, nullptr,
579
          nullptr}},
580
        {DB::Properties::kNumRunningCompactions,
581
         {false, nullptr, &InternalStats::HandleNumRunningCompactions, nullptr,
582
          nullptr}},
583
        {DB::Properties::kActualDelayedWriteRate,
584
         {false, nullptr, &InternalStats::HandleActualDelayedWriteRate, nullptr,
585
          nullptr}},
586
        {DB::Properties::kIsWriteStopped,
587
         {false, nullptr, &InternalStats::HandleIsWriteStopped, nullptr,
588
          nullptr}},
589
        {DB::Properties::kEstimateOldestKeyTime,
590
         {false, nullptr, &InternalStats::HandleEstimateOldestKeyTime, nullptr,
591
          nullptr}},
592
        {DB::Properties::kBlockCacheCapacity,
593
         {false, nullptr, &InternalStats::HandleBlockCacheCapacity, nullptr,
594
          nullptr}},
595
        {DB::Properties::kBlockCacheUsage,
596
         {false, nullptr, &InternalStats::HandleBlockCacheUsage, nullptr,
597
          nullptr}},
598
        {DB::Properties::kBlockCachePinnedUsage,
599
         {false, nullptr, &InternalStats::HandleBlockCachePinnedUsage, nullptr,
600
          nullptr}},
601
        {DB::Properties::kOptionsStatistics,
602
         {true, nullptr, nullptr, nullptr,
603
          &DBImpl::GetPropertyHandleOptionsStatistics}},
604
        {DB::Properties::kNumBlobFiles,
605
         {false, nullptr, &InternalStats::HandleNumBlobFiles, nullptr,
606
          nullptr}},
607
        {DB::Properties::kBlobStats,
608
         {false, &InternalStats::HandleBlobStats, nullptr, nullptr, nullptr}},
609
        {DB::Properties::kTotalBlobFileSize,
610
         {false, nullptr, &InternalStats::HandleTotalBlobFileSize, nullptr,
611
          nullptr}},
612
        {DB::Properties::kLiveBlobFileSize,
613
         {false, nullptr, &InternalStats::HandleLiveBlobFileSize, nullptr,
614
          nullptr}},
615
        {DB::Properties::kLiveBlobFileGarbageSize,
616
         {false, nullptr, &InternalStats::HandleLiveBlobFileGarbageSize,
617
          nullptr, nullptr}},
618
        {DB::Properties::kBlobCacheCapacity,
619
         {false, nullptr, &InternalStats::HandleBlobCacheCapacity, nullptr,
620
          nullptr}},
621
        {DB::Properties::kBlobCacheUsage,
622
         {false, nullptr, &InternalStats::HandleBlobCacheUsage, nullptr,
623
          nullptr}},
624
        {DB::Properties::kBlobCachePinnedUsage,
625
         {false, nullptr, &InternalStats::HandleBlobCachePinnedUsage, nullptr,
626
          nullptr}},
627
};
628
629
InternalStats::InternalStats(int num_levels, SystemClock* clock,
630
                             ColumnFamilyData* cfd)
631
    : db_stats_{},
632
      cf_stats_value_{},
633
      cf_stats_count_{},
634
      comp_stats_(num_levels),
635
      comp_stats_by_pri_(Env::Priority::TOTAL),
636
      file_read_latency_(num_levels),
637
      has_cf_change_since_dump_(true),
638
      bg_error_count_(0),
639
      number_levels_(num_levels),
640
      clock_(clock),
641
      cfd_(cfd),
642
12.0k
      started_at_(clock->NowMicros()) {
643
12.0k
  Cache* block_cache = GetBlockCacheForStats();
644
12.0k
  if (block_cache) {
645
    // Extract or create stats collector. Could fail in rare cases.
646
12.0k
    Status s = CacheEntryStatsCollector<CacheEntryRoleStats>::GetShared(
647
12.0k
        block_cache, clock_, &cache_entry_stats_collector_);
648
12.0k
    if (s.ok()) {
649
12.0k
      assert(cache_entry_stats_collector_);
650
12.0k
    } else {
651
0
      assert(!cache_entry_stats_collector_);
652
0
    }
653
12.0k
  }
654
12.0k
}
655
656
void InternalStats::TEST_GetCacheEntryRoleStats(CacheEntryRoleStats* stats,
657
0
                                                bool foreground) {
658
0
  CollectCacheEntryStats(foreground);
659
0
  if (cache_entry_stats_collector_) {
660
0
    cache_entry_stats_collector_->GetStats(stats);
661
0
  }
662
0
}
663
664
60
void InternalStats::CollectCacheEntryStats(bool foreground) {
665
  // This function is safe to call from any thread because
666
  // cache_entry_stats_collector_ field is const after constructor
667
  // and ->GetStats does its own synchronization, which also suffices for
668
  // cache_entry_stats_.
669
670
60
  if (!cache_entry_stats_collector_) {
671
0
    return;  // nothing to do (e.g. no block cache)
672
0
  }
673
674
  // For "background" collections, strictly cap the collection time by
675
  // expanding effective cache TTL. For foreground, be more aggressive about
676
  // getting latest data.
677
60
  int min_interval_seconds = foreground ? 10 : 180;
678
  // 1/500 = max of 0.2% of one CPU thread
679
60
  int min_interval_factor = foreground ? 10 : 500;
680
60
  cache_entry_stats_collector_->CollectStats(min_interval_seconds,
681
60
                                             min_interval_factor);
682
60
}
683
684
std::function<void(const Slice& key, Cache::ObjectPtr value, size_t charge,
685
                   const Cache::CacheItemHelper* helper)>
686
60
InternalStats::CacheEntryRoleStats::GetEntryCallback() {
687
60
  return [&](const Slice& /*key*/, Cache::ObjectPtr /*value*/, size_t charge,
688
73
             const Cache::CacheItemHelper* helper) -> void {
689
73
    size_t role_idx =
690
73
        static_cast<size_t>(helper ? helper->role : CacheEntryRole::kMisc);
691
73
    entry_counts[role_idx]++;
692
73
    total_charges[role_idx] += charge;
693
73
  };
694
60
}
695
696
void InternalStats::CacheEntryRoleStats::BeginCollection(
697
60
    Cache* cache, SystemClock*, uint64_t start_time_micros) {
698
60
  Clear();
699
60
  last_start_time_micros_ = start_time_micros;
700
60
  ++collection_count;
701
60
  std::ostringstream str;
702
60
  str << cache->Name() << "@" << static_cast<void*>(cache) << "#"
703
60
      << port::GetProcessID();
704
60
  cache_id = str.str();
705
60
  cache_capacity = cache->GetCapacity();
706
60
  cache_usage = cache->GetUsage();
707
60
  table_size = cache->GetTableAddressCount();
708
60
  occupancy = cache->GetOccupancyCount();
709
60
  hash_seed = cache->GetHashSeed();
710
60
}
711
712
void InternalStats::CacheEntryRoleStats::EndCollection(
713
60
    Cache*, SystemClock*, uint64_t end_time_micros) {
714
60
  last_end_time_micros_ = end_time_micros;
715
60
}
716
717
0
void InternalStats::CacheEntryRoleStats::SkippedCollection() {
718
0
  ++copies_of_last_collection;
719
0
}
720
721
60
uint64_t InternalStats::CacheEntryRoleStats::GetLastDurationMicros() const {
722
60
  if (last_end_time_micros_ > last_start_time_micros_) {
723
60
    return last_end_time_micros_ - last_start_time_micros_;
724
60
  } else {
725
0
    return 0U;
726
0
  }
727
60
}
728
729
std::string InternalStats::CacheEntryRoleStats::ToString(
730
60
    SystemClock* clock) const {
731
60
  std::ostringstream str;
732
60
  str << "Block cache " << cache_id
733
60
      << " capacity: " << BytesToHumanString(cache_capacity)
734
60
      << " seed: " << hash_seed << " usage: " << BytesToHumanString(cache_usage)
735
60
      << " table_size: " << table_size << " occupancy: " << occupancy
736
60
      << " collections: " << collection_count
737
60
      << " last_copies: " << copies_of_last_collection
738
60
      << " last_secs: " << (GetLastDurationMicros() / 1000000.0)
739
60
      << " secs_since: "
740
60
      << ((clock->NowMicros() - last_end_time_micros_) / 1000000U) << "\n";
741
60
  str << "Block cache entry stats(count,size,portion):";
742
900
  for (size_t i = 0; i < kNumCacheEntryRoles; ++i) {
743
840
    if (entry_counts[i] > 0) {
744
63
      str << " " << kCacheEntryRoleToCamelString[i] << "(" << entry_counts[i]
745
63
          << "," << BytesToHumanString(total_charges[i]) << ","
746
63
          << (100.0 * total_charges[i] / cache_capacity) << "%)";
747
63
    }
748
840
  }
749
60
  str << "\n";
750
60
  return str.str();
751
60
}
752
753
void InternalStats::CacheEntryRoleStats::ToMap(
754
0
    std::map<std::string, std::string>* values, SystemClock* clock) const {
755
0
  values->clear();
756
0
  auto& v = *values;
757
0
  v[BlockCacheEntryStatsMapKeys::CacheId()] = cache_id;
758
0
  v[BlockCacheEntryStatsMapKeys::CacheCapacityBytes()] =
759
0
      std::to_string(cache_capacity);
760
0
  v[BlockCacheEntryStatsMapKeys::LastCollectionDurationSeconds()] =
761
0
      std::to_string(GetLastDurationMicros() / 1000000.0);
762
0
  v[BlockCacheEntryStatsMapKeys::LastCollectionAgeSeconds()] =
763
0
      std::to_string((clock->NowMicros() - last_end_time_micros_) / 1000000U);
764
0
  for (size_t i = 0; i < kNumCacheEntryRoles; ++i) {
765
0
    auto role = static_cast<CacheEntryRole>(i);
766
0
    v[BlockCacheEntryStatsMapKeys::EntryCount(role)] =
767
0
        std::to_string(entry_counts[i]);
768
0
    v[BlockCacheEntryStatsMapKeys::UsedBytes(role)] =
769
0
        std::to_string(total_charges[i]);
770
0
    v[BlockCacheEntryStatsMapKeys::UsedPercent(role)] =
771
0
        std::to_string(100.0 * total_charges[i] / cache_capacity);
772
0
  }
773
0
}
774
775
bool InternalStats::HandleBlockCacheEntryStatsInternal(std::string* value,
776
0
                                                       bool fast) {
777
0
  if (!cache_entry_stats_collector_) {
778
0
    return false;
779
0
  }
780
0
  CollectCacheEntryStats(!fast /* foreground */);
781
0
  CacheEntryRoleStats stats;
782
0
  cache_entry_stats_collector_->GetStats(&stats);
783
0
  *value = stats.ToString(clock_);
784
0
  return true;
785
0
}
786
787
bool InternalStats::HandleBlockCacheEntryStatsMapInternal(
788
0
    std::map<std::string, std::string>* values, bool fast) {
789
0
  if (!cache_entry_stats_collector_) {
790
0
    return false;
791
0
  }
792
0
  CollectCacheEntryStats(!fast /* foreground */);
793
0
  CacheEntryRoleStats stats;
794
0
  cache_entry_stats_collector_->GetStats(&stats);
795
0
  stats.ToMap(values, clock_);
796
0
  return true;
797
0
}
798
799
bool InternalStats::HandleBlockCacheEntryStats(std::string* value,
800
0
                                               Slice /*suffix*/) {
801
0
  return HandleBlockCacheEntryStatsInternal(value, false /* fast */);
802
0
}
803
804
bool InternalStats::HandleBlockCacheEntryStatsMap(
805
0
    std::map<std::string, std::string>* values, Slice /*suffix*/) {
806
0
  return HandleBlockCacheEntryStatsMapInternal(values, false /* fast */);
807
0
}
808
809
bool InternalStats::HandleFastBlockCacheEntryStats(std::string* value,
810
0
                                                   Slice /*suffix*/) {
811
0
  return HandleBlockCacheEntryStatsInternal(value, true /* fast */);
812
0
}
813
814
bool InternalStats::HandleFastBlockCacheEntryStatsMap(
815
0
    std::map<std::string, std::string>* values, Slice /*suffix*/) {
816
0
  return HandleBlockCacheEntryStatsMapInternal(values, true /* fast */);
817
0
}
818
819
bool InternalStats::HandleLiveSstFilesSizeAtTemperature(std::string* value,
820
0
                                                        Slice suffix) {
821
0
  uint64_t temperature;
822
0
  bool ok = ConsumeDecimalNumber(&suffix, &temperature) && suffix.empty();
823
0
  if (!ok) {
824
0
    return false;
825
0
  }
826
827
0
  uint64_t size = 0;
828
0
  const auto* vstorage = cfd_->current()->storage_info();
829
0
  for (int level = 0; level < vstorage->num_levels(); level++) {
830
0
    for (const auto& file_meta : vstorage->LevelFiles(level)) {
831
0
      if (static_cast<uint8_t>(file_meta->temperature) == temperature) {
832
0
        size += file_meta->fd.GetFileSize();
833
0
      }
834
0
    }
835
0
  }
836
837
0
  *value = std::to_string(size);
838
0
  return true;
839
0
}
840
841
bool InternalStats::HandleNumBlobFiles(uint64_t* value, DBImpl* /*db*/,
842
0
                                       Version* /*version*/) {
843
0
  assert(value);
844
0
  assert(cfd_);
845
846
0
  const auto* current = cfd_->current();
847
0
  assert(current);
848
849
0
  const auto* vstorage = current->storage_info();
850
0
  assert(vstorage);
851
852
0
  const auto& blob_files = vstorage->GetBlobFiles();
853
854
0
  *value = blob_files.size();
855
856
0
  return true;
857
0
}
858
859
0
bool InternalStats::HandleBlobStats(std::string* value, Slice /*suffix*/) {
860
0
  assert(value);
861
0
  assert(cfd_);
862
863
0
  const auto* current = cfd_->current();
864
0
  assert(current);
865
866
0
  const auto* vstorage = current->storage_info();
867
0
  assert(vstorage);
868
869
0
  const auto blob_st = vstorage->GetBlobStats();
870
871
0
  std::ostringstream oss;
872
873
0
  oss << "Number of blob files: " << vstorage->GetBlobFiles().size()
874
0
      << "\nTotal size of blob files: " << blob_st.total_file_size
875
0
      << "\nTotal size of garbage in blob files: " << blob_st.total_garbage_size
876
0
      << "\nBlob file space amplification: " << blob_st.space_amp << '\n';
877
878
0
  value->append(oss.str());
879
880
0
  return true;
881
0
}
882
883
bool InternalStats::HandleTotalBlobFileSize(uint64_t* value, DBImpl* /*db*/,
884
0
                                            Version* /*version*/) {
885
0
  assert(value);
886
0
  assert(cfd_);
887
888
0
  *value = cfd_->GetTotalBlobFileSize();
889
890
0
  return true;
891
0
}
892
893
bool InternalStats::HandleLiveBlobFileSize(uint64_t* value, DBImpl* /*db*/,
894
0
                                           Version* /*version*/) {
895
0
  assert(value);
896
0
  assert(cfd_);
897
898
0
  const auto* current = cfd_->current();
899
0
  assert(current);
900
901
0
  const auto* vstorage = current->storage_info();
902
0
  assert(vstorage);
903
904
0
  *value = vstorage->GetBlobStats().total_file_size;
905
906
0
  return true;
907
0
}
908
909
bool InternalStats::HandleLiveBlobFileGarbageSize(uint64_t* value,
910
                                                  DBImpl* /*db*/,
911
0
                                                  Version* /*version*/) {
912
0
  assert(value);
913
0
  assert(cfd_);
914
915
0
  const auto* current = cfd_->current();
916
0
  assert(current);
917
918
0
  const auto* vstorage = current->storage_info();
919
0
  assert(vstorage);
920
921
0
  *value = vstorage->GetBlobStats().total_garbage_size;
922
923
0
  return true;
924
0
}
925
926
0
Cache* InternalStats::GetBlobCacheForStats() {
927
0
  return cfd_->ioptions()->blob_cache.get();
928
0
}
929
930
bool InternalStats::HandleBlobCacheCapacity(uint64_t* value, DBImpl* /*db*/,
931
0
                                            Version* /*version*/) {
932
0
  Cache* blob_cache = GetBlobCacheForStats();
933
0
  if (blob_cache) {
934
0
    *value = static_cast<uint64_t>(blob_cache->GetCapacity());
935
0
    return true;
936
0
  }
937
0
  return false;
938
0
}
939
940
bool InternalStats::HandleBlobCacheUsage(uint64_t* value, DBImpl* /*db*/,
941
0
                                         Version* /*version*/) {
942
0
  Cache* blob_cache = GetBlobCacheForStats();
943
0
  if (blob_cache) {
944
0
    *value = static_cast<uint64_t>(blob_cache->GetUsage());
945
0
    return true;
946
0
  }
947
0
  return false;
948
0
}
949
950
bool InternalStats::HandleBlobCachePinnedUsage(uint64_t* value, DBImpl* /*db*/,
951
0
                                               Version* /*version*/) {
952
0
  Cache* blob_cache = GetBlobCacheForStats();
953
0
  if (blob_cache) {
954
0
    *value = static_cast<uint64_t>(blob_cache->GetPinnedUsage());
955
0
    return true;
956
0
  }
957
0
  return false;
958
0
}
959
960
381
const DBPropertyInfo* GetPropertyInfo(const Slice& property) {
961
381
  std::string ppt_name = GetPropertyNameAndArg(property).first.ToString();
962
381
  auto ppt_info_iter = InternalStats::ppt_name_to_info.find(ppt_name);
963
381
  if (ppt_info_iter == InternalStats::ppt_name_to_info.end()) {
964
267
    return nullptr;
965
267
  }
966
114
  return &ppt_info_iter->second;
967
381
}
968
969
bool InternalStats::GetStringProperty(const DBPropertyInfo& property_info,
970
                                      const Slice& property,
971
117
                                      std::string* value) {
972
117
  assert(value != nullptr);
973
117
  assert(property_info.handle_string != nullptr);
974
117
  Slice arg = GetPropertyNameAndArg(property).second;
975
117
  return (this->*(property_info.handle_string))(value, arg);
976
117
}
977
978
bool InternalStats::GetMapProperty(const DBPropertyInfo& property_info,
979
                                   const Slice& property,
980
0
                                   std::map<std::string, std::string>* value) {
981
0
  assert(value != nullptr);
982
0
  assert(property_info.handle_map != nullptr);
983
0
  Slice arg = GetPropertyNameAndArg(property).second;
984
0
  return (this->*(property_info.handle_map))(value, arg);
985
0
}
986
987
bool InternalStats::GetIntProperty(const DBPropertyInfo& property_info,
988
0
                                   uint64_t* value, DBImpl* db) {
989
0
  assert(value != nullptr);
990
0
  assert(property_info.handle_int != nullptr &&
991
0
         !property_info.need_out_of_mutex);
992
0
  db->mutex_.AssertHeld();
993
0
  return (this->*(property_info.handle_int))(value, db, nullptr /* version */);
994
0
}
995
996
bool InternalStats::GetIntPropertyOutOfMutex(
997
0
    const DBPropertyInfo& property_info, Version* version, uint64_t* value) {
998
0
  assert(value != nullptr);
999
0
  assert(property_info.handle_int != nullptr &&
1000
0
         property_info.need_out_of_mutex);
1001
0
  return (this->*(property_info.handle_int))(value, nullptr /* db */, version);
1002
0
}
1003
1004
0
bool InternalStats::HandleNumFilesAtLevel(std::string* value, Slice suffix) {
1005
0
  uint64_t level;
1006
0
  const auto* vstorage = cfd_->current()->storage_info();
1007
0
  bool ok = ConsumeDecimalNumber(&suffix, &level) && suffix.empty();
1008
0
  if (!ok || static_cast<int>(level) >= number_levels_) {
1009
0
    return false;
1010
0
  } else {
1011
0
    char buf[100];
1012
0
    snprintf(buf, sizeof(buf), "%d",
1013
0
             vstorage->NumLevelFiles(static_cast<int>(level)));
1014
0
    *value = buf;
1015
0
    return true;
1016
0
  }
1017
0
}
1018
1019
bool InternalStats::HandleCompressionRatioAtLevelPrefix(std::string* value,
1020
0
                                                        Slice suffix) {
1021
0
  uint64_t level;
1022
0
  const auto* vstorage = cfd_->current()->storage_info();
1023
0
  bool ok = ConsumeDecimalNumber(&suffix, &level) && suffix.empty();
1024
0
  if (!ok || level >= static_cast<uint64_t>(number_levels_)) {
1025
0
    return false;
1026
0
  }
1027
0
  *value = std::to_string(
1028
0
      vstorage->GetEstimatedCompressionRatioAtLevel(static_cast<int>(level)));
1029
0
  return true;
1030
0
}
1031
1032
0
bool InternalStats::HandleLevelStats(std::string* value, Slice /*suffix*/) {
1033
0
  char buf[1000];
1034
0
  const auto* vstorage = cfd_->current()->storage_info();
1035
0
  snprintf(buf, sizeof(buf),
1036
0
           "Level Files Size(MB)\n"
1037
0
           "--------------------\n");
1038
0
  value->append(buf);
1039
1040
0
  for (int level = 0; level < number_levels_; level++) {
1041
0
    snprintf(buf, sizeof(buf), "%3d %8d %8.0f\n", level,
1042
0
             vstorage->NumLevelFiles(level),
1043
0
             vstorage->NumLevelBytes(level) / kMB);
1044
0
    value->append(buf);
1045
0
  }
1046
0
  return true;
1047
0
}
1048
1049
0
bool InternalStats::HandleStats(std::string* value, Slice suffix) {
1050
0
  if (!HandleCFStats(value, suffix)) {
1051
0
    return false;
1052
0
  }
1053
0
  if (!HandleDBStats(value, suffix)) {
1054
0
    return false;
1055
0
  }
1056
0
  return true;
1057
0
}
1058
1059
bool InternalStats::HandleCFMapStats(
1060
0
    std::map<std::string, std::string>* cf_stats, Slice /*suffix*/) {
1061
0
  DumpCFMapStats(cf_stats);
1062
0
  return true;
1063
0
}
1064
1065
0
bool InternalStats::HandleCFStats(std::string* value, Slice /*suffix*/) {
1066
0
  DumpCFStats(value);
1067
0
  return true;
1068
0
}
1069
1070
bool InternalStats::HandleCFStatsPeriodic(std::string* value,
1071
60
                                          Slice /*suffix*/) {
1072
60
  bool has_change = has_cf_change_since_dump_;
1073
60
  if (!has_change) {
1074
    // If file histogram changes, there is activity in this period too.
1075
0
    uint64_t new_histogram_num = 0;
1076
0
    for (int level = 0; level < number_levels_; level++) {
1077
0
      new_histogram_num += file_read_latency_[level].num();
1078
0
    }
1079
0
    new_histogram_num += blob_file_read_latency_.num();
1080
0
    if (new_histogram_num != last_histogram_num) {
1081
0
      has_change = true;
1082
0
      last_histogram_num = new_histogram_num;
1083
0
    }
1084
0
  }
1085
60
  if (has_change) {
1086
60
    no_cf_change_period_since_dump_ = 0;
1087
60
    has_cf_change_since_dump_ = false;
1088
60
  } else if (no_cf_change_period_since_dump_++ > 0) {
1089
    // Not ready to sync
1090
0
    if (no_cf_change_period_since_dump_ == kMaxNoChangePeriodSinceDump) {
1091
      // Next periodic, we need to dump stats even if there is no change.
1092
0
      no_cf_change_period_since_dump_ = 0;
1093
0
    }
1094
0
    return true;
1095
0
  }
1096
1097
60
  DumpCFStatsNoFileHistogram(/*is_periodic=*/true, value);
1098
60
  DumpCFFileHistogram(value);
1099
60
  return true;
1100
60
}
1101
1102
bool InternalStats::HandleCFStatsNoFileHistogram(std::string* value,
1103
0
                                                 Slice /*suffix*/) {
1104
0
  DumpCFStatsNoFileHistogram(/*is_periodic=*/false, value);
1105
0
  return true;
1106
0
}
1107
1108
bool InternalStats::HandleCFFileHistogram(std::string* value,
1109
0
                                          Slice /*suffix*/) {
1110
0
  DumpCFFileHistogram(value);
1111
0
  return true;
1112
0
}
1113
1114
bool InternalStats::HandleCFWriteStallStats(std::string* value,
1115
0
                                            Slice /*suffix*/) {
1116
0
  DumpCFStatsWriteStall(value);
1117
0
  return true;
1118
0
}
1119
1120
bool InternalStats::HandleCFWriteStallStatsMap(
1121
0
    std::map<std::string, std::string>* value, Slice /*suffix*/) {
1122
0
  DumpCFMapStatsWriteStall(value);
1123
0
  return true;
1124
0
}
1125
1126
bool InternalStats::HandleDBMapStats(
1127
0
    std::map<std::string, std::string>* db_stats, Slice /*suffix*/) {
1128
0
  DumpDBMapStats(db_stats);
1129
0
  return true;
1130
0
}
1131
1132
57
bool InternalStats::HandleDBStats(std::string* value, Slice /*suffix*/) {
1133
57
  DumpDBStats(value);
1134
57
  return true;
1135
57
}
1136
1137
bool InternalStats::HandleDBWriteStallStats(std::string* value,
1138
0
                                            Slice /*suffix*/) {
1139
0
  DumpDBStatsWriteStall(value);
1140
0
  return true;
1141
0
}
1142
1143
bool InternalStats::HandleDBWriteStallStatsMap(
1144
0
    std::map<std::string, std::string>* value, Slice /*suffix*/) {
1145
0
  DumpDBMapStatsWriteStall(value);
1146
0
  return true;
1147
0
}
1148
1149
0
bool InternalStats::HandleSsTables(std::string* value, Slice /*suffix*/) {
1150
0
  auto* current = cfd_->current();
1151
0
  *value = current->DebugString(true, true);
1152
0
  return true;
1153
0
}
1154
1155
bool InternalStats::HandleAggregatedTableProperties(std::string* value,
1156
0
                                                    Slice /*suffix*/) {
1157
0
  std::shared_ptr<const TableProperties> tp;
1158
  // TODO: plumb Env::IOActivity, Env::IOPriority
1159
0
  const ReadOptions read_options;
1160
0
  auto s = cfd_->current()->GetAggregatedTableProperties(read_options, &tp);
1161
0
  if (!s.ok()) {
1162
0
    return false;
1163
0
  }
1164
0
  *value = tp->ToString();
1165
0
  return true;
1166
0
}
1167
1168
static std::map<std::string, std::string> MapUint64ValuesToString(
1169
0
    const std::map<std::string, uint64_t>& from) {
1170
0
  std::map<std::string, std::string> to;
1171
0
  for (const auto& e : from) {
1172
0
    to[e.first] = std::to_string(e.second);
1173
0
  }
1174
0
  return to;
1175
0
}
1176
1177
bool InternalStats::HandleAggregatedTablePropertiesMap(
1178
0
    std::map<std::string, std::string>* values, Slice /*suffix*/) {
1179
0
  std::shared_ptr<const TableProperties> tp;
1180
  // TODO: plumb Env::IOActivity, Env::IOPriority
1181
0
  const ReadOptions read_options;
1182
0
  auto s = cfd_->current()->GetAggregatedTableProperties(read_options, &tp);
1183
0
  if (!s.ok()) {
1184
0
    return false;
1185
0
  }
1186
0
  *values = MapUint64ValuesToString(tp->GetAggregatablePropertiesAsMap());
1187
0
  return true;
1188
0
}
1189
1190
bool InternalStats::HandleAggregatedTablePropertiesAtLevel(std::string* values,
1191
0
                                                           Slice suffix) {
1192
0
  uint64_t level;
1193
0
  bool ok = ConsumeDecimalNumber(&suffix, &level) && suffix.empty();
1194
0
  if (!ok || static_cast<int>(level) >= number_levels_) {
1195
0
    return false;
1196
0
  }
1197
0
  std::shared_ptr<const TableProperties> tp;
1198
  // TODO: plumb Env::IOActivity, Env::IOPriority
1199
0
  const ReadOptions read_options;
1200
0
  auto s = cfd_->current()->GetAggregatedTableProperties(
1201
0
      read_options, &tp, static_cast<int>(level));
1202
0
  if (!s.ok()) {
1203
0
    return false;
1204
0
  }
1205
0
  *values = tp->ToString();
1206
0
  return true;
1207
0
}
1208
1209
bool InternalStats::HandleAggregatedTablePropertiesAtLevelMap(
1210
0
    std::map<std::string, std::string>* values, Slice suffix) {
1211
0
  uint64_t level;
1212
0
  bool ok = ConsumeDecimalNumber(&suffix, &level) && suffix.empty();
1213
0
  if (!ok || static_cast<int>(level) >= number_levels_) {
1214
0
    return false;
1215
0
  }
1216
0
  std::shared_ptr<const TableProperties> tp;
1217
  // TODO: plumb Env::IOActivity, Env::IOPriority
1218
0
  const ReadOptions read_options;
1219
0
  auto s = cfd_->current()->GetAggregatedTableProperties(
1220
0
      read_options, &tp, static_cast<int>(level));
1221
0
  if (!s.ok()) {
1222
0
    return false;
1223
0
  }
1224
0
  *values = MapUint64ValuesToString(tp->GetAggregatablePropertiesAsMap());
1225
0
  return true;
1226
0
}
1227
1228
bool InternalStats::HandleNumImmutableMemTable(uint64_t* value, DBImpl* /*db*/,
1229
0
                                               Version* /*version*/) {
1230
0
  *value = cfd_->imm()->NumNotFlushed();
1231
0
  return true;
1232
0
}
1233
1234
bool InternalStats::HandleNumImmutableMemTableFlushed(uint64_t* value,
1235
                                                      DBImpl* /*db*/,
1236
0
                                                      Version* /*version*/) {
1237
0
  *value = cfd_->imm()->NumFlushed();
1238
0
  return true;
1239
0
}
1240
1241
bool InternalStats::HandleMemTableFlushPending(uint64_t* value, DBImpl* /*db*/,
1242
0
                                               Version* /*version*/) {
1243
0
  *value = (cfd_->imm()->IsFlushPending() ? 1 : 0);
1244
0
  return true;
1245
0
}
1246
1247
bool InternalStats::HandleNumRunningFlushes(uint64_t* value, DBImpl* db,
1248
0
                                            Version* /*version*/) {
1249
0
  *value = db->num_running_flushes();
1250
0
  return true;
1251
0
}
1252
1253
bool InternalStats::HandleCompactionPending(uint64_t* value, DBImpl* /*db*/,
1254
0
                                            Version* /*version*/) {
1255
  // 1 if the system already determines at least one compaction is needed.
1256
  // 0 otherwise,
1257
0
  const auto* vstorage = cfd_->current()->storage_info();
1258
0
  *value = (cfd_->compaction_picker()->NeedsCompaction(vstorage) ? 1 : 0);
1259
0
  return true;
1260
0
}
1261
1262
bool InternalStats::HandleNumRunningCompactions(uint64_t* value, DBImpl* db,
1263
0
                                                Version* /*version*/) {
1264
0
  *value = db->num_running_compactions_;
1265
0
  return true;
1266
0
}
1267
1268
bool InternalStats::HandleBackgroundErrors(uint64_t* value, DBImpl* /*db*/,
1269
0
                                           Version* /*version*/) {
1270
  // Accumulated number of  errors in background flushes or compactions.
1271
0
  *value = GetBackgroundErrorCount();
1272
0
  return true;
1273
0
}
1274
1275
bool InternalStats::HandleCurSizeActiveMemTable(uint64_t* value, DBImpl* /*db*/,
1276
0
                                                Version* /*version*/) {
1277
  // Current size of the active memtable
1278
  // Using ApproximateMemoryUsageFast to avoid the need for synchronization
1279
0
  *value = cfd_->mem()->ApproximateMemoryUsageFast();
1280
0
  return true;
1281
0
}
1282
1283
bool InternalStats::HandleCurSizeAllMemTables(uint64_t* value, DBImpl* /*db*/,
1284
0
                                              Version* /*version*/) {
1285
  // Current size of the active memtable + immutable memtables
1286
  // Using ApproximateMemoryUsageFast to avoid the need for synchronization
1287
0
  *value = cfd_->mem()->ApproximateMemoryUsageFast() +
1288
0
           cfd_->imm()->ApproximateUnflushedMemTablesMemoryUsage();
1289
0
  return true;
1290
0
}
1291
1292
bool InternalStats::HandleSizeAllMemTables(uint64_t* value, DBImpl* /*db*/,
1293
0
                                           Version* /*version*/) {
1294
  // Using ApproximateMemoryUsageFast to avoid the need for synchronization
1295
0
  *value = cfd_->mem()->ApproximateMemoryUsageFast() +
1296
0
           cfd_->imm()->ApproximateMemoryUsage();
1297
0
  return true;
1298
0
}
1299
1300
bool InternalStats::HandleNumEntriesActiveMemTable(uint64_t* value,
1301
                                                   DBImpl* /*db*/,
1302
0
                                                   Version* /*version*/) {
1303
  // Current number of entires in the active memtable
1304
0
  *value = cfd_->mem()->num_entries();
1305
0
  return true;
1306
0
}
1307
1308
bool InternalStats::HandleNumEntriesImmMemTables(uint64_t* value,
1309
                                                 DBImpl* /*db*/,
1310
0
                                                 Version* /*version*/) {
1311
  // Current number of entries in the immutable memtables
1312
0
  *value = cfd_->imm()->current()->GetTotalNumEntries();
1313
0
  return true;
1314
0
}
1315
1316
bool InternalStats::HandleNumDeletesActiveMemTable(uint64_t* value,
1317
                                                   DBImpl* /*db*/,
1318
0
                                                   Version* /*version*/) {
1319
  // Current number of entires in the active memtable
1320
0
  *value = cfd_->mem()->num_deletes();
1321
0
  return true;
1322
0
}
1323
1324
bool InternalStats::HandleNumDeletesImmMemTables(uint64_t* value,
1325
                                                 DBImpl* /*db*/,
1326
0
                                                 Version* /*version*/) {
1327
  // Current number of entries in the immutable memtables
1328
0
  *value = cfd_->imm()->current()->GetTotalNumDeletes();
1329
0
  return true;
1330
0
}
1331
1332
bool InternalStats::HandleEstimateNumKeys(uint64_t* value, DBImpl* /*db*/,
1333
0
                                          Version* /*version*/) {
1334
  // Estimate number of entries in the column family:
1335
  // Use estimated entries in tables + total entries in memtables.
1336
0
  const auto* vstorage = cfd_->current()->storage_info();
1337
0
  uint64_t estimate_keys = cfd_->mem()->num_entries() +
1338
0
                           cfd_->imm()->current()->GetTotalNumEntries() +
1339
0
                           vstorage->GetEstimatedActiveKeys();
1340
0
  uint64_t estimate_deletes =
1341
0
      cfd_->mem()->num_deletes() + cfd_->imm()->current()->GetTotalNumDeletes();
1342
0
  *value = estimate_keys > estimate_deletes * 2
1343
0
               ? estimate_keys - (estimate_deletes * 2)
1344
0
               : 0;
1345
0
  return true;
1346
0
}
1347
1348
bool InternalStats::HandleNumSnapshots(uint64_t* value, DBImpl* db,
1349
0
                                       Version* /*version*/) {
1350
0
  *value = db->snapshots().count();
1351
0
  return true;
1352
0
}
1353
1354
bool InternalStats::HandleOldestSnapshotTime(uint64_t* value, DBImpl* db,
1355
0
                                             Version* /*version*/) {
1356
0
  *value = static_cast<uint64_t>(db->snapshots().GetOldestSnapshotTime());
1357
0
  return true;
1358
0
}
1359
1360
bool InternalStats::HandleOldestSnapshotSequence(uint64_t* value, DBImpl* db,
1361
0
                                                 Version* /*version*/) {
1362
0
  *value = static_cast<uint64_t>(db->snapshots().GetOldestSnapshotSequence());
1363
0
  return true;
1364
0
}
1365
1366
bool InternalStats::HandleNumLiveVersions(uint64_t* value, DBImpl* /*db*/,
1367
0
                                          Version* /*version*/) {
1368
0
  *value = cfd_->GetNumLiveVersions();
1369
0
  return true;
1370
0
}
1371
1372
bool InternalStats::HandleCurrentSuperVersionNumber(uint64_t* value,
1373
                                                    DBImpl* /*db*/,
1374
0
                                                    Version* /*version*/) {
1375
0
  *value = cfd_->GetSuperVersionNumber();
1376
0
  return true;
1377
0
}
1378
1379
bool InternalStats::HandleIsFileDeletionsEnabled(uint64_t* value, DBImpl* db,
1380
0
                                                 Version* /*version*/) {
1381
0
  *value = db->IsFileDeletionsEnabled() ? 1 : 0;
1382
0
  return true;
1383
0
}
1384
1385
bool InternalStats::HandleBaseLevel(uint64_t* value, DBImpl* /*db*/,
1386
0
                                    Version* /*version*/) {
1387
0
  const auto* vstorage = cfd_->current()->storage_info();
1388
0
  *value = vstorage->base_level();
1389
0
  return true;
1390
0
}
1391
1392
bool InternalStats::HandleTotalSstFilesSize(uint64_t* value, DBImpl* /*db*/,
1393
0
                                            Version* /*version*/) {
1394
0
  *value = cfd_->GetTotalSstFilesSize();
1395
0
  return true;
1396
0
}
1397
1398
bool InternalStats::HandleLiveSstFilesSize(uint64_t* value, DBImpl* /*db*/,
1399
0
                                           Version* /*version*/) {
1400
0
  *value = cfd_->GetLiveSstFilesSize();
1401
0
  return true;
1402
0
}
1403
1404
bool InternalStats::HandleObsoleteSstFilesSize(uint64_t* value, DBImpl* db,
1405
0
                                               Version* /*version*/) {
1406
0
  *value = db->GetObsoleteSstFilesSize();
1407
0
  return true;
1408
0
}
1409
1410
bool InternalStats::HandleEstimatePendingCompactionBytes(uint64_t* value,
1411
                                                         DBImpl* /*db*/,
1412
0
                                                         Version* /*version*/) {
1413
0
  const auto* vstorage = cfd_->current()->storage_info();
1414
0
  *value = vstorage->estimated_compaction_needed_bytes();
1415
0
  return true;
1416
0
}
1417
1418
bool InternalStats::HandleEstimateTableReadersMem(uint64_t* value,
1419
                                                  DBImpl* /*db*/,
1420
0
                                                  Version* version) {
1421
  // TODO: plumb Env::IOActivity, Env::IOPriority
1422
0
  const ReadOptions read_options;
1423
0
  *value = (version == nullptr)
1424
0
               ? 0
1425
0
               : version->GetMemoryUsageByTableReaders(read_options);
1426
0
  return true;
1427
0
}
1428
1429
bool InternalStats::HandleEstimateLiveDataSize(uint64_t* value, DBImpl* /*db*/,
1430
0
                                               Version* version) {
1431
0
  const auto* vstorage = version->storage_info();
1432
0
  *value = vstorage->EstimateLiveDataSize();
1433
0
  return true;
1434
0
}
1435
1436
bool InternalStats::HandleMinLogNumberToKeep(uint64_t* value, DBImpl* db,
1437
0
                                             Version* /*version*/) {
1438
0
  *value = db->MinLogNumberToKeep();
1439
0
  return true;
1440
0
}
1441
1442
bool InternalStats::HandleMinObsoleteSstNumberToKeep(uint64_t* value,
1443
                                                     DBImpl* db,
1444
0
                                                     Version* /*version*/) {
1445
0
  *value = db->MinObsoleteSstNumberToKeep();
1446
0
  return true;
1447
0
}
1448
1449
bool InternalStats::HandleActualDelayedWriteRate(uint64_t* value, DBImpl* db,
1450
0
                                                 Version* /*version*/) {
1451
0
  const WriteController& wc = db->write_controller();
1452
0
  if (!wc.NeedsDelay()) {
1453
0
    *value = 0;
1454
0
  } else {
1455
0
    *value = wc.delayed_write_rate();
1456
0
  }
1457
0
  return true;
1458
0
}
1459
1460
bool InternalStats::HandleIsWriteStopped(uint64_t* value, DBImpl* db,
1461
0
                                         Version* /*version*/) {
1462
0
  *value = db->write_controller().IsStopped() ? 1 : 0;
1463
0
  return true;
1464
0
}
1465
1466
bool InternalStats::HandleEstimateOldestKeyTime(uint64_t* value, DBImpl* /*db*/,
1467
0
                                                Version* /*version*/) {
1468
  // TODO(yiwu): The property is currently available for fifo compaction
1469
  // with allow_compaction = false. This is because we don't propagate
1470
  // oldest_key_time on compaction.
1471
0
  if (cfd_->ioptions()->compaction_style != kCompactionStyleFIFO ||
1472
0
      cfd_->GetCurrentMutableCFOptions()
1473
0
          ->compaction_options_fifo.allow_compaction) {
1474
0
    return false;
1475
0
  }
1476
  // TODO: plumb Env::IOActivity, Env::IOPriority
1477
0
  const ReadOptions read_options;
1478
0
  TablePropertiesCollection collection;
1479
0
  auto s = cfd_->current()->GetPropertiesOfAllTables(read_options, &collection);
1480
0
  if (!s.ok()) {
1481
0
    return false;
1482
0
  }
1483
0
  *value = std::numeric_limits<uint64_t>::max();
1484
0
  for (auto& p : collection) {
1485
0
    *value = std::min(*value, p.second->oldest_key_time);
1486
0
    if (*value == 0) {
1487
0
      break;
1488
0
    }
1489
0
  }
1490
0
  if (*value > 0) {
1491
0
    *value = std::min({cfd_->mem()->ApproximateOldestKeyTime(),
1492
0
                       cfd_->imm()->ApproximateOldestKeyTime(), *value});
1493
0
  }
1494
0
  return *value > 0 && *value < std::numeric_limits<uint64_t>::max();
1495
0
}
1496
1497
12.0k
Cache* InternalStats::GetBlockCacheForStats() {
1498
12.0k
  auto* table_factory = cfd_->ioptions()->table_factory.get();
1499
12.0k
  assert(table_factory != nullptr);
1500
12.0k
  return table_factory->GetOptions<Cache>(TableFactory::kBlockCacheOpts());
1501
12.0k
}
1502
1503
bool InternalStats::HandleBlockCacheCapacity(uint64_t* value, DBImpl* /*db*/,
1504
0
                                             Version* /*version*/) {
1505
0
  Cache* block_cache = GetBlockCacheForStats();
1506
0
  if (block_cache) {
1507
0
    *value = static_cast<uint64_t>(block_cache->GetCapacity());
1508
0
    return true;
1509
0
  }
1510
0
  return false;
1511
0
}
1512
1513
bool InternalStats::HandleBlockCacheUsage(uint64_t* value, DBImpl* /*db*/,
1514
0
                                          Version* /*version*/) {
1515
0
  Cache* block_cache = GetBlockCacheForStats();
1516
0
  if (block_cache) {
1517
0
    *value = static_cast<uint64_t>(block_cache->GetUsage());
1518
0
    return true;
1519
0
  }
1520
0
  return false;
1521
0
}
1522
1523
bool InternalStats::HandleBlockCachePinnedUsage(uint64_t* value, DBImpl* /*db*/,
1524
0
                                                Version* /*version*/) {
1525
0
  Cache* block_cache = GetBlockCacheForStats();
1526
0
  if (block_cache) {
1527
0
    *value = static_cast<uint64_t>(block_cache->GetPinnedUsage());
1528
0
    return true;
1529
0
  }
1530
0
  return false;
1531
0
}
1532
1533
void InternalStats::DumpDBMapStats(
1534
0
    std::map<std::string, std::string>* db_stats) {
1535
0
  for (int i = 0; i < static_cast<int>(kIntStatsNumMax); ++i) {
1536
0
    InternalDBStatsType type = static_cast<InternalDBStatsType>(i);
1537
0
    (*db_stats)[db_stats_type_to_info.at(type).property_name] =
1538
0
        std::to_string(GetDBStats(type));
1539
0
  }
1540
0
  double seconds_up = (clock_->NowMicros() - started_at_) / kMicrosInSec;
1541
0
  (*db_stats)["db.uptime"] = std::to_string(seconds_up);
1542
0
}
1543
1544
57
void InternalStats::DumpDBStats(std::string* value) {
1545
57
  char buf[1000];
1546
  // DB-level stats, only available from default column family
1547
57
  double seconds_up = (clock_->NowMicros() - started_at_) / kMicrosInSec;
1548
57
  double interval_seconds_up = seconds_up - db_stats_snapshot_.seconds_up;
1549
57
  snprintf(buf, sizeof(buf),
1550
57
           "\n** DB Stats **\nUptime(secs): %.1f total, %.1f interval\n",
1551
57
           seconds_up, interval_seconds_up);
1552
57
  value->append(buf);
1553
  // Cumulative
1554
57
  uint64_t user_bytes_written =
1555
57
      GetDBStats(InternalStats::kIntStatsBytesWritten);
1556
57
  uint64_t num_keys_written =
1557
57
      GetDBStats(InternalStats::kIntStatsNumKeysWritten);
1558
57
  uint64_t write_other = GetDBStats(InternalStats::kIntStatsWriteDoneByOther);
1559
57
  uint64_t write_self = GetDBStats(InternalStats::kIntStatsWriteDoneBySelf);
1560
57
  uint64_t wal_bytes = GetDBStats(InternalStats::kIntStatsWalFileBytes);
1561
57
  uint64_t wal_synced = GetDBStats(InternalStats::kIntStatsWalFileSynced);
1562
57
  uint64_t write_with_wal = GetDBStats(InternalStats::kIntStatsWriteWithWal);
1563
57
  uint64_t write_stall_micros =
1564
57
      GetDBStats(InternalStats::kIntStatsWriteStallMicros);
1565
1566
57
  const int kHumanMicrosLen = 32;
1567
57
  char human_micros[kHumanMicrosLen];
1568
1569
  // Data
1570
  // writes: total number of write requests.
1571
  // keys: total number of key updates issued by all the write requests
1572
  // commit groups: number of group commits issued to the DB. Each group can
1573
  //                contain one or more writes.
1574
  // so writes/keys is the average number of put in multi-put or put
1575
  // writes/groups is the average group commit size.
1576
  //
1577
  // The format is the same for interval stats.
1578
57
  snprintf(buf, sizeof(buf),
1579
57
           "Cumulative writes: %s writes, %s keys, %s commit groups, "
1580
57
           "%.1f writes per commit group, ingest: %.2f GB, %.2f MB/s\n",
1581
57
           NumberToHumanString(write_other + write_self).c_str(),
1582
57
           NumberToHumanString(num_keys_written).c_str(),
1583
57
           NumberToHumanString(write_self).c_str(),
1584
57
           (write_other + write_self) /
1585
57
               std::max(1.0, static_cast<double>(write_self)),
1586
57
           user_bytes_written / kGB,
1587
57
           user_bytes_written / kMB / std::max(seconds_up, 0.001));
1588
57
  value->append(buf);
1589
  // WAL
1590
57
  snprintf(buf, sizeof(buf),
1591
57
           "Cumulative WAL: %s writes, %s syncs, "
1592
57
           "%.2f writes per sync, written: %.2f GB, %.2f MB/s\n",
1593
57
           NumberToHumanString(write_with_wal).c_str(),
1594
57
           NumberToHumanString(wal_synced).c_str(),
1595
57
           write_with_wal / std::max(1.0, static_cast<double>(wal_synced)),
1596
57
           wal_bytes / kGB, wal_bytes / kMB / std::max(seconds_up, 0.001));
1597
57
  value->append(buf);
1598
  // Stall
1599
57
  AppendHumanMicros(write_stall_micros, human_micros, kHumanMicrosLen, true);
1600
57
  snprintf(buf, sizeof(buf), "Cumulative stall: %s, %.1f percent\n",
1601
57
           human_micros,
1602
           // 10000 = divide by 1M to get secs, then multiply by 100 for pct
1603
57
           write_stall_micros / 10000.0 / std::max(seconds_up, 0.001));
1604
57
  value->append(buf);
1605
1606
  // Interval
1607
57
  uint64_t interval_write_other = write_other - db_stats_snapshot_.write_other;
1608
57
  uint64_t interval_write_self = write_self - db_stats_snapshot_.write_self;
1609
57
  uint64_t interval_num_keys_written =
1610
57
      num_keys_written - db_stats_snapshot_.num_keys_written;
1611
57
  snprintf(
1612
57
      buf, sizeof(buf),
1613
57
      "Interval writes: %s writes, %s keys, %s commit groups, "
1614
57
      "%.1f writes per commit group, ingest: %.2f MB, %.2f MB/s\n",
1615
57
      NumberToHumanString(interval_write_other + interval_write_self).c_str(),
1616
57
      NumberToHumanString(interval_num_keys_written).c_str(),
1617
57
      NumberToHumanString(interval_write_self).c_str(),
1618
57
      static_cast<double>(interval_write_other + interval_write_self) /
1619
57
          std::max(1.0, static_cast<double>(interval_write_self)),
1620
57
      (user_bytes_written - db_stats_snapshot_.ingest_bytes) / kMB,
1621
57
      (user_bytes_written - db_stats_snapshot_.ingest_bytes) / kMB /
1622
57
          std::max(interval_seconds_up, 0.001)),
1623
57
      value->append(buf);
1624
1625
57
  uint64_t interval_write_with_wal =
1626
57
      write_with_wal - db_stats_snapshot_.write_with_wal;
1627
57
  uint64_t interval_wal_synced = wal_synced - db_stats_snapshot_.wal_synced;
1628
57
  uint64_t interval_wal_bytes = wal_bytes - db_stats_snapshot_.wal_bytes;
1629
1630
57
  snprintf(buf, sizeof(buf),
1631
57
           "Interval WAL: %s writes, %s syncs, "
1632
57
           "%.2f writes per sync, written: %.2f GB, %.2f MB/s\n",
1633
57
           NumberToHumanString(interval_write_with_wal).c_str(),
1634
57
           NumberToHumanString(interval_wal_synced).c_str(),
1635
57
           interval_write_with_wal /
1636
57
               std::max(1.0, static_cast<double>(interval_wal_synced)),
1637
57
           interval_wal_bytes / kGB,
1638
57
           interval_wal_bytes / kMB / std::max(interval_seconds_up, 0.001));
1639
57
  value->append(buf);
1640
1641
  // Stall
1642
57
  AppendHumanMicros(write_stall_micros - db_stats_snapshot_.write_stall_micros,
1643
57
                    human_micros, kHumanMicrosLen, true);
1644
57
  snprintf(buf, sizeof(buf), "Interval stall: %s, %.1f percent\n", human_micros,
1645
           // 10000 = divide by 1M to get secs, then multiply by 100 for pct
1646
57
           (write_stall_micros - db_stats_snapshot_.write_stall_micros) /
1647
57
               10000.0 / std::max(interval_seconds_up, 0.001));
1648
57
  value->append(buf);
1649
1650
57
  std::string write_stall_stats;
1651
57
  DumpDBStatsWriteStall(&write_stall_stats);
1652
57
  value->append(write_stall_stats);
1653
1654
57
  db_stats_snapshot_.seconds_up = seconds_up;
1655
57
  db_stats_snapshot_.ingest_bytes = user_bytes_written;
1656
57
  db_stats_snapshot_.write_other = write_other;
1657
57
  db_stats_snapshot_.write_self = write_self;
1658
57
  db_stats_snapshot_.num_keys_written = num_keys_written;
1659
57
  db_stats_snapshot_.wal_bytes = wal_bytes;
1660
57
  db_stats_snapshot_.wal_synced = wal_synced;
1661
57
  db_stats_snapshot_.write_with_wal = write_with_wal;
1662
57
  db_stats_snapshot_.write_stall_micros = write_stall_micros;
1663
57
}
1664
1665
void InternalStats::DumpDBMapStatsWriteStall(
1666
57
    std::map<std::string, std::string>* value) {
1667
57
  constexpr uint32_t max_db_scope_write_stall_cause =
1668
57
      static_cast<uint32_t>(WriteStallCause::kDBScopeWriteStallCauseEnumMax);
1669
1670
57
  for (uint32_t i =
1671
57
           max_db_scope_write_stall_cause - kNumDBScopeWriteStallCauses;
1672
114
       i < max_db_scope_write_stall_cause; ++i) {
1673
57
    for (uint32_t j = 0;
1674
171
         j < static_cast<uint32_t>(WriteStallCondition::kNormal); ++j) {
1675
114
      WriteStallCause cause = static_cast<WriteStallCause>(i);
1676
114
      WriteStallCondition condition = static_cast<WriteStallCondition>(j);
1677
114
      InternalStats::InternalDBStatsType internal_db_stat =
1678
114
          InternalDBStat(cause, condition);
1679
1680
114
      if (internal_db_stat == InternalStats::kIntStatsNumMax) {
1681
57
        continue;
1682
57
      }
1683
1684
57
      std::string name =
1685
57
          WriteStallStatsMapKeys::CauseConditionCount(cause, condition);
1686
57
      uint64_t stat =
1687
57
          db_stats_[static_cast<std::size_t>(internal_db_stat)].load(
1688
57
              std::memory_order_relaxed);
1689
57
      (*value)[name] = std::to_string(stat);
1690
57
    }
1691
57
  }
1692
57
}
1693
1694
57
void InternalStats::DumpDBStatsWriteStall(std::string* value) {
1695
57
  assert(value);
1696
1697
57
  std::map<std::string, std::string> write_stall_stats_map;
1698
57
  DumpDBMapStatsWriteStall(&write_stall_stats_map);
1699
1700
57
  std::ostringstream str;
1701
57
  str << "Write Stall (count): ";
1702
1703
57
  for (auto write_stall_stats_map_iter = write_stall_stats_map.begin();
1704
114
       write_stall_stats_map_iter != write_stall_stats_map.end();
1705
57
       write_stall_stats_map_iter++) {
1706
57
    const auto& name_and_stat = *write_stall_stats_map_iter;
1707
57
    str << name_and_stat.first << ": " << name_and_stat.second;
1708
57
    if (std::next(write_stall_stats_map_iter) == write_stall_stats_map.end()) {
1709
57
      str << "\n";
1710
57
    } else {
1711
0
      str << ", ";
1712
0
    }
1713
57
  }
1714
57
  *value = str.str();
1715
57
}
1716
1717
/**
1718
 * Dump Compaction Level stats to a map of stat name with "compaction." prefix
1719
 * to value in double as string. The level in stat name is represented with
1720
 * a prefix "Lx" where "x" is the level number. A special level "Sum"
1721
 * represents the sum of a stat for all levels.
1722
 * The result also contains IO stall counters which keys start with "io_stalls."
1723
 * and values represent uint64 encoded as strings.
1724
 */
1725
void InternalStats::DumpCFMapStats(
1726
0
    std::map<std::string, std::string>* cf_stats) {
1727
0
  const VersionStorageInfo* vstorage = cfd_->current()->storage_info();
1728
0
  CompactionStats compaction_stats_sum;
1729
0
  std::map<int, std::map<LevelStatType, double>> levels_stats;
1730
0
  DumpCFMapStats(vstorage, &levels_stats, &compaction_stats_sum);
1731
0
  for (auto const& level_ent : levels_stats) {
1732
0
    auto level_str =
1733
0
        level_ent.first == -1 ? "Sum" : "L" + std::to_string(level_ent.first);
1734
0
    for (auto const& stat_ent : level_ent.second) {
1735
0
      auto stat_type = stat_ent.first;
1736
0
      auto key_str =
1737
0
          "compaction." + level_str + "." +
1738
0
          InternalStats::compaction_level_stats.at(stat_type).property_name;
1739
0
      (*cf_stats)[key_str] = std::to_string(stat_ent.second);
1740
0
    }
1741
0
  }
1742
1743
0
  DumpCFMapStatsWriteStall(cf_stats);
1744
0
}
1745
1746
void InternalStats::DumpCFMapStats(
1747
    const VersionStorageInfo* vstorage,
1748
    std::map<int, std::map<LevelStatType, double>>* levels_stats,
1749
60
    CompactionStats* compaction_stats_sum) {
1750
60
  assert(vstorage);
1751
1752
60
  int num_levels_to_check =
1753
60
      (cfd_->ioptions()->compaction_style == kCompactionStyleLevel)
1754
60
          ? vstorage->num_levels() - 1
1755
60
          : 1;
1756
1757
  // Compaction scores are sorted based on its value. Restore them to the
1758
  // level order
1759
60
  std::vector<double> compaction_score(number_levels_, 0);
1760
420
  for (int i = 0; i < num_levels_to_check; ++i) {
1761
360
    compaction_score[vstorage->CompactionScoreLevel(i)] =
1762
360
        vstorage->CompactionScore(i);
1763
360
  }
1764
  // Count # of files being compacted for each level
1765
60
  std::vector<int> files_being_compacted(number_levels_, 0);
1766
480
  for (int level = 0; level < number_levels_; ++level) {
1767
420
    for (auto* f : vstorage->LevelFiles(level)) {
1768
13
      if (f->being_compacted) {
1769
5
        ++files_being_compacted[level];
1770
5
      }
1771
13
    }
1772
420
  }
1773
1774
60
  int total_files = 0;
1775
60
  int total_files_being_compacted = 0;
1776
60
  double total_file_size = 0;
1777
60
  uint64_t flush_ingest = cf_stats_value_[BYTES_FLUSHED];
1778
60
  uint64_t add_file_ingest = cf_stats_value_[BYTES_INGESTED_ADD_FILE];
1779
60
  uint64_t curr_ingest = flush_ingest + add_file_ingest;
1780
480
  for (int level = 0; level < number_levels_; level++) {
1781
420
    int files = vstorage->NumLevelFiles(level);
1782
420
    total_files += files;
1783
420
    total_files_being_compacted += files_being_compacted[level];
1784
420
    if (comp_stats_[level].micros > 0 || comp_stats_[level].cpu_micros > 0 ||
1785
420
        files > 0) {
1786
8
      compaction_stats_sum->Add(comp_stats_[level]);
1787
8
      total_file_size += vstorage->NumLevelBytes(level);
1788
8
      uint64_t input_bytes;
1789
8
      if (level == 0) {
1790
3
        input_bytes = curr_ingest;
1791
5
      } else {
1792
5
        input_bytes = comp_stats_[level].bytes_read_non_output_levels +
1793
5
                      comp_stats_[level].bytes_read_blob;
1794
5
      }
1795
8
      double w_amp =
1796
8
          (input_bytes == 0)
1797
8
              ? 0.0
1798
8
              : static_cast<double>(comp_stats_[level].bytes_written +
1799
2
                                    comp_stats_[level].bytes_written_blob) /
1800
2
                    input_bytes;
1801
8
      std::map<LevelStatType, double> level_stats;
1802
8
      PrepareLevelStats(&level_stats, files, files_being_compacted[level],
1803
8
                        static_cast<double>(vstorage->NumLevelBytes(level)),
1804
8
                        compaction_score[level], w_amp, comp_stats_[level]);
1805
8
      (*levels_stats)[level] = level_stats;
1806
8
    }
1807
420
  }
1808
  // Cumulative summary
1809
60
  double w_amp = (0 == curr_ingest)
1810
60
                     ? 0.0
1811
60
                     : (compaction_stats_sum->bytes_written +
1812
2
                        compaction_stats_sum->bytes_written_blob) /
1813
2
                           static_cast<double>(curr_ingest);
1814
  // Stats summary across levels
1815
60
  std::map<LevelStatType, double> sum_stats;
1816
60
  PrepareLevelStats(&sum_stats, total_files, total_files_being_compacted,
1817
60
                    total_file_size, 0, w_amp, *compaction_stats_sum);
1818
60
  (*levels_stats)[-1] = sum_stats;  //  -1 is for the Sum level
1819
60
}
1820
1821
void InternalStats::DumpCFMapStatsByPriority(
1822
60
    std::map<int, std::map<LevelStatType, double>>* priorities_stats) {
1823
300
  for (size_t priority = 0; priority < comp_stats_by_pri_.size(); priority++) {
1824
240
    if (comp_stats_by_pri_[priority].micros > 0) {
1825
2
      std::map<LevelStatType, double> priority_stats;
1826
2
      PrepareLevelStats(&priority_stats, 0 /* num_files */,
1827
2
                        0 /* being_compacted */, 0 /* total_file_size */,
1828
2
                        0 /* compaction_score */, 0 /* w_amp */,
1829
2
                        comp_stats_by_pri_[priority]);
1830
2
      (*priorities_stats)[static_cast<int>(priority)] = priority_stats;
1831
2
    }
1832
240
  }
1833
60
}
1834
1835
void InternalStats::DumpCFMapStatsWriteStall(
1836
60
    std::map<std::string, std::string>* value) {
1837
60
  uint64_t total_delays = 0;
1838
60
  uint64_t total_stops = 0;
1839
60
  constexpr uint32_t max_cf_scope_write_stall_cause =
1840
60
      static_cast<uint32_t>(WriteStallCause::kCFScopeWriteStallCauseEnumMax);
1841
1842
60
  for (uint32_t i =
1843
60
           max_cf_scope_write_stall_cause - kNumCFScopeWriteStallCauses;
1844
240
       i < max_cf_scope_write_stall_cause; ++i) {
1845
180
    for (uint32_t j = 0;
1846
540
         j < static_cast<uint32_t>(WriteStallCondition::kNormal); ++j) {
1847
360
      WriteStallCause cause = static_cast<WriteStallCause>(i);
1848
360
      WriteStallCondition condition = static_cast<WriteStallCondition>(j);
1849
360
      InternalStats::InternalCFStatsType internal_cf_stat =
1850
360
          InternalCFStat(cause, condition);
1851
1852
360
      if (internal_cf_stat == InternalStats::INTERNAL_CF_STATS_ENUM_MAX) {
1853
0
        continue;
1854
0
      }
1855
1856
360
      std::string name =
1857
360
          WriteStallStatsMapKeys::CauseConditionCount(cause, condition);
1858
360
      uint64_t stat =
1859
360
          cf_stats_count_[static_cast<std::size_t>(internal_cf_stat)];
1860
360
      (*value)[name] = std::to_string(stat);
1861
1862
360
      if (condition == WriteStallCondition::kDelayed) {
1863
180
        total_delays += stat;
1864
180
      } else if (condition == WriteStallCondition::kStopped) {
1865
180
        total_stops += stat;
1866
180
      }
1867
360
    }
1868
180
  }
1869
1870
60
  (*value)[WriteStallStatsMapKeys::
1871
60
               CFL0FileCountLimitDelaysWithOngoingCompaction()] =
1872
60
      std::to_string(
1873
60
          cf_stats_count_[L0_FILE_COUNT_LIMIT_DELAYS_WITH_ONGOING_COMPACTION]);
1874
60
  (*value)[WriteStallStatsMapKeys::
1875
60
               CFL0FileCountLimitStopsWithOngoingCompaction()] =
1876
60
      std::to_string(
1877
60
          cf_stats_count_[L0_FILE_COUNT_LIMIT_STOPS_WITH_ONGOING_COMPACTION]);
1878
1879
60
  (*value)[WriteStallStatsMapKeys::TotalStops()] = std::to_string(total_stops);
1880
60
  (*value)[WriteStallStatsMapKeys::TotalDelays()] =
1881
60
      std::to_string(total_delays);
1882
60
}
1883
1884
void InternalStats::DumpCFStatsWriteStall(std::string* value,
1885
60
                                          uint64_t* total_stall_count) {
1886
60
  assert(value);
1887
1888
60
  std::map<std::string, std::string> write_stall_stats_map;
1889
60
  DumpCFMapStatsWriteStall(&write_stall_stats_map);
1890
1891
60
  std::ostringstream str;
1892
60
  str << "Write Stall (count): ";
1893
1894
60
  for (auto write_stall_stats_map_iter = write_stall_stats_map.begin();
1895
660
       write_stall_stats_map_iter != write_stall_stats_map.end();
1896
600
       write_stall_stats_map_iter++) {
1897
600
    const auto& name_and_stat = *write_stall_stats_map_iter;
1898
600
    str << name_and_stat.first << ": " << name_and_stat.second;
1899
600
    if (std::next(write_stall_stats_map_iter) == write_stall_stats_map.end()) {
1900
60
      str << "\n";
1901
540
    } else {
1902
540
      str << ", ";
1903
540
    }
1904
600
  }
1905
1906
60
  if (total_stall_count) {
1907
60
    *total_stall_count =
1908
60
        ParseUint64(
1909
60
            write_stall_stats_map[WriteStallStatsMapKeys::TotalStops()]) +
1910
60
        ParseUint64(
1911
60
            write_stall_stats_map[WriteStallStatsMapKeys::TotalDelays()]);
1912
60
    if (*total_stall_count > 0) {
1913
0
      str << "interval: " << *total_stall_count - cf_stats_snapshot_.stall_count
1914
0
          << " total count\n";
1915
0
    }
1916
60
  }
1917
60
  *value = str.str();
1918
60
}
1919
1920
0
void InternalStats::DumpCFStats(std::string* value) {
1921
0
  DumpCFStatsNoFileHistogram(/*is_periodic=*/false, value);
1922
0
  DumpCFFileHistogram(value);
1923
0
}
1924
1925
void InternalStats::DumpCFStatsNoFileHistogram(bool is_periodic,
1926
60
                                               std::string* value) {
1927
60
  char buf[2000];
1928
  // Per-ColumnFamily stats
1929
60
  PrintLevelStatsHeader(buf, sizeof(buf), cfd_->GetName(), "Level");
1930
60
  value->append(buf);
1931
1932
  // Print stats for each level
1933
60
  const VersionStorageInfo* vstorage = cfd_->current()->storage_info();
1934
60
  std::map<int, std::map<LevelStatType, double>> levels_stats;
1935
60
  CompactionStats compaction_stats_sum;
1936
60
  DumpCFMapStats(vstorage, &levels_stats, &compaction_stats_sum);
1937
480
  for (int l = 0; l < number_levels_; ++l) {
1938
420
    if (levels_stats.find(l) != levels_stats.end()) {
1939
8
      PrintLevelStats(buf, sizeof(buf), "L" + std::to_string(l),
1940
8
                      levels_stats[l]);
1941
8
      value->append(buf);
1942
8
    }
1943
420
  }
1944
1945
  // Print sum of level stats
1946
60
  PrintLevelStats(buf, sizeof(buf), "Sum", levels_stats[-1]);
1947
60
  value->append(buf);
1948
1949
60
  uint64_t flush_ingest = cf_stats_value_[BYTES_FLUSHED];
1950
60
  uint64_t add_file_ingest = cf_stats_value_[BYTES_INGESTED_ADD_FILE];
1951
60
  uint64_t ingest_files_addfile = cf_stats_value_[INGESTED_NUM_FILES_TOTAL];
1952
60
  uint64_t ingest_l0_files_addfile =
1953
60
      cf_stats_value_[INGESTED_LEVEL0_NUM_FILES_TOTAL];
1954
60
  uint64_t ingest_keys_addfile = cf_stats_value_[INGESTED_NUM_KEYS_TOTAL];
1955
  // Interval summary
1956
60
  uint64_t interval_flush_ingest =
1957
60
      flush_ingest - cf_stats_snapshot_.ingest_bytes_flush;
1958
60
  uint64_t interval_add_file_inget =
1959
60
      add_file_ingest - cf_stats_snapshot_.ingest_bytes_addfile;
1960
60
  uint64_t interval_ingest =
1961
60
      interval_flush_ingest + interval_add_file_inget + 1;
1962
60
  CompactionStats interval_stats(compaction_stats_sum);
1963
60
  interval_stats.Subtract(cf_stats_snapshot_.comp_stats);
1964
60
  double w_amp =
1965
60
      (interval_stats.bytes_written + interval_stats.bytes_written_blob) /
1966
60
      static_cast<double>(interval_ingest);
1967
60
  PrintLevelStats(buf, sizeof(buf), "Int", 0, 0, 0, 0, w_amp, interval_stats);
1968
60
  value->append(buf);
1969
1970
60
  PrintLevelStatsHeader(buf, sizeof(buf), cfd_->GetName(), "Priority");
1971
60
  value->append(buf);
1972
60
  std::map<int, std::map<LevelStatType, double>> priorities_stats;
1973
60
  DumpCFMapStatsByPriority(&priorities_stats);
1974
300
  for (size_t priority = 0; priority < comp_stats_by_pri_.size(); ++priority) {
1975
240
    if (priorities_stats.find(static_cast<int>(priority)) !=
1976
240
        priorities_stats.end()) {
1977
2
      PrintLevelStats(
1978
2
          buf, sizeof(buf),
1979
2
          Env::PriorityToString(static_cast<Env::Priority>(priority)),
1980
2
          priorities_stats[static_cast<int>(priority)]);
1981
2
      value->append(buf);
1982
2
    }
1983
240
  }
1984
1985
60
  const auto blob_st = vstorage->GetBlobStats();
1986
1987
60
  snprintf(buf, sizeof(buf),
1988
60
           "\nBlob file count: %" ROCKSDB_PRIszt
1989
60
           ", total size: %.1f GB, garbage size: %.1f GB, space amp: %.1f\n\n",
1990
60
           vstorage->GetBlobFiles().size(), blob_st.total_file_size / kGB,
1991
60
           blob_st.total_garbage_size / kGB, blob_st.space_amp);
1992
60
  value->append(buf);
1993
1994
60
  uint64_t now_micros = clock_->NowMicros();
1995
60
  double seconds_up = (now_micros - started_at_) / kMicrosInSec;
1996
60
  double interval_seconds_up = seconds_up - cf_stats_snapshot_.seconds_up;
1997
60
  snprintf(buf, sizeof(buf), "Uptime(secs): %.1f total, %.1f interval\n",
1998
60
           seconds_up, interval_seconds_up);
1999
60
  value->append(buf);
2000
60
  snprintf(buf, sizeof(buf), "Flush(GB): cumulative %.3f, interval %.3f\n",
2001
60
           flush_ingest / kGB, interval_flush_ingest / kGB);
2002
60
  value->append(buf);
2003
60
  snprintf(buf, sizeof(buf), "AddFile(GB): cumulative %.3f, interval %.3f\n",
2004
60
           add_file_ingest / kGB, interval_add_file_inget / kGB);
2005
60
  value->append(buf);
2006
2007
60
  uint64_t interval_ingest_files_addfile =
2008
60
      ingest_files_addfile - cf_stats_snapshot_.ingest_files_addfile;
2009
60
  snprintf(buf, sizeof(buf),
2010
60
           "AddFile(Total Files): cumulative %" PRIu64 ", interval %" PRIu64
2011
60
           "\n",
2012
60
           ingest_files_addfile, interval_ingest_files_addfile);
2013
60
  value->append(buf);
2014
2015
60
  uint64_t interval_ingest_l0_files_addfile =
2016
60
      ingest_l0_files_addfile - cf_stats_snapshot_.ingest_l0_files_addfile;
2017
60
  snprintf(buf, sizeof(buf),
2018
60
           "AddFile(L0 Files): cumulative %" PRIu64 ", interval %" PRIu64 "\n",
2019
60
           ingest_l0_files_addfile, interval_ingest_l0_files_addfile);
2020
60
  value->append(buf);
2021
2022
60
  uint64_t interval_ingest_keys_addfile =
2023
60
      ingest_keys_addfile - cf_stats_snapshot_.ingest_keys_addfile;
2024
60
  snprintf(buf, sizeof(buf),
2025
60
           "AddFile(Keys): cumulative %" PRIu64 ", interval %" PRIu64 "\n",
2026
60
           ingest_keys_addfile, interval_ingest_keys_addfile);
2027
60
  value->append(buf);
2028
2029
  // Compact
2030
60
  uint64_t compact_bytes_read = 0;
2031
60
  uint64_t compact_bytes_write = 0;
2032
60
  uint64_t compact_micros = 0;
2033
480
  for (int level = 0; level < number_levels_; level++) {
2034
420
    compact_bytes_read += comp_stats_[level].bytes_read_output_level +
2035
420
                          comp_stats_[level].bytes_read_non_output_levels +
2036
420
                          comp_stats_[level].bytes_read_blob;
2037
420
    compact_bytes_write += comp_stats_[level].bytes_written +
2038
420
                           comp_stats_[level].bytes_written_blob;
2039
420
    compact_micros += comp_stats_[level].micros;
2040
420
  }
2041
2042
60
  snprintf(buf, sizeof(buf),
2043
60
           "Cumulative compaction: %.2f GB write, %.2f MB/s write, "
2044
60
           "%.2f GB read, %.2f MB/s read, %.1f seconds\n",
2045
60
           compact_bytes_write / kGB,
2046
60
           compact_bytes_write / kMB / std::max(seconds_up, 0.001),
2047
60
           compact_bytes_read / kGB,
2048
60
           compact_bytes_read / kMB / std::max(seconds_up, 0.001),
2049
60
           compact_micros / kMicrosInSec);
2050
60
  value->append(buf);
2051
2052
  // Compaction interval
2053
60
  uint64_t interval_compact_bytes_write =
2054
60
      compact_bytes_write - cf_stats_snapshot_.compact_bytes_write;
2055
60
  uint64_t interval_compact_bytes_read =
2056
60
      compact_bytes_read - cf_stats_snapshot_.compact_bytes_read;
2057
60
  uint64_t interval_compact_micros =
2058
60
      compact_micros - cf_stats_snapshot_.compact_micros;
2059
2060
60
  snprintf(
2061
60
      buf, sizeof(buf),
2062
60
      "Interval compaction: %.2f GB write, %.2f MB/s write, "
2063
60
      "%.2f GB read, %.2f MB/s read, %.1f seconds\n",
2064
60
      interval_compact_bytes_write / kGB,
2065
60
      interval_compact_bytes_write / kMB / std::max(interval_seconds_up, 0.001),
2066
60
      interval_compact_bytes_read / kGB,
2067
60
      interval_compact_bytes_read / kMB / std::max(interval_seconds_up, 0.001),
2068
60
      interval_compact_micros / kMicrosInSec);
2069
60
  value->append(buf);
2070
2071
60
  snprintf(buf, sizeof(buf),
2072
60
           "Estimated pending compaction bytes: %" PRIu64 "\n",
2073
60
           vstorage->estimated_compaction_needed_bytes());
2074
60
  value->append(buf);
2075
2076
60
  if (is_periodic) {
2077
60
    cf_stats_snapshot_.compact_bytes_write = compact_bytes_write;
2078
60
    cf_stats_snapshot_.compact_bytes_read = compact_bytes_read;
2079
60
    cf_stats_snapshot_.compact_micros = compact_micros;
2080
60
  }
2081
2082
60
  std::string write_stall_stats;
2083
60
  uint64_t total_stall_count;
2084
60
  DumpCFStatsWriteStall(&write_stall_stats, &total_stall_count);
2085
60
  value->append(write_stall_stats);
2086
2087
60
  if (is_periodic) {
2088
60
    cf_stats_snapshot_.seconds_up = seconds_up;
2089
60
    cf_stats_snapshot_.ingest_bytes_flush = flush_ingest;
2090
60
    cf_stats_snapshot_.ingest_bytes_addfile = add_file_ingest;
2091
60
    cf_stats_snapshot_.ingest_files_addfile = ingest_files_addfile;
2092
60
    cf_stats_snapshot_.ingest_l0_files_addfile = ingest_l0_files_addfile;
2093
60
    cf_stats_snapshot_.ingest_keys_addfile = ingest_keys_addfile;
2094
60
    cf_stats_snapshot_.comp_stats = compaction_stats_sum;
2095
60
    cf_stats_snapshot_.stall_count = total_stall_count;
2096
60
  }
2097
2098
  // Do not gather cache entry stats during CFStats because DB
2099
  // mutex is held. Only dump last cached collection (rely on DB
2100
  // periodic stats dump to update)
2101
60
  if (cache_entry_stats_collector_) {
2102
60
    CacheEntryRoleStats stats;
2103
    // thread safe
2104
60
    cache_entry_stats_collector_->GetStats(&stats);
2105
2106
60
    constexpr uint64_t kDayInMicros = uint64_t{86400} * 1000000U;
2107
2108
    // Skip if stats are extremely old (> 1 day, incl not yet populated)
2109
60
    if (now_micros - stats.last_end_time_micros_ < kDayInMicros) {
2110
60
      value->append(stats.ToString(clock_));
2111
60
    }
2112
60
  }
2113
60
}
2114
2115
60
void InternalStats::DumpCFFileHistogram(std::string* value) {
2116
60
  assert(value);
2117
60
  assert(cfd_);
2118
2119
60
  std::ostringstream oss;
2120
60
  oss << "\n** File Read Latency Histogram By Level [" << cfd_->GetName()
2121
60
      << "] **\n";
2122
2123
480
  for (int level = 0; level < number_levels_; level++) {
2124
420
    if (!file_read_latency_[level].Empty()) {
2125
0
      oss << "** Level " << level << " read latency histogram (micros):\n"
2126
0
          << file_read_latency_[level].ToString() << '\n';
2127
0
    }
2128
420
  }
2129
2130
60
  if (!blob_file_read_latency_.Empty()) {
2131
0
    oss << "** Blob file read latency histogram (micros):\n"
2132
0
        << blob_file_read_latency_.ToString() << '\n';
2133
0
  }
2134
2135
60
  value->append(oss.str());
2136
60
}
2137
2138
namespace {
2139
2140
class SumPropertyAggregator : public IntPropertyAggregator {
2141
 public:
2142
0
  SumPropertyAggregator() : aggregated_value_(0) {}
2143
  virtual ~SumPropertyAggregator() override = default;
2144
2145
0
  void Add(ColumnFamilyData* cfd, uint64_t value) override {
2146
0
    (void)cfd;
2147
0
    aggregated_value_ += value;
2148
0
  }
2149
2150
0
  uint64_t Aggregate() const override { return aggregated_value_; }
2151
2152
 private:
2153
  uint64_t aggregated_value_;
2154
};
2155
2156
// A block cache may be shared by multiple column families.
2157
// BlockCachePropertyAggregator ensures that the same cache is only added once.
2158
class BlockCachePropertyAggregator : public IntPropertyAggregator {
2159
 public:
2160
0
  BlockCachePropertyAggregator() = default;
2161
0
  virtual ~BlockCachePropertyAggregator() override = default;
2162
2163
0
  void Add(ColumnFamilyData* cfd, uint64_t value) override {
2164
0
    auto* table_factory = cfd->ioptions()->table_factory.get();
2165
0
    assert(table_factory != nullptr);
2166
0
    Cache* cache =
2167
0
        table_factory->GetOptions<Cache>(TableFactory::kBlockCacheOpts());
2168
0
    if (cache != nullptr) {
2169
0
      block_cache_properties_.emplace(cache, value);
2170
0
    }
2171
0
  }
2172
2173
0
  uint64_t Aggregate() const override {
2174
0
    uint64_t sum = 0;
2175
0
    for (const auto& p : block_cache_properties_) {
2176
0
      sum += p.second;
2177
0
    }
2178
0
    return sum;
2179
0
  }
2180
2181
 private:
2182
  std::unordered_map<Cache*, uint64_t> block_cache_properties_;
2183
};
2184
2185
}  // anonymous namespace
2186
2187
std::unique_ptr<IntPropertyAggregator> CreateIntPropertyAggregator(
2188
0
    const Slice& property) {
2189
0
  if (property == DB::Properties::kBlockCacheCapacity ||
2190
0
      property == DB::Properties::kBlockCacheUsage ||
2191
0
      property == DB::Properties::kBlockCachePinnedUsage) {
2192
0
    return std::make_unique<BlockCachePropertyAggregator>();
2193
0
  } else {
2194
0
    return std::make_unique<SumPropertyAggregator>();
2195
0
  }
2196
0
}
2197
2198
}  // namespace ROCKSDB_NAMESPACE