]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/monitoring/persistent_stats_history.cc
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / rocksdb / monitoring / persistent_stats_history.cc
1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
6 // Use of this source code is governed by a BSD-style license that can be
7 // found in the LICENSE file. See the AUTHORS file for names of contributors.
8
9 #include "monitoring/persistent_stats_history.h"
10
11 #include <cstring>
12 #include <string>
13 #include <utility>
14
15 #include "db/db_impl/db_impl.h"
16 #include "util/string_util.h"
17
18 namespace ROCKSDB_NAMESPACE {
19 // 10 digit seconds timestamp => [Sep 9, 2001 ~ Nov 20, 2286]
20 const int kNowSecondsStringLength = 10;
21 const std::string kFormatVersionKeyString =
22 "__persistent_stats_format_version__";
23 const std::string kCompatibleVersionKeyString =
24 "__persistent_stats_compatible_version__";
25 // Every release maintains two versions numbers for persistents stats: Current
26 // format version and compatible format version. Current format version
27 // designates what type of encoding will be used when writing to stats CF;
28 // compatible format version designates the minimum format version that
29 // can decode the stats CF encoded using the current format version.
30 const uint64_t kStatsCFCurrentFormatVersion = 1;
31 const uint64_t kStatsCFCompatibleFormatVersion = 1;
32
33 Status DecodePersistentStatsVersionNumber(DBImpl* db, StatsVersionKeyType type,
34 uint64_t* version_number) {
35 if (type >= StatsVersionKeyType::kKeyTypeMax) {
36 return Status::InvalidArgument("Invalid stats version key type provided");
37 }
38 std::string key;
39 if (type == StatsVersionKeyType::kFormatVersion) {
40 key = kFormatVersionKeyString;
41 } else if (type == StatsVersionKeyType::kCompatibleVersion) {
42 key = kCompatibleVersionKeyString;
43 }
44 ReadOptions options;
45 options.verify_checksums = true;
46 std::string result;
47 Status s = db->Get(options, db->PersistentStatsColumnFamily(), key, &result);
48 if (!s.ok() || result.empty()) {
49 return Status::NotFound("Persistent stats version key " + key +
50 " not found.");
51 }
52
53 // read version_number but do nothing in current version
54 *version_number = ParseUint64(result);
55 return Status::OK();
56 }
57
58 int EncodePersistentStatsKey(uint64_t now_seconds, const std::string& key,
59 int size, char* buf) {
60 char timestamp[kNowSecondsStringLength + 1];
61 // make time stamp string equal in length to allow sorting by time
62 snprintf(timestamp, sizeof(timestamp), "%010d",
63 static_cast<int>(now_seconds));
64 timestamp[kNowSecondsStringLength] = '\0';
65 return snprintf(buf, size, "%s#%s", timestamp, key.c_str());
66 }
67
68 void OptimizeForPersistentStats(ColumnFamilyOptions* cfo) {
69 cfo->write_buffer_size = 2 << 20;
70 cfo->target_file_size_base = 2 * 1048576;
71 cfo->max_bytes_for_level_base = 10 * 1048576;
72 cfo->soft_pending_compaction_bytes_limit = 256 * 1048576;
73 cfo->hard_pending_compaction_bytes_limit = 1073741824ul;
74 cfo->compression = kNoCompression;
75 }
76
77 PersistentStatsHistoryIterator::~PersistentStatsHistoryIterator() {}
78
79 bool PersistentStatsHistoryIterator::Valid() const { return valid_; }
80
81 Status PersistentStatsHistoryIterator::status() const { return status_; }
82
83 void PersistentStatsHistoryIterator::Next() {
84 // increment start_time by 1 to avoid infinite loop
85 AdvanceIteratorByTime(GetStatsTime() + 1, end_time_);
86 }
87
88 uint64_t PersistentStatsHistoryIterator::GetStatsTime() const { return time_; }
89
90 const std::map<std::string, uint64_t>&
91 PersistentStatsHistoryIterator::GetStatsMap() const {
92 return stats_map_;
93 }
94
95 std::pair<uint64_t, std::string> parseKey(const Slice& key,
96 uint64_t start_time) {
97 std::pair<uint64_t, std::string> result;
98 std::string key_str = key.ToString();
99 std::string::size_type pos = key_str.find("#");
100 // TODO(Zhongyi): add counters to track parse failures?
101 if (pos == std::string::npos) {
102 result.first = std::numeric_limits<uint64_t>::max();
103 result.second.clear();
104 } else {
105 uint64_t parsed_time = ParseUint64(key_str.substr(0, pos));
106 // skip entries with timestamp smaller than start_time
107 if (parsed_time < start_time) {
108 result.first = std::numeric_limits<uint64_t>::max();
109 result.second = "";
110 } else {
111 result.first = parsed_time;
112 std::string key_resize = key_str.substr(pos + 1);
113 result.second = key_resize;
114 }
115 }
116 return result;
117 }
118
119 // advance the iterator to the next time between [start_time, end_time)
120 // if success, update time_ and stats_map_ with new_time and stats_map
121 void PersistentStatsHistoryIterator::AdvanceIteratorByTime(uint64_t start_time,
122 uint64_t end_time) {
123 // try to find next entry in stats_history_ map
124 if (db_impl_ != nullptr) {
125 ReadOptions ro;
126 Iterator* iter =
127 db_impl_->NewIterator(ro, db_impl_->PersistentStatsColumnFamily());
128
129 char timestamp[kNowSecondsStringLength + 1];
130 snprintf(timestamp, sizeof(timestamp), "%010d",
131 static_cast<int>(std::max(time_, start_time)));
132 timestamp[kNowSecondsStringLength] = '\0';
133
134 iter->Seek(timestamp);
135 // no more entries with timestamp >= start_time is found or version key
136 // is found to be incompatible
137 if (!iter->Valid()) {
138 valid_ = false;
139 delete iter;
140 return;
141 }
142 time_ = parseKey(iter->key(), start_time).first;
143 valid_ = true;
144 // check parsed time and invalid if it exceeds end_time
145 if (time_ > end_time) {
146 valid_ = false;
147 delete iter;
148 return;
149 }
150 // find all entries with timestamp equal to time_
151 std::map<std::string, uint64_t> new_stats_map;
152 std::pair<uint64_t, std::string> kv;
153 for (; iter->Valid(); iter->Next()) {
154 kv = parseKey(iter->key(), start_time);
155 if (kv.first != time_) {
156 break;
157 }
158 if (kv.second.compare(kFormatVersionKeyString) == 0) {
159 continue;
160 }
161 new_stats_map[kv.second] = ParseUint64(iter->value().ToString());
162 }
163 stats_map_.swap(new_stats_map);
164 delete iter;
165 } else {
166 valid_ = false;
167 }
168 }
169
170 } // namespace ROCKSDB_NAMESPACE