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