YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/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