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"
14 #include "db/db_impl/db_impl.h"
15 #include "util/string_util.h"
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;
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");
38 if (type
== StatsVersionKeyType::kFormatVersion
) {
39 key
= kFormatVersionKeyString
;
40 } else if (type
== StatsVersionKeyType::kCompatibleVersion
) {
41 key
= kCompatibleVersionKeyString
;
44 options
.verify_checksums
= true;
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
+
52 // read version_number but do nothing in current version
53 *version_number
= ParseUint64(result
);
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());
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
;
76 PersistentStatsHistoryIterator::~PersistentStatsHistoryIterator() {}
78 bool PersistentStatsHistoryIterator::Valid() const { return valid_
; }
80 Status
PersistentStatsHistoryIterator::status() const { return status_
; }
82 void PersistentStatsHistoryIterator::Next() {
83 // increment start_time by 1 to avoid infinite loop
84 AdvanceIteratorByTime(GetStatsTime() + 1, end_time_
);
87 uint64_t PersistentStatsHistoryIterator::GetStatsTime() const { return time_
; }
89 const std::map
<std::string
, uint64_t>&
90 PersistentStatsHistoryIterator::GetStatsMap() const {
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();
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
;
110 result
.first
= parsed_time
;
111 std::string key_resize
= key_str
.substr(pos
+ 1);
112 result
.second
= key_resize
;
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
,
122 // try to find next entry in stats_history_ map
123 if (db_impl_
!= nullptr) {
126 db_impl_
->NewIterator(ro
, db_impl_
->PersistentStatsColumnFamily());
128 char timestamp
[kNowSecondsStringLength
+ 1];
129 snprintf(timestamp
, sizeof(timestamp
), "%010d",
130 static_cast<int>(std::max(time_
, start_time
)));
131 timestamp
[kNowSecondsStringLength
] = '\0';
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()) {
141 time_
= parseKey(iter
->key(), start_time
).first
;
143 // check parsed time and invalid if it exceeds end_time
144 if (time_
> end_time
) {
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_
) {
157 if (kv
.second
.compare(kFormatVersionKeyString
) == 0) {
160 new_stats_map
[kv
.second
] = ParseUint64(iter
->value().ToString());
162 stats_map_
.swap(new_stats_map
);
169 } // namespace ROCKSDB_NAMESPACE