/
mmap.go
136 lines (119 loc) · 2.94 KB
/
mmap.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Generated from https://github.com/streamrail/concurrent-map
package stratum
import (
"hash/fnv"
"sync"
)
var SHARD_COUNT = 32
// TODO: Add Keys function which returns an array of keys for the map.
// A "thread" safe map of type string:*Miner.
// To avoid lock bottlenecks this map is dived to several (SHARD_COUNT) map shards.
type MinersMap []*MinersMapShared
type MinersMapShared struct {
items map[string]*Miner
sync.RWMutex // Read Write mutex, guards access to internal map.
}
// Creates a new concurrent map.
func NewMinersMap() MinersMap {
m := make(MinersMap, SHARD_COUNT)
for i := 0; i < SHARD_COUNT; i++ {
m[i] = &MinersMapShared{items: make(map[string]*Miner)}
}
return m
}
// Returns shard under given key
func (m MinersMap) GetShard(key string) *MinersMapShared {
hasher := fnv.New32()
_, _ = hasher.Write([]byte(key))
return m[int(hasher.Sum32())%SHARD_COUNT]
}
// Sets the given value under the specified key.
func (m *MinersMap) Set(key string, value *Miner) {
// Get map shard.
shard := m.GetShard(key)
shard.Lock()
defer shard.Unlock()
shard.items[key] = value
}
// Retrieves an element from map under given key.
func (m MinersMap) Get(key string) (*Miner, bool) {
// Get shard
shard := m.GetShard(key)
shard.RLock()
defer shard.RUnlock()
// Get item from shard.
val, ok := shard.items[key]
return val, ok
}
// Returns the number of elements within the map.
func (m MinersMap) Count() int {
count := 0
for i := 0; i < SHARD_COUNT; i++ {
shard := m[i]
shard.RLock()
count += len(shard.items)
shard.RUnlock()
}
return count
}
// Looks up an item under specified key
func (m *MinersMap) Has(key string) bool {
// Get shard
shard := m.GetShard(key)
shard.RLock()
defer shard.RUnlock()
// See if element is within shard.
_, ok := shard.items[key]
return ok
}
// Removes an element from the map.
func (m *MinersMap) Remove(key string) {
// Try to get shard.
shard := m.GetShard(key)
shard.Lock()
defer shard.Unlock()
delete(shard.items, key)
}
// Checks if map is empty.
func (m *MinersMap) IsEmpty() bool {
return m.Count() == 0
}
// Used by the Iter & IterBuffered functions to wrap two variables together over a channel,
type Tuple struct {
Key string
Val *Miner
}
// Returns an iterator which could be used in a for range loop.
func (m MinersMap) Iter() <-chan Tuple {
ch := make(chan Tuple)
go func() {
// Foreach shard.
for _, shard := range m {
// Foreach key, value pair.
shard.RLock()
for key, val := range shard.items {
ch <- Tuple{key, val}
}
shard.RUnlock()
}
close(ch)
}()
return ch
}
// Returns a buffered iterator which could be used in a for range loop.
func (m MinersMap) IterBuffered() <-chan Tuple {
ch := make(chan Tuple, m.Count())
go func() {
// Foreach shard.
for _, shard := range m {
// Foreach key, value pair.
shard.RLock()
for key, val := range shard.items {
ch <- Tuple{key, val}
}
shard.RUnlock()
}
close(ch)
}()
return ch
}