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