/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 | 217M | 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 | | // Given a string holding the raw bytes in network byte order, it builds the appropriate |
85 | | // UUID object. |
86 | | CHECKED_STATUS FromBytes(const std::string& bytes); |
87 | | |
88 | | // Given a string representation of uuid in hex where the bytes are in host byte order, build |
89 | | // an appropriate UUID object. |
90 | | CHECKED_STATUS FromHexString(const std::string& hex_string); |
91 | | |
92 | | std::string ToHexString() const; |
93 | | |
94 | | // Decodes the Comparable UUID bytes into a lexical UUID. |
95 | | CHECKED_STATUS DecodeFromComparable(const std::string& bytes); |
96 | | |
97 | | // Give a slice holding raw bytes in network byte order, build the appropriate UUID |
98 | | // object. If size_hint is specified, it indicates the number of bytes to decode from the slice. |
99 | | CHECKED_STATUS FromSlice(const Slice& slice, size_t size_hint = 0); |
100 | | |
101 | | CHECKED_STATUS DecodeFromComparableSlice(const Slice& slice, size_t size_hint = 0); |
102 | | |
103 | | // For time UUIDs only. |
104 | | // This function takes a time UUID and generates a SHA hash for the MAC address bits. |
105 | | // This is done because it is not secure to generate UUIDs directly from the MAC address. |
106 | | CHECKED_STATUS HashMACAddress(); |
107 | | |
108 | | // Builds the smallest TimeUUID that willl compare as larger than any TimeUUID with the given |
109 | | // timestamp. |
110 | | CHECKED_STATUS MaxFromUnixTimestamp(int64_t timestamp_ms); |
111 | | |
112 | | // Builds the largest TimeUUID that willl compare as smaller than any TimeUUID with the given |
113 | | // timestamp. |
114 | | CHECKED_STATUS MinFromUnixTimestamp(int64_t timestamp_ms); |
115 | | |
116 | | // This function takes a 64 bit integer that represents the timestamp, that is basically the |
117 | | // number of milliseconds since epoch. |
118 | | CHECKED_STATUS ToUnixTimestamp(int64_t *timestamp_ms) const; |
119 | | |
120 | | CHECKED_STATUS IsTimeUuid() const; |
121 | | |
122 | 275M | bool IsNil() const { |
123 | 275M | return boost_uuid_.is_nil(); |
124 | 275M | } |
125 | | |
126 | 652 | bool operator==(const Uuid& other) const { |
127 | 652 | return (boost_uuid_ == other.boost_uuid_); |
128 | 652 | } |
129 | | |
130 | 1 | bool operator!=(const Uuid& other) const { |
131 | 1 | return !(*this == other); |
132 | 1 | } |
133 | | |
134 | | // A custom comparator that compares UUID v1 according to their timestamp. |
135 | | // If not, it will compare the version first and then lexicographically. |
136 | | bool operator<(const Uuid& other) const; |
137 | | |
138 | 760 | bool operator>(const Uuid& other) const { |
139 | 760 | return (other < *this); |
140 | 760 | } |
141 | | |
142 | 2 | bool operator<=(const Uuid& other) const { |
143 | 2 | return !(other < *this); |
144 | 2 | } |
145 | | |
146 | 1 | bool operator>=(const Uuid& other) const { |
147 | 1 | return !(*this < other); |
148 | 1 | } |
149 | | |
150 | 86.0M | Uuid& operator=(const Uuid& other) { |
151 | 86.0M | boost_uuid_ = other.boost_uuid_; |
152 | 86.0M | return *this; |
153 | 86.0M | } |
154 | | |
155 | 74.4M | const boost::uuids::uuid& impl() const { |
156 | 74.4M | return boost_uuid_; |
157 | 74.4M | } |
158 | | |
159 | 36.8M | uint8_t* data() { |
160 | 36.8M | return boost_uuid_.data; |
161 | 36.8M | } |
162 | | |
163 | 4.80M | const uint8_t* data() const { |
164 | 4.80M | return boost_uuid_.data; |
165 | 4.80M | } |
166 | | |
167 | 3.27M | size_t size() const { |
168 | 3.27M | return boost_uuid_.size(); |
169 | 3.27M | } |
170 | | |
171 | 14 | auto version() const { |
172 | 14 | return boost_uuid_.version(); |
173 | 14 | } |
174 | | |
175 | | private: |
176 | | boost::uuids::uuid boost_uuid_; |
177 | | |
178 | | // Encodes the MSB of the uuid into a timestamp based byte stream as follows. |
179 | | // [Timestamp Low (32 bits)][Timestamp Mid (16 bits)][Version (4 bits)][Timestamp High (12 bits)] |
180 | | // into |
181 | | // [Version (4 bits)][Timestamp High (12 bits)][Timestamp Mid (16 bits)][Timestamp Low (32 bits)] |
182 | | // So that their lexical comparison of the bytes will result in time based comparison. |
183 | 1.08k | void ToTimestampBytes(uint8_t* output) const { |
184 | 1.08k | output[0] = boost_uuid_.data[6]; |
185 | 1.08k | output[1] = boost_uuid_.data[7]; |
186 | 1.08k | output[2] = boost_uuid_.data[4]; |
187 | 1.08k | output[3] = boost_uuid_.data[5]; |
188 | 1.08k | output[4] = boost_uuid_.data[0]; |
189 | 1.08k | output[5] = boost_uuid_.data[1]; |
190 | 1.08k | output[6] = boost_uuid_.data[2]; |
191 | 1.08k | output[7] = boost_uuid_.data[3]; |
192 | 1.08k | } |
193 | | |
194 | | // Reverse the timestamp based byte stream into regular UUID style MSB. |
195 | | // See comments for toTimestampBytes function for more detail. |
196 | 6.92k | void FromTimestampBytes(const uint8_t* input) { |
197 | 6.92k | uint8_t tmp[kUuidMsbSize]; |
198 | 6.92k | tmp[0] = input[4]; |
199 | 6.92k | tmp[1] = input[5]; |
200 | 6.92k | tmp[2] = input[6]; |
201 | 6.92k | tmp[3] = input[7]; |
202 | 6.92k | tmp[4] = input[2]; |
203 | 6.92k | tmp[5] = input[3]; |
204 | 6.92k | tmp[6] = input[0]; |
205 | 6.92k | tmp[7] = input[1]; |
206 | 6.92k | memcpy(boost_uuid_.data, tmp, kUuidMsbSize); |
207 | 6.92k | } |
208 | | |
209 | | // Utility method used by minTimeuuid and maxTimeuuid. |
210 | | // Set the timestamp bytes of a (time)uuid to the specified value (in hundred nanos). |
211 | | // Also ensure that the uuid is a version 1 uuid (i.e. timeuuid) by setting the version. |
212 | | void FromTimestamp(int64_t ts_hnanos); |
213 | | |
214 | | // Encodes the MSB of the uuid into a version based byte stream as follows. |
215 | | // Used for non-time-based UUIDs, i.e. not version 1. |
216 | | // [Timestamp Low (32 bits)][Timestamp Mid (16 bits)][Version (4 bits)][Timestamp High (12 bits)] |
217 | | // into |
218 | | // [Version (4 bits)][Timestamp Low (32 bits)][Timestamp Mid (16 bits)][Timestamp High (12 bits)] |
219 | | // So that their lexical comparison of the bytes will result in version based comparison. |
220 | 16.3M | void ToVersionFirstBytes(uint8_t* output) const { |
221 | 16.3M | output[0] = (uint8_t) ( ((boost_uuid_.data[6] & 0xF0)) |
222 | 16.3M | | ((boost_uuid_.data[0] & 0xF0) >> 4)); |
223 | 16.3M | output[1] = (uint8_t) ( ((boost_uuid_.data[0] & 0x0F) << 4) |
224 | 16.3M | | ((boost_uuid_.data[1] & 0xF0) >> 4)); |
225 | 16.3M | output[2] = (uint8_t) ( ((boost_uuid_.data[1] & 0x0F) << 4) |
226 | 16.3M | | ((boost_uuid_.data[2] & 0xF0) >> 4)); |
227 | 16.3M | output[3] = (uint8_t) ( ((boost_uuid_.data[2] & 0x0F) << 4) |
228 | 16.3M | | ((boost_uuid_.data[3] & 0xF0) >> 4)); |
229 | 16.3M | output[4] = (uint8_t) ( ((boost_uuid_.data[3] & 0x0F) << 4) |
230 | 16.3M | | ((boost_uuid_.data[4] & 0xF0) >> 4)); |
231 | 16.3M | output[5] = (uint8_t) ( ((boost_uuid_.data[4] & 0x0F) << 4) |
232 | 16.3M | | ((boost_uuid_.data[5] & 0xF0) >> 4)); |
233 | 16.3M | output[6] = (uint8_t) ( ((boost_uuid_.data[5] & 0x0F) << 4) |
234 | 16.3M | | ((boost_uuid_.data[6] & 0x0F))); |
235 | 16.3M | output[7] = boost_uuid_.data[7]; |
236 | 16.3M | } |
237 | | |
238 | | // Reverse the version based byte stream into regular UUID style MSB. |
239 | | // See comments for toVersionFirstBytes function for more detail. |
240 | 87.0M | void FromVersionFirstBytes(const uint8_t* input) { |
241 | 87.0M | uint8_t tmp[kUuidMsbSize]; |
242 | 87.0M | tmp[0] = (uint8_t) ( ((input[0] & 0x0F) << 4) |
243 | 87.0M | | ((input[1] & 0xF0) >> 4)); |
244 | 87.0M | tmp[1] = (uint8_t) ( ((input[1] & 0x0F) << 4) |
245 | 87.0M | | ((input[2] & 0xF0) >> 4)); |
246 | 87.0M | tmp[2] = (uint8_t) ( ((input[2] & 0x0F) << 4) |
247 | 87.0M | | ((input[3] & 0xF0) >> 4)); |
248 | 87.0M | tmp[3] = (uint8_t) ( ((input[3] & 0x0F) << 4) |
249 | 87.0M | | ((input[4] & 0xF0) >> 4)); |
250 | 87.0M | tmp[4] = (uint8_t) ( ((input[4] & 0x0F) << 4) |
251 | 87.0M | | ((input[5] & 0xF0) >> 4)); |
252 | 87.0M | tmp[5] = (uint8_t) ( ((input[5] & 0x0F) << 4) |
253 | 87.0M | | ((input[6] & 0xF0) >> 4)); |
254 | 87.0M | tmp[6] = (uint8_t) ( ((input[0] & 0xF0)) |
255 | 87.0M | | ((input[6] & 0x0F))); |
256 | 87.0M | tmp[7] = input[7]; |
257 | 87.0M | memcpy(boost_uuid_.data, tmp, kUuidMsbSize); |
258 | 87.0M | } |
259 | | |
260 | | }; |
261 | | |
262 | | } // namespace yb |
263 | | |
264 | | #endif // YB_UTIL_UUID_H |