/
id_registry.go
86 lines (72 loc) · 1.89 KB
/
id_registry.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// Copyright (c) 2017 Opsidian Ltd.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package conflow
import (
"fmt"
"sync"
"github.com/conflowio/conflow/src/util"
)
// IDRegistry generates and stores identifiers
type IDRegistry interface {
IDExists(id ID) bool
RegisterID(id ID) error
GenerateID() ID
}
// idRegistry stores and generates identifiers
type idRegistry struct {
ids map[ID]struct{}
minLength int
maxLength int
lock sync.RWMutex
}
func NewIDRegistry(minLength int, maxLength int) IDRegistry {
return &idRegistry{
ids: map[ID]struct{}{},
minLength: minLength,
maxLength: maxLength,
}
}
// IDExists returns true if the identifier already exists
func (i *idRegistry) IDExists(id ID) bool {
i.lock.RLock()
defer i.lock.RUnlock()
_, exists := i.ids[id]
return exists
}
// GenerateID generates and registers a new block id
// If there are many block ids generated with the current minimum length and it's getting hard to generate unique ones
// then the min length will be increased by one (up to the maximum length)
func (i *idRegistry) GenerateID() ID {
util.SeedMathRand()
tries := 0
for {
id := ID("0x" + util.RandHexString(i.minLength, true))
err := i.RegisterID(id)
if err == nil {
return id
}
tries++
if tries == 3 {
if i.minLength < i.maxLength {
i.minLength++
tries = 0
} else {
panic("unable to generate unique id, please increase the maximum identifier length")
}
}
}
}
// RegisterID registers a new block id and returns an error if it is already taken
func (i *idRegistry) RegisterID(id ID) error {
i.lock.Lock()
defer i.lock.Unlock()
_, exists := i.ids[id]
if exists {
return fmt.Errorf("%q identifier already exists", id)
}
i.ids[id] = struct{}{}
return nil
}