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.
9 #include "monitoring/persistent_stats_history.h"
15 #include "db/db_impl/db_impl.h"
16 #include "util/string_util.h"
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;
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");
39 if (type
== StatsVersionKeyType::kFormatVersion
) {
40 key
= kFormatVersionKeyString
;
41 } else if (type
== StatsVersionKeyType::kCompatibleVersion
) {
42 key
= kCompatibleVersionKeyString
;
45 options
.verify_checksums
= true;
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
+
53 // read version_number but do nothing in current version
54 *version_number
= ParseUint64(result
);
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());
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
;
77 PersistentStatsHistoryIterator::~PersistentStatsHistoryIterator() {}
79 bool PersistentStatsHistoryIterator::Valid() const { return valid_
; }
81 Status
PersistentStatsHistoryIterator::status() const { return status_
; }
83 void PersistentStatsHistoryIterator::Next() {
84 // increment start_time by 1 to avoid infinite loop
85 AdvanceIteratorByTime(GetStatsTime() + 1, end_time_
);
88 uint64_t PersistentStatsHistoryIterator::GetStatsTime() const { return time_
; }
90 const std::map
<std::string
, uint64_t>&
91 PersistentStatsHistoryIterator::GetStatsMap() const {
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();
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();
111 result
.first
= parsed_time
;
112 std::string key_resize
= key_str
.substr(pos
+ 1);
113 result
.second
= key_resize
;
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
,
123 // try to find next entry in stats_history_ map
124 if (db_impl_
!= nullptr) {
127 db_impl_
->NewIterator(ro
, db_impl_
->PersistentStatsColumnFamily());
129 char timestamp
[kNowSecondsStringLength
+ 1];
130 snprintf(timestamp
, sizeof(timestamp
), "%010d",
131 static_cast<int>(std::max(time_
, start_time
)));
132 timestamp
[kNowSecondsStringLength
] = '\0';
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()) {
142 time_
= parseKey(iter
->key(), start_time
).first
;
144 // check parsed time and invalid if it exceeds end_time
145 if (time_
> end_time
) {
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_
) {
158 if (kv
.second
.compare(kFormatVersionKeyString
) == 0) {
161 new_stats_map
[kv
.second
] = ParseUint64(iter
->value().ToString());
163 stats_map_
.swap(new_stats_map
);
170 } // namespace ROCKSDB_NAMESPACE