Skip to content

Commit f38dd7c

Browse files
refactor: enhanced uuid
- more allocation friendly uuid string function - use buffered rand.Reader to reduce syscalls - uuid benchmarks Signed-off-by: Marcus Brandenburger <bur@zurich.ibm.com>
1 parent 6cc7726 commit f38dd7c

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

pkg/utils/uuid.go

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,18 @@ package utils
88

99
import (
1010
"crypto/rand"
11+
"encoding/hex"
1112
"fmt"
1213
"io"
14+
"sync"
15+
)
16+
17+
const randPoolSize = 16 * 16
18+
19+
var (
20+
poolMu sync.Mutex
21+
poolPos = randPoolSize // protected with poolMu
22+
pool [randPoolSize]byte // protected with poolMu
1323
)
1424

1525
var randChar = &poolRandReader{
@@ -38,10 +48,19 @@ func (r *poolRandReader) Read(p []byte) (int, error) {
3848
// GenerateBytesUUID returns a UUID based on RFC 4122 returning the generated bytes
3949
func GenerateBytesUUID() []byte {
4050
uuid := make([]byte, 16)
41-
_, err := io.ReadFull(rand.Reader, uuid)
42-
if err != nil {
43-
panic(fmt.Sprintf("Error generating UUID: %s", err))
51+
52+
poolMu.Lock()
53+
if poolPos == randPoolSize {
54+
_, err := io.ReadFull(rand.Reader, pool[:])
55+
if err != nil {
56+
poolMu.Unlock()
57+
panic(fmt.Sprintf("Error generating UUID: %s", err))
58+
}
59+
poolPos = 0
4460
}
61+
copy(uuid[:], pool[poolPos:(poolPos+16)])
62+
poolPos += 16
63+
poolMu.Unlock()
4564

4665
// variant bits; see section 4.1.1
4766
uuid[8] = uuid[8]&^0xc0 | 0x80
@@ -59,7 +78,17 @@ func GenerateUUID() string {
5978
}
6079

6180
func idBytesToStr(id []byte) string {
62-
return fmt.Sprintf("%x-%x-%x-%x-%x", id[0:4], id[4:6], id[6:8], id[8:10], id[10:])
81+
dst := make([]byte, 36)
82+
hex.Encode(dst[0:8], id[0:4])
83+
dst[8] = '-'
84+
hex.Encode(dst[9:13], id[4:6])
85+
dst[13] = '-'
86+
hex.Encode(dst[14:18], id[6:8])
87+
dst[18] = '-'
88+
hex.Encode(dst[19:23], id[8:10])
89+
dst[23] = '-'
90+
hex.Encode(dst[24:], id[10:16])
91+
return string(dst)
6392
}
6493

6594
// GenerateUUIDOnlyLetters returns a UUID without digits

pkg/utils/uuid_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,24 @@ import (
1515
func TestUUIDLettersOnly(t *testing.T) {
1616
assert.Regexp(t, "^[a-zA-Z]{16}$", GenerateUUIDOnlyLetters())
1717
}
18+
19+
func BenchmarkUUID(b *testing.B) {
20+
b.Run("GenerateBytesUUID", func(b *testing.B) {
21+
for b.Loop() {
22+
_ = GenerateBytesUUID()
23+
}
24+
})
25+
26+
b.Run("GenerateUUID", func(b *testing.B) {
27+
for b.Loop() {
28+
_ = GenerateUUID()
29+
}
30+
})
31+
32+
b.Run("idBytesToStr", func(b *testing.B) {
33+
k := GenerateBytesUUID()
34+
for b.Loop() {
35+
_ = idBytesToStr(k)
36+
}
37+
})
38+
}

0 commit comments

Comments
 (0)