forked from karlseguin/nabu
/
idmap.go
84 lines (71 loc) · 1.41 KB
/
idmap.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
package nabu
import (
"github.com/karlseguin/nabu/key"
"hash/fnv"
"sync"
"sync/atomic"
)
const IDMAP_BUCKET_COUNT = uint32(32)
type IdMap struct {
counter uint64
lookup map[uint32]*IdMapBucket
}
type IdMapBucket struct {
sync.RWMutex
lookup map[string]key.Type
}
func newIdMap() *IdMap {
m := &IdMap{
lookup: make(map[uint32]*IdMapBucket, IDMAP_BUCKET_COUNT),
}
for i := uint32(0); i < IDMAP_BUCKET_COUNT; i++ {
m.lookup[i] = &IdMapBucket{
lookup: make(map[string]key.Type),
}
}
return m
}
// assumes not being called from multiple threads
func (m *IdMap) load(ids map[uint]string) {
max := uint(0)
for id, s := range ids {
if id > max {
max = id
}
m.getBucket(s).lookup[s] = key.Type(id)
}
m.counter = uint64(max)
}
func (m *IdMap) get(s string, create bool) key.Type {
bucket := m.getBucket(s)
bucket.RLock()
id, exists := bucket.lookup[s]
bucket.RUnlock()
if exists {
return id
}
if create == false {
return key.NULL
}
bucket.Lock()
defer bucket.Unlock()
id, exists = bucket.lookup[s]
if exists {
return id
}
id = key.Type(atomic.AddUint64(&m.counter, 1))
bucket.lookup[s] = id
return id
}
func (m *IdMap) remove(s string) {
bucket := m.getBucket(s)
bucket.Lock()
delete(bucket.lookup, s)
bucket.Unlock()
}
func (m *IdMap) getBucket(s string) *IdMapBucket {
h := fnv.New32a()
h.Write([]byte(s))
index := h.Sum32() % IDMAP_BUCKET_COUNT
return m.lookup[index]
}