/Users/deen/code/yugabyte-db/src/yb/rocksdb/metadata.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under the BSD-style license found in the |
3 | | // LICENSE file in the root directory of this source tree. An additional grant |
4 | | // of patent rights can be found in the PATENTS file in the same directory. |
5 | | // |
6 | | // The following only applies to changes made to this file as part of YugaByte development. |
7 | | // |
8 | | // Portions Copyright (c) YugaByte, Inc. |
9 | | // |
10 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
11 | | // in compliance with the License. You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
16 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
17 | | // or implied. See the License for the specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | |
21 | | #ifndef YB_ROCKSDB_METADATA_H |
22 | | #define YB_ROCKSDB_METADATA_H |
23 | | |
24 | | #include <stdint.h> |
25 | | |
26 | | #include <limits> |
27 | | #include <string> |
28 | | #include <vector> |
29 | | |
30 | | #include <boost/container/small_vector.hpp> |
31 | | |
32 | | #include "yb/common/hybrid_time.h" |
33 | | |
34 | | #include "yb/gutil/casts.h" |
35 | | |
36 | | #include "yb/util/clone_ptr.h" |
37 | | #include "yb/util/slice.h" |
38 | | #include "yb/util/enums.h" |
39 | | |
40 | | #include "yb/rocksdb/types.h" |
41 | | |
42 | | namespace google { namespace protobuf { |
43 | | class Any; |
44 | | } |
45 | | } |
46 | | |
47 | | namespace yb { |
48 | | class OpIdPB; |
49 | | } |
50 | | |
51 | | namespace rocksdb { |
52 | | struct ColumnFamilyMetaData; |
53 | | struct LevelMetaData; |
54 | | struct SstFileMetaData; |
55 | | |
56 | | // The metadata that describes a column family. |
57 | | struct ColumnFamilyMetaData { |
58 | 470 | ColumnFamilyMetaData() : size(0), name("") {} |
59 | | ColumnFamilyMetaData(const std::string& _name, uint64_t _size, |
60 | | const std::vector<LevelMetaData>&& _levels) |
61 | | : size(_size), |
62 | | name(_name), |
63 | 0 | levels(_levels) {} |
64 | | |
65 | | // The size of this column family in bytes, which is equal to the sum of |
66 | | // the file size of its "levels". |
67 | | uint64_t size = 0; |
68 | | // The number of files in this column family. |
69 | | size_t file_count = 0; |
70 | | // The name of the column family. |
71 | | std::string name; |
72 | | // The metadata of all levels in this column family. |
73 | | std::vector<LevelMetaData> levels; |
74 | | }; |
75 | | |
76 | | // The metadata that describes a level. |
77 | | struct LevelMetaData { |
78 | | LevelMetaData(int _level, uint64_t _size, |
79 | | const std::vector<SstFileMetaData>&& _files) |
80 | | : level(_level), |
81 | | size(_size), |
82 | 2.20k | files(_files) {} |
83 | | |
84 | | // The level which this meta data describes. |
85 | | const int level = 0; |
86 | | // The size of this level in bytes, which is equal to the sum of |
87 | | // the file size of its "files". |
88 | | const uint64_t size = 0; |
89 | | // The metadata of all sst files in this level. |
90 | | const std::vector<SstFileMetaData> files; |
91 | | }; |
92 | | |
93 | | class UserFrontier; |
94 | | |
95 | | // Frontier should be copyable, but should still preserve its polymorphic nature. We cannot use |
96 | | // shared_ptr here, because we are planning to modify the copied value. If we used shared_ptr and |
97 | | // modified the copied value, the original value would also change. |
98 | | typedef yb::clone_ptr<UserFrontier> UserFrontierPtr; |
99 | | |
100 | | void UpdateUserFrontier(UserFrontierPtr* value, const UserFrontierPtr& update, |
101 | | UpdateUserValueType type); |
102 | | void UpdateUserFrontier(UserFrontierPtr* value, UserFrontierPtr&& update, |
103 | | UpdateUserValueType type); |
104 | | |
105 | | // When writing a batch of RocksDB records, the user could specify "frontier" values of that batch, |
106 | | // such as smallest/largest Raft OpId or smallest/largest HybridTime of records in that batch. We |
107 | | // maintain these values for each SSTable file and whole DB. This class defines an abstract |
108 | | // interface for a single user frontier, i.e. only smallest values or only largest values, but all |
109 | | // types of these values together as a tuple (e.g. OpId / hybrid time / etc.) See |
110 | | // consensus_frontier.h for a concrete example. |
111 | | class UserFrontier { |
112 | | public: |
113 | | virtual std::unique_ptr<UserFrontier> Clone() const = 0; |
114 | | virtual std::string ToString() const = 0; |
115 | | virtual void ToPB(google::protobuf::Any* pb) const = 0; |
116 | | virtual bool Equals(const UserFrontier& rhs) const = 0; |
117 | | |
118 | | // Updates the user frontier with the new values from rhs. |
119 | | virtual void Update(const UserFrontier& rhs, UpdateUserValueType type) = 0; |
120 | | |
121 | | // Checks if the given update is valid, i.e. that it does not move the fields of the frontier |
122 | | // (such as OpId / hybrid time) in the direction opposite to that indicated by |
123 | | // UpdateUserValueType. A "largest" update should only increase fields, and a "smallest" should |
124 | | // only decrease them. Fields that are not set in rhs are not checked. |
125 | | virtual bool IsUpdateValid(const UserFrontier& rhs, UpdateUserValueType type) const = 0; |
126 | | |
127 | | // Should return value that will be passed to iterator replacer. |
128 | | virtual Slice Filter() const = 0; |
129 | | |
130 | | // Returns true if this frontier dominates another frontier, i.e. if we update this frontier |
131 | | // with the values from the other one in the direction specified by update_type, nothing will |
132 | | // change. This is used to check invariants. |
133 | | bool Dominates(const UserFrontier& rhs, UpdateUserValueType update_type) const; |
134 | | |
135 | | virtual void FromOpIdPBDeprecated(const yb::OpIdPB& op_id) = 0; |
136 | | virtual void FromPB(const google::protobuf::Any& pb) = 0; |
137 | | |
138 | 35.4M | virtual ~UserFrontier() {} |
139 | | |
140 | | static void Update(const UserFrontier* rhs, UpdateUserValueType type, UserFrontierPtr* out); |
141 | | }; |
142 | | |
143 | 8 | inline bool operator==(const UserFrontier& lhs, const UserFrontier& rhs) { |
144 | 8 | return lhs.Equals(rhs); |
145 | 8 | } |
146 | | |
147 | 0 | inline bool operator!=(const UserFrontier& lhs, const UserFrontier& rhs) { |
148 | 0 | return !lhs.Equals(rhs); |
149 | 0 | } |
150 | | |
151 | 6 | inline std::ostream& operator<<(std::ostream& out, const UserFrontier& frontier) { |
152 | 6 | return out << frontier.ToString(); |
153 | 6 | } |
154 | | |
155 | | // Abstract interface to a pair of user defined frontiers - smallest and largest. |
156 | | class UserFrontiers { |
157 | | public: |
158 | | virtual std::unique_ptr<UserFrontiers> Clone() const = 0; |
159 | | std::string ToString() const; |
160 | | virtual const UserFrontier& Smallest() const = 0; |
161 | | virtual const UserFrontier& Largest() const = 0; |
162 | | |
163 | | virtual void MergeFrontiers(const UserFrontiers& rhs) = 0; |
164 | | |
165 | 12.6M | virtual ~UserFrontiers() {} |
166 | | }; |
167 | | |
168 | | template<class Frontier> |
169 | | class UserFrontiersBase : public rocksdb::UserFrontiers { |
170 | | public: |
171 | 11.7k | const rocksdb::UserFrontier& Smallest() const override { return smallest_; } |
172 | 2.49M | const rocksdb::UserFrontier& Largest() const override { return largest_; } |
173 | | |
174 | 23.6M | Frontier& Smallest() { return smallest_; } |
175 | 32.4M | Frontier& Largest() { return largest_; } |
176 | | |
177 | 90.5k | std::unique_ptr<rocksdb::UserFrontiers> Clone() const override { |
178 | 90.5k | return std::make_unique<UserFrontiersBase>(*this); |
179 | 90.5k | } Unexecuted instantiation: rocksdb::UserFrontiersBase<rocksdb::test::TestUserFrontier>::Clone() const rocksdb::UserFrontiersBase<yb::docdb::ConsensusFrontier>::Clone() const Line | Count | Source | 177 | 90.5k | std::unique_ptr<rocksdb::UserFrontiers> Clone() const override { | 178 | 90.5k | return std::make_unique<UserFrontiersBase>(*this); | 179 | 90.5k | } |
|
180 | | |
181 | 11.5M | void MergeFrontiers(const UserFrontiers& pre_rhs) override { |
182 | 11.5M | const auto& rhs = down_cast<const UserFrontiersBase&>(pre_rhs); |
183 | 11.5M | smallest_.Update(rhs.smallest_, rocksdb::UpdateUserValueType::kSmallest); |
184 | 11.5M | largest_.Update(rhs.largest_, rocksdb::UpdateUserValueType::kLargest); |
185 | 11.5M | } Unexecuted instantiation: rocksdb::UserFrontiersBase<rocksdb::test::TestUserFrontier>::MergeFrontiers(rocksdb::UserFrontiers const&) rocksdb::UserFrontiersBase<yb::docdb::ConsensusFrontier>::MergeFrontiers(rocksdb::UserFrontiers const&) Line | Count | Source | 181 | 11.5M | void MergeFrontiers(const UserFrontiers& pre_rhs) override { | 182 | 11.5M | const auto& rhs = down_cast<const UserFrontiersBase&>(pre_rhs); | 183 | 11.5M | smallest_.Update(rhs.smallest_, rocksdb::UpdateUserValueType::kSmallest); | 184 | 11.5M | largest_.Update(rhs.largest_, rocksdb::UpdateUserValueType::kLargest); | 185 | 11.5M | } |
|
186 | | |
187 | | private: |
188 | | Frontier smallest_; |
189 | | Frontier largest_; |
190 | | }; |
191 | | |
192 | | inline bool operator==(const UserFrontiers& lhs, const UserFrontiers& rhs) { |
193 | | return lhs.Smallest() == rhs.Smallest() && lhs.Largest() == rhs.Largest(); |
194 | | } |
195 | | |
196 | | typedef uint32_t UserBoundaryTag; |
197 | | |
198 | | class UserBoundaryValue { |
199 | | public: |
200 | | virtual UserBoundaryTag Tag() = 0; |
201 | | virtual yb::Slice Encode() = 0; |
202 | | virtual int CompareTo(const UserBoundaryValue& rhs) = 0; |
203 | | protected: |
204 | 151M | ~UserBoundaryValue() {} |
205 | | }; |
206 | | |
207 | | typedef std::shared_ptr<UserBoundaryValue> UserBoundaryValuePtr; |
208 | | typedef boost::container::small_vector_base<UserBoundaryValuePtr> UserBoundaryValues; |
209 | | |
210 | | struct FileBoundaryValuesBase { |
211 | | SequenceNumber seqno; // Boundary sequence number in file. |
212 | | UserFrontierPtr user_frontier; |
213 | | // We expect that there will be just a few user values, so use small_vector for it. |
214 | | boost::container::small_vector<UserBoundaryValuePtr, 10> user_values; |
215 | | |
216 | | std::string ToString() const; |
217 | | }; |
218 | | |
219 | | template<class KeyType> |
220 | | struct FileBoundaryValues : FileBoundaryValuesBase { |
221 | | KeyType key; // Boundary key in the file. |
222 | | }; |
223 | | |
224 | | inline UserBoundaryValuePtr UserValueWithTag(const UserBoundaryValues& values, |
225 | 151M | UserBoundaryTag tag) { |
226 | 251M | for (const auto& value : values) { |
227 | 251M | if (value->Tag() == tag) |
228 | 151M | return value; |
229 | 251M | } |
230 | 18.4E | return UserBoundaryValuePtr(); |
231 | 151M | } |
232 | | |
233 | | inline void UpdateUserValue(UserBoundaryValues* values, |
234 | | const UserBoundaryValuePtr& new_value, |
235 | 301M | UpdateUserValueType type) { |
236 | 301M | int compare_sign = static_cast<int>(type); |
237 | 301M | auto tag = new_value->Tag(); |
238 | 502M | for (auto& value : *values) { |
239 | 502M | if (value->Tag() == tag) { |
240 | 301M | if (value->CompareTo(*new_value) * compare_sign > 0) { |
241 | 8.14M | value = new_value; |
242 | 8.14M | } |
243 | 301M | return; |
244 | 301M | } |
245 | 502M | } |
246 | 18.4E | values->push_back(new_value); |
247 | 18.4E | } |
248 | | |
249 | | // The metadata that describes a SST fileset. |
250 | | struct SstFileMetaData { |
251 | | typedef FileBoundaryValues<std::string> BoundaryValues; |
252 | | |
253 | 384k | SstFileMetaData() {} |
254 | | SstFileMetaData(const std::string& _file_name, |
255 | | const std::string& _path, |
256 | | uint64_t _total_size, |
257 | | uint64_t _base_size, |
258 | | uint64_t _uncompressed_size, |
259 | | const BoundaryValues& _smallest, |
260 | | const BoundaryValues& _largest, |
261 | | bool _being_compacted) |
262 | | : total_size(_total_size), |
263 | | base_size(_base_size), |
264 | | uncompressed_size(_uncompressed_size), |
265 | | name(_file_name), |
266 | | db_path(_path), |
267 | | smallest(_smallest), |
268 | | largest(_largest), |
269 | 5.14k | being_compacted(_being_compacted) { |
270 | 5.14k | } |
271 | | |
272 | | // Total file(s) (metadata and data (aka s-block) files) size in bytes. |
273 | | uint64_t total_size = 0; |
274 | | // Base file size in bytes. |
275 | | uint64_t base_size = 0; |
276 | | // Total uncompressed size in bytes. |
277 | | uint64_t uncompressed_size = 0; |
278 | | // The name of the file. |
279 | | std::string name; |
280 | | // The full path where the file locates. |
281 | | std::string db_path; |
282 | | |
283 | | BoundaryValues smallest; |
284 | | BoundaryValues largest; |
285 | | bool imported = false; |
286 | | bool being_compacted = false; // true if the file is currently being compacted. |
287 | | }; |
288 | | |
289 | | // The full set of metadata associated with each SST file. |
290 | | struct LiveFileMetaData : SstFileMetaData { |
291 | | std::string column_family_name; // Name of the column family |
292 | | int level; // Level at which this file resides. |
293 | | |
294 | | std::string ToString() const; |
295 | | }; |
296 | | |
297 | | } // namespace rocksdb |
298 | | |
299 | | #endif // YB_ROCKSDB_METADATA_H |