github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/uuid/uuid.go (about) 1 // Copyright 2019 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 // Copyright (C) 2013-2018 by Maxim Bublis <b@codemonkey.ru> 12 // Use of this source code is governed by a MIT-style 13 // license that can be found in licenses/MIT-gofrs.txt. 14 15 // This code originated in github.com/gofrs/uuid. 16 17 package uuid 18 19 import ( 20 "encoding/binary" 21 "encoding/hex" 22 "fmt" 23 "math" 24 "time" 25 26 "github.com/cockroachdb/cockroach/pkg/util/timeutil" 27 "github.com/cockroachdb/errors" 28 ) 29 30 // Size of a UUID in bytes. 31 const Size = 16 32 33 // UUID is an array type to represent the value of a UUID, as defined in RFC-4122. 34 type UUID [Size]byte 35 36 // UUID versions. 37 const ( 38 _ byte = iota 39 V1 // Version 1 (date-time and MAC address) 40 _ // Version 2 (date-time and MAC address, DCE security version) 41 V3 // Version 3 (namespace name-based) 42 V4 // Version 4 (random) 43 V5 // Version 5 (namespace name-based) 44 ) 45 46 // UUID layout variants. 47 const ( 48 VariantNCS byte = iota 49 VariantRFC4122 50 VariantMicrosoft 51 VariantFuture 52 ) 53 54 // Timestamp is the count of 100-nanosecond intervals since 00:00:00.00, 55 // 15 October 1582 within a V1 UUID. This type has no meaning for V2-V5 56 // UUIDs since they don't have an embedded timestamp. 57 type Timestamp uint64 58 59 const _100nsPerSecond = 10000000 60 61 // Time returns the UTC time.Time representation of a Timestamp 62 func (t Timestamp) Time() (time.Time, error) { 63 secs := uint64(t) / _100nsPerSecond 64 nsecs := 100 * (uint64(t) % _100nsPerSecond) 65 return timeutil.Unix(int64(secs)-(epochStart/_100nsPerSecond), int64(nsecs)), nil 66 } 67 68 // TimestampFromV1 returns the Timestamp embedded within a V1 UUID. 69 // Returns an error if the UUID is any version other than 1. 70 func TimestampFromV1(u UUID) (Timestamp, error) { 71 if u.Version() != 1 { 72 err := fmt.Errorf("uuid: %s is version %d, not version 1", u, u.Version()) 73 return 0, err 74 } 75 low := binary.BigEndian.Uint32(u[0:4]) 76 mid := binary.BigEndian.Uint16(u[4:6]) 77 hi := binary.BigEndian.Uint16(u[6:8]) & 0xfff 78 return Timestamp(uint64(low) + (uint64(mid) << 32) + (uint64(hi) << 48)), nil 79 } 80 81 // String parse helpers. 82 var ( 83 urnPrefix = []byte("urn:uuid:") 84 byteGroups = []int{8, 4, 4, 4, 12} 85 ) 86 87 // Nil is the nil UUID, as specified in RFC-4122, that has all 128 bits set to 88 // zero. 89 var Nil = UUID{} 90 91 // Predefined namespace UUIDs. 92 var ( 93 NamespaceDNS = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) 94 NamespaceURL = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) 95 NamespaceOID = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) 96 NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) 97 ) 98 99 // Version returns the algorithm version used to generate the UUID. 100 func (u UUID) Version() byte { 101 return u[6] >> 4 102 } 103 104 // Variant returns the UUID layout variant. 105 func (u UUID) Variant() byte { 106 switch { 107 case (u[8] >> 7) == 0x00: 108 return VariantNCS 109 case (u[8] >> 6) == 0x02: 110 return VariantRFC4122 111 case (u[8] >> 5) == 0x06: 112 return VariantMicrosoft 113 case (u[8] >> 5) == 0x07: 114 fallthrough 115 default: 116 return VariantFuture 117 } 118 } 119 120 // bytes returns a byte slice representation of the UUID. It incurs an 121 // allocation if the return value escapes. 122 func (u UUID) bytes() []byte { 123 return u[:] 124 } 125 126 // bytesMut returns a mutable byte slice representation of the UUID. Unlike 127 // bytes, it does not necessarily incur an allocation if the return value 128 // escapes. Instead, the return value escaping will cause the method's receiver 129 // (and any struct that it is a part of) to escape. 130 func (u *UUID) bytesMut() []byte { 131 return u[:] 132 } 133 134 // String returns a canonical RFC-4122 string representation of the UUID: 135 // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. 136 func (u UUID) String() string { 137 buf := make([]byte, 36) 138 u.StringBytes(buf) 139 return string(buf) 140 } 141 142 // StringBytes writes the result of String directly into a buffer, which must 143 // have a length of at least 36. 144 func (u UUID) StringBytes(buf []byte) { 145 _ = buf[:36] 146 hex.Encode(buf[0:8], u[0:4]) 147 buf[8] = '-' 148 hex.Encode(buf[9:13], u[4:6]) 149 buf[13] = '-' 150 hex.Encode(buf[14:18], u[6:8]) 151 buf[18] = '-' 152 hex.Encode(buf[19:23], u[8:10]) 153 buf[23] = '-' 154 hex.Encode(buf[24:], u[10:]) 155 } 156 157 // SetVersion sets the version bits. 158 func (u *UUID) SetVersion(v byte) { 159 u[6] = (u[6] & 0x0f) | (v << 4) 160 } 161 162 // SetVariant sets the variant bits. 163 func (u *UUID) SetVariant(v byte) { 164 switch v { 165 case VariantNCS: 166 u[8] = (u[8]&(0xff>>1) | (0x00 << 7)) 167 case VariantRFC4122: 168 u[8] = (u[8]&(0xff>>2) | (0x02 << 6)) 169 case VariantMicrosoft: 170 u[8] = (u[8]&(0xff>>3) | (0x06 << 5)) 171 case VariantFuture: 172 fallthrough 173 default: 174 u[8] = (u[8]&(0xff>>3) | (0x07 << 5)) 175 } 176 } 177 178 // Must is a helper that wraps a call to a function returning (UUID, error) 179 // and panics if the error is non-nil. It is intended for use in variable 180 // initializations such as 181 // var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000")) 182 func Must(u UUID, err error) UUID { 183 if err != nil { 184 panic(err) 185 } 186 return u 187 } 188 189 // DeterministicV4 overwrites this UUID with one computed deterministically to 190 // evenly fill the space of possible V4 UUIDs. `n` represents how many UUIDs 191 // will fill the space and `i` is an index into these `n` (and thus must be in 192 // the range `[0,n)`). The resulting UUIDs will be unique, evenly-spaced, and 193 // sorted. 194 func (u *UUID) DeterministicV4(i, n uint64) { 195 if i >= n { 196 panic(errors.Errorf(`i must be in [0,%d) was %d`, n, i)) 197 } 198 // V4 uuids are generated by simply filling 16 bytes with random data (then 199 // setting the version and variant), so they're randomly distributed through 200 // the space of possible values. This also means they're roughly evenly 201 // distributed. We guarantee these values to be similarly distributed. 202 // 203 // So, space the row indexes out to fill the space of the integers 204 // representable with 8 bytes. Then, because this involves some floats (and 205 // who knows what kind of crazy rounding things can happen when floats are 206 // involved), make sure they're unique by sticking the index 207 // in the lower 8 bytes. Note that we need to use BigEndian encodings to keep 208 // the uuids sorted in the same order as the ints. 209 spacing := uint64(float64(i) * float64(math.MaxUint64) / float64(n)) 210 binary.BigEndian.PutUint64(u[0:8], spacing) 211 binary.BigEndian.PutUint64(u[8:16], i) 212 u.SetVersion(V4) 213 u.SetVariant(VariantRFC4122) 214 }