/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 | 1.76G |   HybridTime() noexcept : v(kInvalidHybridTimeValue) {} | 
| 96 |  |  | 
| 97 | 698M |   HybridTime(MicrosTime micros, LogicalTimeComponent logical_value) { | 
| 98 | 698M |     v = (micros << kBitsForLogicalComponent) + logical_value; | 
| 99 | 698M |   } | 
| 100 |  |  | 
| 101 |  |   static inline HybridTime FromMicrosecondsAndLogicalValue( | 
| 102 | 474M |       MicrosTime micros, LogicalTimeComponent logical_value) { | 
| 103 | 474M |     return HybridTime(micros, logical_value); | 
| 104 | 474M |   } | 
| 105 |  |  | 
| 106 | 192M |   static inline HybridTime FromMicros(MicrosTime micros) { | 
| 107 | 192M |     return HybridTime(micros, 0); | 
| 108 | 192M |   } | 
| 109 |  |  | 
| 110 | 121M |   explicit HybridTime(uint64_t val) : v(val) {} | 
| 111 |  |  | 
| 112 | 427M |   bool operator ==(const HybridTime &other) const { | 
| 113 | 427M |     return v == other.v; | 
| 114 | 427M |   } | 
| 115 | 16.1M |   bool operator !=(const HybridTime &other) const { | 
| 116 | 16.1M |     return v != other.v; | 
| 117 | 16.1M |   } | 
| 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 | 18.8M |   HybridTime Decremented() const { | 
| 140 | 18.8M |     if (v == 0) return *this; | 
| 141 | 18.8M |     return HybridTime(v - 1); | 
| 142 | 18.8M |   } | 
| 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.00M |   HybridTime AddMicroseconds(MicrosTime micros) const { | 
| 152 | 1.00M |     if (is_special()) return *this; | 
| 153 | 1.00M |     return HybridTime(v + (micros << kBitsForLogicalComponent)); | 
| 154 | 1.00M |   } | 
| 155 |  |  | 
| 156 | 506 |   HybridTime AddMilliseconds(int64_t millis) const { | 
| 157 | 506 |     return AddMicroseconds(millis * MonoTime::kMicrosecondsPerMillisecond); | 
| 158 | 506 |   } | 
| 159 |  |  | 
| 160 | 0 |   HybridTime AddSeconds(int64_t seconds) const { | 
| 161 | 0 |     return AddMicroseconds(seconds * MonoTime::kMicrosecondsPerSecond); | 
| 162 | 0 |   } | 
| 163 |  |  | 
| 164 | 968k |   HybridTime AddDelta(MonoDelta delta) const { | 
| 165 | 968k |     return AddMicroseconds(delta.ToMicroseconds()); | 
| 166 | 968k |   } | 
| 167 |  |  | 
| 168 |  |   // Sets this hybrid time from 'value' | 
| 169 |  |   CHECKED_STATUS FromUint64(uint64_t value); | 
| 170 |  |  | 
| 171 | 19.8M |   static HybridTime FromPB(uint64_t value) { | 
| 172 | 18.9M |     return value ? HybridTime(value) : HybridTime(); | 
| 173 | 19.8M |   } | 
| 174 |  |  | 
| 175 | 26.7M |   HybridTimeRepr value() const { return v; } | 
| 176 |  |  | 
| 177 |  |   // Returns this HybridTime if valid, otherwise returns the one provided. | 
| 178 | 0 |   HybridTime GetValueOr(const HybridTime& other) const { | 
| 179 | 0 |     return is_valid() ? *this : other; | 
| 180 | 0 |   } | 
| 181 |  |  | 
| 182 | 1.00M |   bool is_special() const { | 
| 183 | 1.00M |     switch (v) { | 
| 184 | 1 |       case kMinHybridTimeValue: FALLTHROUGH_INTENDED; | 
| 185 | 1 |       case kMaxHybridTimeValue: FALLTHROUGH_INTENDED; | 
| 186 | 1 |       case kInvalidHybridTimeValue: | 
| 187 | 1 |         return true; | 
| 188 | 1.00M |       default: | 
| 189 | 1.00M |         return false; | 
| 190 | 1.00M |     } | 
| 191 | 1.00M |   } | 
| 192 |  |  | 
| 193 | 209M |   bool operator <(const HybridTime& other) const { | 
| 194 | 209M |     return CompareTo(other) < 0; | 
| 195 | 209M |   } | 
| 196 |  |  | 
| 197 | 84.2M |   bool operator >(const HybridTime& other) const { | 
| 198 | 84.2M |     return CompareTo(other) > 0; | 
| 199 | 84.2M |   } | 
| 200 |  |  | 
| 201 | 46.3M |   bool operator <=(const HybridTime& other) const { | 
| 202 | 46.3M |     return CompareTo(other) <= 0; | 
| 203 | 46.3M |   } | 
| 204 |  |  | 
| 205 | 371M |   bool operator >=(const HybridTime& other) const { | 
| 206 | 371M |     return CompareTo(other) >= 0; | 
| 207 | 371M |   } | 
| 208 |  |  | 
| 209 |  |   // Returns the physical value embedded in this HybridTime, in microseconds. | 
| 210 | 596M |   inline MicrosTime GetPhysicalValueMicros() const { | 
| 211 | 596M |     return v >> kBitsForLogicalComponent; | 
| 212 | 596M |   } | 
| 213 |  |  | 
| 214 |  |   MicrosTime CeilPhysicalValueMicros() const; | 
| 215 |  |  | 
| 216 | 0 |   inline int64_t PhysicalDiff(const HybridTime& other) const { | 
| 217 | 0 |     return static_cast<int64_t>(GetPhysicalValueMicros() - other.GetPhysicalValueMicros()); | 
| 218 | 0 |   } | 
| 219 |  |  | 
| 220 | 192M |   inline LogicalTimeComponent GetLogicalValue() const { | 
| 221 | 192M |     return v & kLogicalBitMask; | 
| 222 | 192M |   } | 
| 223 |  |  | 
| 224 | 1.05G |   inline bool is_valid() const { return v != kInvalidHybridTimeValue; } | 
| 225 |  |  | 
| 226 | 60.5M |   explicit operator bool() const { return is_valid(); } | 
| 227 |  |  | 
| 228 | 317M |   void MakeAtLeast(HybridTime rhs) { | 
| 229 | 317M |     if (rhs.is_valid()) { | 
| 230 | 306M |       v = is_valid() ? std::max(v, rhs.v) : rhs.v; | 
| 231 | 306M |     } | 
| 232 | 317M |   } | 
| 233 |  |  | 
| 234 | 19.0M |   void MakeAtMost(HybridTime rhs) { | 
| 235 | 19.0M |     if (rhs.is_valid()) { | 
| 236 | 18.4E |       v = is_valid() ? std::min(v, rhs.v) : rhs.v; | 
| 237 | 6.34M |     } | 
| 238 | 19.0M |   } | 
| 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 | 1.23G | inline int HybridTime::CompareTo(const HybridTime &other) const { | 
| 265 | 1.23G |   if (v < other.v) { | 
| 266 | 140M |     return -1; | 
| 267 | 1.09G |   } else if (v > other.v) { | 
| 268 | 793M |     return 1; | 
| 269 | 793M |   } | 
| 270 | 297M |   return 0; | 
| 271 | 297M | } | 
| 272 |  |  | 
| 273 | 23.2k | inline std::ostream &operator <<(std::ostream &o, const HybridTime &hybridTime) { | 
| 274 | 23.2k |   return o << hybridTime.ToString(); | 
| 275 | 23.2k | } | 
| 276 |  |  | 
| 277 |  | namespace hybrid_time_literals { | 
| 278 |  |  | 
| 279 | 0 | inline HybridTime operator "" _usec_ht(unsigned long long microseconds) { // NOLINT | 
| 280 | 0 |   return HybridTime::FromMicros(microseconds); | 
| 281 | 0 | } | 
| 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_ |