/Users/deen/code/yugabyte-db/src/yb/common/hybrid_time.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | |
33 | | // Portions Copyright (c) YugaByte, Inc. |
34 | | |
35 | | #ifndef YB_COMMON_HYBRID_TIME_H_ |
36 | | #define YB_COMMON_HYBRID_TIME_H_ |
37 | | |
38 | | #include <inttypes.h> |
39 | | |
40 | | #include <limits> |
41 | | #include <string> |
42 | | |
43 | | #include "yb/util/status_fwd.h" |
44 | | #include "yb/util/faststring.h" |
45 | | #include "yb/util/monotime.h" |
46 | | #include "yb/util/physical_time.h" |
47 | | |
48 | | namespace yb { |
49 | | |
50 | | class Slice; |
51 | | |
52 | | // An alias for the raw in-memory representation of a HybridTime. |
53 | | using HybridTimeRepr = uint64_t; |
54 | | |
55 | | // An alias for the in-memory representation of the logical component of a HybridTime. |
56 | | using LogicalTimeComponent = uint32_t; |
57 | | |
58 | | constexpr HybridTimeRepr kMinHybridTimeValue = std::numeric_limits<HybridTimeRepr>::min(); |
59 | | constexpr HybridTimeRepr kMaxHybridTimeValue = std::numeric_limits<HybridTimeRepr>::max(); |
60 | | constexpr HybridTimeRepr kInitialHybridTimeValue = kMinHybridTimeValue + 1; |
61 | | constexpr HybridTimeRepr kInvalidHybridTimeValue = kMaxHybridTimeValue - 1; |
62 | | |
63 | | // A transaction hybrid time generated by a Clock. |
64 | | class HybridTime { |
65 | | public: |
66 | | // TODO: replace all mentions of this with HybridTimeRepr itself and deprecate val_type. |
67 | | using val_type = HybridTimeRepr; |
68 | | |
69 | | // Left-shifting the microseconds timestamp 12 bits gives us 12 bits for the logical value and |
70 | | // should still keep accurate microseconds time until 2100+. |
71 | | static constexpr int kBitsForLogicalComponent = 12; |
72 | | |
73 | | // This mask gives us back the logical bits. |
74 | | static constexpr HybridTimeRepr kLogicalBitMask = (1 << kBitsForLogicalComponent) - 1; |
75 | | |
76 | | // An initial transaction hybrid time, higher than min so that we can have |
77 | | // a hybrid time guaranteed to be lower than all generated hybrid times. |
78 | | static const HybridTime kInitial; |
79 | | |
80 | | // An invalid transaction hybrid time -- HybridTime types initialize to this variable. |
81 | | static const HybridTime kInvalid; |
82 | | |
83 | | // The maximum hybrid time. |
84 | | static const HybridTime kMax; |
85 | | |
86 | | // The minimum hybrid time. |
87 | | static const HybridTime kMin; |
88 | | |
89 | | // Hybrid times are converted to debug strings as <this_string_constant>(<hybrid_time_value>). |
90 | | static const char* const kHybridTimeDebugStrPrefix; |
91 | | |
92 | | // ---------------------------------------------------------------------------------------------- |
93 | | // Constructors / static factories |
94 | | |
95 | 4.94G | HybridTime() noexcept : v(kInvalidHybridTimeValue) {} |
96 | | |
97 | 1.85G | HybridTime(MicrosTime micros, LogicalTimeComponent logical_value) { |
98 | 1.85G | v = (micros << kBitsForLogicalComponent) + logical_value; |
99 | 1.85G | } |
100 | | |
101 | | static inline HybridTime FromMicrosecondsAndLogicalValue( |
102 | 1.38G | MicrosTime micros, LogicalTimeComponent logical_value) { |
103 | 1.38G | return HybridTime(micros, logical_value); |
104 | 1.38G | } |
105 | | |
106 | 403M | static inline HybridTime FromMicros(MicrosTime micros) { |
107 | 403M | return HybridTime(micros, 0); |
108 | 403M | } |
109 | | |
110 | 258M | explicit HybridTime(uint64_t val) : v(val) {} |
111 | | |
112 | 1.23G | bool operator ==(const HybridTime &other) const { |
113 | 1.23G | return v == other.v; |
114 | 1.23G | } |
115 | 47.4M | bool operator !=(const HybridTime &other) const { |
116 | 47.4M | return v != other.v; |
117 | 47.4M | } |
118 | | |
119 | | // Decode a hybrid time from the given input slice. |
120 | | // Mutates the slice to point after the decoded hybrid time. |
121 | | // Returns true upon success. |
122 | | bool DecodeFrom(Slice *input); |
123 | | |
124 | | // Append the hybrid time to the given buffer. |
125 | | void AppendAsUint64To(faststring *dst) const; |
126 | | void AppendAsUint64To(std::string* dst) const; |
127 | | |
128 | | int CompareTo(const HybridTime &other) const; |
129 | | |
130 | | std::string ToString() const; |
131 | | |
132 | | std::string ToDebugString() const; |
133 | | |
134 | | // Returns this hybrid time as an uint64_t |
135 | | uint64_t ToUint64() const; |
136 | | |
137 | | // Return the highest value of a HybridTime that is lower than this. If called on kMin, returns |
138 | | // kMin itself, because it cannot be decremented. |
139 | 29.1M | HybridTime Decremented() const { |
140 | 29.1M | if (v == 0) return *this0 ; |
141 | 29.1M | return HybridTime(v - 1); |
142 | 29.1M | } |
143 | | |
144 | | // Returns the hybrid time value by the smallest possible amount. For invalid / max hybrid time, |
145 | | // returns the unmodified value. |
146 | 0 | HybridTime Incremented() const { |
147 | 0 | if (v >= kInvalidHybridTimeValue) return *this; |
148 | 0 | return HybridTime(v + 1); |
149 | 0 | } |
150 | | |
151 | 1.72M | HybridTime AddMicroseconds(MicrosTime micros) const { |
152 | 1.72M | if (is_special()) return *this1 ; |
153 | 1.72M | return HybridTime(v + (micros << kBitsForLogicalComponent)); |
154 | 1.72M | } |
155 | | |
156 | 529 | HybridTime AddMilliseconds(int64_t millis) const { |
157 | 529 | return AddMicroseconds(millis * MonoTime::kMicrosecondsPerMillisecond); |
158 | 529 | } |
159 | | |
160 | 353 | HybridTime AddSeconds(int64_t seconds) const { |
161 | 353 | return AddMicroseconds(seconds * MonoTime::kMicrosecondsPerSecond); |
162 | 353 | } |
163 | | |
164 | 1.67M | HybridTime AddDelta(MonoDelta delta) const { |
165 | 1.67M | return AddMicroseconds(delta.ToMicroseconds()); |
166 | 1.67M | } |
167 | | |
168 | | // Sets this hybrid time from 'value' |
169 | | CHECKED_STATUS FromUint64(uint64_t value); |
170 | | |
171 | 48.8M | static HybridTime FromPB(uint64_t value) { |
172 | 48.8M | return value ? HybridTime(value)46.2M : HybridTime()2.58M ; |
173 | 48.8M | } |
174 | | |
175 | 48.8M | HybridTimeRepr value() const { return v; } |
176 | | |
177 | | // Returns this HybridTime if valid, otherwise returns the one provided. |
178 | 74 | HybridTime GetValueOr(const HybridTime& other) const { |
179 | 74 | return is_valid() ? *this59 : other15 ; |
180 | 74 | } |
181 | | |
182 | 1.72M | bool is_special() const { |
183 | 1.72M | switch (v) { |
184 | 1 | case kMinHybridTimeValue: FALLTHROUGH_INTENDED; |
185 | 2 | case kMaxHybridTimeValue: FALLTHROUGH_INTENDED; |
186 | 3 | case kInvalidHybridTimeValue: |
187 | 3 | return true; |
188 | 1.72M | default: |
189 | 1.72M | return false; |
190 | 1.72M | } |
191 | 1.72M | } |
192 | | |
193 | 435M | bool operator <(const HybridTime& other) const { |
194 | 435M | return CompareTo(other) < 0; |
195 | 435M | } |
196 | | |
197 | 170M | bool operator >(const HybridTime& other) const { |
198 | 170M | return CompareTo(other) > 0; |
199 | 170M | } |
200 | | |
201 | 97.0M | bool operator <=(const HybridTime& other) const { |
202 | 97.0M | return CompareTo(other) <= 0; |
203 | 97.0M | } |
204 | | |
205 | 1.03G | bool operator >=(const HybridTime& other) const { |
206 | 1.03G | return CompareTo(other) >= 0; |
207 | 1.03G | } |
208 | | |
209 | | // Returns the physical value embedded in this HybridTime, in microseconds. |
210 | 1.55G | inline MicrosTime GetPhysicalValueMicros() const { |
211 | 1.55G | return v >> kBitsForLogicalComponent; |
212 | 1.55G | } |
213 | | |
214 | | MicrosTime CeilPhysicalValueMicros() const; |
215 | | |
216 | 32 | inline int64_t PhysicalDiff(const HybridTime& other) const { |
217 | 32 | return static_cast<int64_t>(GetPhysicalValueMicros() - other.GetPhysicalValueMicros()); |
218 | 32 | } |
219 | | |
220 | 550M | inline LogicalTimeComponent GetLogicalValue() const { |
221 | 550M | return v & kLogicalBitMask; |
222 | 550M | } |
223 | | |
224 | 2.75G | inline bool is_valid() const { return v != kInvalidHybridTimeValue; } |
225 | | |
226 | 140M | explicit operator bool() const { return is_valid(); } |
227 | | |
228 | 893M | void MakeAtLeast(HybridTime rhs) { |
229 | 893M | if (rhs.is_valid()) { |
230 | 872M | v = is_valid() ? std::max(v, rhs.v)871M : rhs.v599k ; |
231 | 872M | } |
232 | 893M | } |
233 | | |
234 | 34.6M | void MakeAtMost(HybridTime rhs) { |
235 | 34.6M | if (rhs.is_valid()) { |
236 | 18.4E | v = is_valid()11.5M ? std::min(v, rhs.v)11.5M : rhs.v; |
237 | 11.5M | } |
238 | 34.6M | } |
239 | | |
240 | | // Set mode for HybridTime::ToString, in case of true hybrid time is rendered as human readable. |
241 | | // It is slower than default one. |
242 | | static void TEST_SetPrettyToString(bool flag); |
243 | | |
244 | | // Acceptable system time formats: |
245 | | // 1. HybridTime Timestamp (in Microseconds) |
246 | | // 2. Interval |
247 | | // 3. Human readable string |
248 | | static Result<HybridTime> ParseHybridTime(std::string input); |
249 | | |
250 | | private: |
251 | | |
252 | | HybridTimeRepr v; |
253 | | }; |
254 | | |
255 | | // The maximum microsecond value possible so that the corresponding HybridTime can still fit into a |
256 | | // uint64_t. |
257 | | constexpr MicrosTime kMaxHybridTimePhysicalMicros{ |
258 | | kMaxHybridTimeValue >> HybridTime::kBitsForLogicalComponent}; |
259 | | |
260 | | class faststring; |
261 | | |
262 | | class Slice; |
263 | | |
264 | 3.26G | inline int HybridTime::CompareTo(const HybridTime &other) const { |
265 | 3.26G | if (v < other.v) { |
266 | 388M | return -1; |
267 | 2.87G | } else if (v > other.v) { |
268 | 2.08G | return 1; |
269 | 2.08G | } |
270 | 792M | return 0; |
271 | 3.26G | } |
272 | | |
273 | 121k | inline std::ostream &operator <<(std::ostream &o, const HybridTime &hybridTime) { |
274 | 121k | return o << hybridTime.ToString(); |
275 | 121k | } |
276 | | |
277 | | namespace hybrid_time_literals { |
278 | | |
279 | | inline HybridTime operator "" _usec_ht(unsigned long long microseconds) { // NOLINT |
280 | | return HybridTime::FromMicros(microseconds); |
281 | | } |
282 | | |
283 | | } // namespace hybrid_time_literals |
284 | | |
285 | | using hybrid_time_literals::operator"" _usec_ht; |
286 | | |
287 | | } // namespace yb |
288 | | |
289 | | #endif // YB_COMMON_HYBRID_TIME_H_ |