/Users/deen/code/yugabyte-db/src/yb/util/uuid.h
Line | Count | Source |
1 | | // Copyright (c) YugaByte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | // |
13 | | |
14 | | #ifndef YB_UTIL_UUID_H |
15 | | #define YB_UTIL_UUID_H |
16 | | |
17 | | #include <uuid/uuid.h> |
18 | | |
19 | | #include <array> |
20 | | #include <random> |
21 | | |
22 | | #include <boost/uuid/uuid.hpp> |
23 | | |
24 | | #include "yb/util/status_fwd.h" |
25 | | |
26 | | namespace yb { |
27 | | |
28 | | class Slice; |
29 | | |
30 | | constexpr size_t kUuidSize = 16; |
31 | | constexpr int kShaDigestSize = 5; |
32 | | // Generic class that UUID type and uses the boost implementation underneath. |
33 | | // Implements a custom comparator that follows the cassandra implementation. |
34 | | class Uuid { |
35 | | public: |
36 | | static constexpr size_t kUuidMsbSize = 8; |
37 | | static constexpr size_t kUuidLsbSize = kUuidSize - kUuidMsbSize; |
38 | | static constexpr size_t kTimeUUIDMacOffset = 10; |
39 | | static constexpr size_t kTimeUUIDTotalMacBytes = 6; |
40 | | |
41 | | // The timestamp is a 60-bit value. For UUID version 1, this is |
42 | | // represented by Coordinated Universal Time (UTC) as a count of 100- |
43 | | // nanosecond intervals since 00:00:00.00, 15 October 1582 (the date of |
44 | | // Gregorian reform to the Christian calendar). |
45 | | static constexpr int64_t kGregorianOffsetMillis = -12219292800000; |
46 | | |
47 | | static constexpr int64_t kMillisPerHundredNanos = 10000; |
48 | | |
49 | | Uuid(); |
50 | | |
51 | 634M | explicit Uuid(const boost::uuids::uuid& boost_uuid) : boost_uuid_(boost_uuid) {} |
52 | | |
53 | | explicit Uuid(const uuid_t copy); |
54 | | |
55 | | Uuid(const Uuid& other); |
56 | | |
57 | | // Generate a new boost uuid |
58 | | static Uuid Generate(); |
59 | | static Uuid Generate(std::mt19937_64* rng); |
60 | | static Uuid Nil(); |
61 | | |
62 | | static Result<Uuid> FromString(const std::string& strval); |
63 | | // name is used in error message in case of failure. |
64 | | static Result<Uuid> FullyDecode(const Slice& slice, const char* name = nullptr); |
65 | | static Uuid TryFullyDecode(const Slice& slice); |
66 | | static Result<Uuid> Decode(Slice* slice, const char* name = nullptr); |
67 | | |
68 | | // Fills in strval with the string representation of the UUID. |
69 | | CHECKED_STATUS ToString(std::string* strval) const; |
70 | | |
71 | | // Returns string representation the UUID. This method doesn't return a |
72 | | // Status for usecases in the code where we don't support returning a status. |
73 | | std::string ToString() const; |
74 | | |
75 | | // Fills in the given string with the raw bytes for the appropriate address in network byte order. |
76 | | void ToBytes(std::string* bytes) const; |
77 | | void ToBytes(std::array<uint8_t, kUuidSize>* out) const; |
78 | | Slice AsSlice() const; |
79 | | |
80 | | // Encodes the UUID into the time comparable uuid to be stored in RocksDB. |
81 | | void EncodeToComparable(uint8_t* output) const; |
82 | | void EncodeToComparable(std::string* bytes) const; |
83 | | |
84 | | void AppendEncodedComparable(std::string* bytes) const; |
85 | | |
86 | | // Given a string holding the raw bytes in network byte order, it builds the appropriate |
87 | | // UUID object. |
88 | | CHECKED_STATUS FromBytes(const std::string& bytes); |
89 | | |
90 | | // Given a string representation of uuid in hex where the bytes are in host byte order, build |
91 | | // an appropriate UUID object. |
92 | | CHECKED_STATUS FromHexString(const std::string& hex_string); |
93 | | |
94 | | std::string ToHexString() const; |
95 | | |
96 | | // Decodes the Comparable UUID bytes into a lexical UUID. |
97 | | CHECKED_STATUS DecodeFromComparable(const std::string& bytes); |
98 | | |
99 | | // Give a slice holding raw bytes in network byte order, build the appropriate UUID |
100 | | // object. If size_hint is specified, it indicates the number of bytes to decode from the slice. |
101 | | CHECKED_STATUS FromSlice(const Slice& slice, size_t size_hint = 0); |
102 | | |
103 | | CHECKED_STATUS DecodeFromComparableSlice(const Slice& slice, size_t size_hint = 0); |
104 | | |
105 | | // For time UUIDs only. |
106 | | // This function takes a time UUID and generates a SHA hash for the MAC address bits. |
107 | | // This is done because it is not secure to generate UUIDs directly from the MAC address. |
108 | | CHECKED_STATUS HashMACAddress(); |
109 | | |
110 | | // Builds the smallest TimeUUID that willl compare as larger than any TimeUUID with the given |
111 | | // timestamp. |
112 | | CHECKED_STATUS MaxFromUnixTimestamp(int64_t timestamp_ms); |
113 | | |
114 | | // Builds the largest TimeUUID that willl compare as smaller than any TimeUUID with the given |
115 | | // timestamp. |
116 | | CHECKED_STATUS MinFromUnixTimestamp(int64_t timestamp_ms); |
117 | | |
118 | | // This function takes a 64 bit integer that represents the timestamp, that is basically the |
119 | | // number of milliseconds since epoch. |
120 | | CHECKED_STATUS ToUnixTimestamp(int64_t *timestamp_ms) const; |
121 | | |
122 | | CHECKED_STATUS IsTimeUuid() const; |
123 | | |
124 | 662M | bool IsNil() const { |
125 | 662M | return boost_uuid_.is_nil(); |
126 | 662M | } |
127 | | |
128 | 135k | bool operator==(const Uuid& other) const { |
129 | 135k | return (boost_uuid_ == other.boost_uuid_); |
130 | 135k | } |
131 | | |
132 | | bool operator!=(const Uuid& other) const { |
133 | | return !(*this == other); |
134 | | } |
135 | | |
136 | | // A custom comparator that compares UUID v1 according to their timestamp. |
137 | | // If not, it will compare the version first and then lexicographically. |
138 | | bool operator<(const Uuid& other) const; |
139 | | |
140 | 1.69k | bool operator>(const Uuid& other) const { |
141 | 1.69k | return (other < *this); |
142 | 1.69k | } |
143 | | |
144 | | bool operator<=(const Uuid& other) const { |
145 | | return !(other < *this); |
146 | | } |
147 | | |
148 | | bool operator>=(const Uuid& other) const { |
149 | | return !(*this < other); |
150 | | } |
151 | | |
152 | 332M | Uuid& operator=(const Uuid& other) { |
153 | 332M | boost_uuid_ = other.boost_uuid_; |
154 | 332M | return *this; |
155 | 332M | } |
156 | | |
157 | 140M | const boost::uuids::uuid& impl() const { |
158 | 140M | return boost_uuid_; |
159 | 140M | } |
160 | | |
161 | 72.0M | uint8_t* data() { |
162 | 72.0M | return boost_uuid_.data; |
163 | 72.0M | } |
164 | | |
165 | 8.98M | const uint8_t* data() const { |
166 | 8.98M | return boost_uuid_.data; |
167 | 8.98M | } |
168 | | |
169 | 5.60M | size_t size() const { |
170 | 5.60M | return boost_uuid_.size(); |
171 | 5.60M | } |
172 | | |
173 | 14 | auto version() const { |
174 | 14 | return boost_uuid_.version(); |
175 | 14 | } |
176 | | |
177 | | private: |
178 | | boost::uuids::uuid boost_uuid_; |
179 | | |
180 | | // Encodes the MSB of the uuid into a timestamp based byte stream as follows. |
181 | | // [Timestamp Low (32 bits)][Timestamp Mid (16 bits)][Version (4 bits)][Timestamp High (12 bits)] |
182 | | // into |
183 | | // [Version (4 bits)][Timestamp High (12 bits)][Timestamp Mid (16 bits)][Timestamp Low (32 bits)] |
184 | | // So that their lexical comparison of the bytes will result in time based comparison. |
185 | 1.05k | void ToTimestampBytes(uint8_t* output) const { |
186 | 1.05k | output[0] = boost_uuid_.data[6]; |
187 | 1.05k | output[1] = boost_uuid_.data[7]; |
188 | 1.05k | output[2] = boost_uuid_.data[4]; |
189 | 1.05k | output[3] = boost_uuid_.data[5]; |
190 | 1.05k | output[4] = boost_uuid_.data[0]; |
191 | 1.05k | output[5] = boost_uuid_.data[1]; |
192 | 1.05k | output[6] = boost_uuid_.data[2]; |
193 | 1.05k | output[7] = boost_uuid_.data[3]; |
194 | 1.05k | } |
195 | | |
196 | | // Reverse the timestamp based byte stream into regular UUID style MSB. |
197 | | // See comments for toTimestampBytes function for more detail. |
198 | 6.69k | void FromTimestampBytes(const uint8_t* input) { |
199 | 6.69k | uint8_t tmp[kUuidMsbSize]; |
200 | 6.69k | tmp[0] = input[4]; |
201 | 6.69k | tmp[1] = input[5]; |
202 | 6.69k | tmp[2] = input[6]; |
203 | 6.69k | tmp[3] = input[7]; |
204 | 6.69k | tmp[4] = input[2]; |
205 | 6.69k | tmp[5] = input[3]; |
206 | 6.69k | tmp[6] = input[0]; |
207 | 6.69k | tmp[7] = input[1]; |
208 | 6.69k | memcpy(boost_uuid_.data, tmp, kUuidMsbSize); |
209 | 6.69k | } |
210 | | |
211 | | // Utility method used by minTimeuuid and maxTimeuuid. |
212 | | // Set the timestamp bytes of a (time)uuid to the specified value (in hundred nanos). |
213 | | // Also ensure that the uuid is a version 1 uuid (i.e. timeuuid) by setting the version. |
214 | | void FromTimestamp(int64_t ts_hnanos); |
215 | | |
216 | | // Encodes the MSB of the uuid into a version based byte stream as follows. |
217 | | // Used for non-time-based UUIDs, i.e. not version 1. |
218 | | // [Timestamp Low (32 bits)][Timestamp Mid (16 bits)][Version (4 bits)][Timestamp High (12 bits)] |
219 | | // into |
220 | | // [Version (4 bits)][Timestamp Low (32 bits)][Timestamp Mid (16 bits)][Timestamp High (12 bits)] |
221 | | // So that their lexical comparison of the bytes will result in version based comparison. |
222 | 56.9M | void ToVersionFirstBytes(uint8_t* output) const { |
223 | 56.9M | output[0] = (uint8_t) ( ((boost_uuid_.data[6] & 0xF0)) |
224 | 56.9M | | ((boost_uuid_.data[0] & 0xF0) >> 4)); |
225 | 56.9M | output[1] = (uint8_t) ( ((boost_uuid_.data[0] & 0x0F) << 4) |
226 | 56.9M | | ((boost_uuid_.data[1] & 0xF0) >> 4)); |
227 | 56.9M | output[2] = (uint8_t) ( ((boost_uuid_.data[1] & 0x0F) << 4) |
228 | 56.9M | | ((boost_uuid_.data[2] & 0xF0) >> 4)); |
229 | 56.9M | output[3] = (uint8_t) ( ((boost_uuid_.data[2] & 0x0F) << 4) |
230 | 56.9M | | ((boost_uuid_.data[3] & 0xF0) >> 4)); |
231 | 56.9M | output[4] = (uint8_t) ( ((boost_uuid_.data[3] & 0x0F) << 4) |
232 | 56.9M | | ((boost_uuid_.data[4] & 0xF0) >> 4)); |
233 | 56.9M | output[5] = (uint8_t) ( ((boost_uuid_.data[4] & 0x0F) << 4) |
234 | 56.9M | | ((boost_uuid_.data[5] & 0xF0) >> 4)); |
235 | 56.9M | output[6] = (uint8_t) ( ((boost_uuid_.data[5] & 0x0F) << 4) |
236 | 56.9M | | ((boost_uuid_.data[6] & 0x0F))); |
237 | 56.9M | output[7] = boost_uuid_.data[7]; |
238 | 56.9M | } |
239 | | |
240 | | // Reverse the version based byte stream into regular UUID style MSB. |
241 | | // See comments for toVersionFirstBytes function for more detail. |
242 | 389M | void FromVersionFirstBytes(const uint8_t* input) { |
243 | 389M | uint8_t tmp[kUuidMsbSize]; |
244 | 389M | tmp[0] = (uint8_t) ( ((input[0] & 0x0F) << 4) |
245 | 389M | | ((input[1] & 0xF0) >> 4)); |
246 | 389M | tmp[1] = (uint8_t) ( ((input[1] & 0x0F) << 4) |
247 | 389M | | ((input[2] & 0xF0) >> 4)); |
248 | 389M | tmp[2] = (uint8_t) ( ((input[2] & 0x0F) << 4) |
249 | 389M | | ((input[3] & 0xF0) >> 4)); |
250 | 389M | tmp[3] = (uint8_t) ( ((input[3] & 0x0F) << 4) |
251 | 389M | | ((input[4] & 0xF0) >> 4)); |
252 | 389M | tmp[4] = (uint8_t) ( ((input[4] & 0x0F) << 4) |
253 | 389M | | ((input[5] & 0xF0) >> 4)); |
254 | 389M | tmp[5] = (uint8_t) ( ((input[5] & 0x0F) << 4) |
255 | 389M | | ((input[6] & 0xF0) >> 4)); |
256 | 389M | tmp[6] = (uint8_t) ( ((input[0] & 0xF0)) |
257 | 389M | | ((input[6] & 0x0F))); |
258 | 389M | tmp[7] = input[7]; |
259 | 389M | memcpy(boost_uuid_.data, tmp, kUuidMsbSize); |
260 | 389M | } |
261 | | |
262 | | }; |
263 | | |
264 | | } // namespace yb |
265 | | |
266 | | #endif // YB_UTIL_UUID_H |