Browse Source
rename ConcurrentReadMap to ConcurrentMap
rename ConcurrentReadMap to ConcurrentMap
use RWMutex lock both read and write on ConcurrentMappull/279/head
7 changed files with 195 additions and 100 deletions
-
23go/topology/collection.go
-
25go/topology/topology.go
-
13go/topology/topology_map.go
-
13go/topology/topology_replicate.go
-
13go/topology/topology_vacuum.go
-
121go/util/concurrent_map.go
-
37go/util/concurrent_read_map.go
@ -0,0 +1,121 @@ |
|||
package util |
|||
|
|||
import ( |
|||
"errors" |
|||
"sync" |
|||
) |
|||
|
|||
// A mostly for read map, which can thread-safely
|
|||
// initialize the map entries.
|
|||
type ConcurrentMap struct { |
|||
mutex sync.RWMutex |
|||
items map[string]interface{} |
|||
} |
|||
|
|||
func NewConcurrentMap() *ConcurrentMap { |
|||
return &ConcurrentMap{items: make(map[string]interface{})} |
|||
} |
|||
|
|||
func (m *ConcurrentMap) initMapEntry(key string, newEntry func() interface{}) (value interface{}) { |
|||
m.mutex.Lock() |
|||
defer m.mutex.Unlock() |
|||
if value, ok := m.items[key]; ok { |
|||
return value |
|||
} |
|||
value = newEntry() |
|||
m.items[key] = value |
|||
return value |
|||
} |
|||
|
|||
func (m *ConcurrentMap) GetOrNew(key string, newEntry func() interface{}) interface{} { |
|||
m.mutex.RLock() |
|||
value, ok := m.items[key] |
|||
m.mutex.RUnlock() |
|||
if ok { |
|||
return value |
|||
} |
|||
return m.initMapEntry(key, newEntry) |
|||
} |
|||
|
|||
func (m *ConcurrentMap) Get(key string) (item interface{}, ok bool) { |
|||
m.mutex.RLock() |
|||
defer m.mutex.RUnlock() |
|||
item, ok = m.items[key] |
|||
return |
|||
} |
|||
|
|||
func (m *ConcurrentMap) Has(key string) bool { |
|||
m.mutex.RLock() |
|||
_, ok := m.items[key] |
|||
m.mutex.RUnlock() |
|||
return ok |
|||
} |
|||
|
|||
func (m *ConcurrentMap) Delete(key string) { |
|||
m.mutex.Lock() |
|||
delete(m.items, key) |
|||
m.mutex.Unlock() |
|||
} |
|||
|
|||
func (m *ConcurrentMap) Size() int { |
|||
m.mutex.RLock() |
|||
defer m.mutex.RUnlock() |
|||
return len(m.items) |
|||
} |
|||
|
|||
// Wipes all items from the map
|
|||
func (m *ConcurrentMap) Flush() int { |
|||
m.mutex.Lock() |
|||
size := len(m.items) |
|||
m.items = make(map[string]interface{}) |
|||
m.mutex.Unlock() |
|||
return size |
|||
} |
|||
|
|||
var ErrBreakWalk = errors.New("Break walk.") |
|||
|
|||
// break walk when walker fuc return an error
|
|||
type MapWalker func(k string, v interface{}) (e error) |
|||
|
|||
// MUST NOT add or delete item in walker
|
|||
func (m *ConcurrentMap) Walk(mw MapWalker) (e error) { |
|||
m.mutex.RLock() |
|||
defer m.mutex.RUnlock() |
|||
for k, v := range m.items { |
|||
if e = mw(k, v); e != nil { |
|||
return e |
|||
} |
|||
} |
|||
return |
|||
} |
|||
|
|||
func (m *ConcurrentMap) Keys() (keys []string) { |
|||
m.mutex.RLock() |
|||
keys = make([]string, 0, len(m.items)) |
|||
for key := range m.items { |
|||
keys = append(keys, key) |
|||
} |
|||
m.mutex.RUnlock() |
|||
return |
|||
} |
|||
|
|||
// Item is a pair of key and value
|
|||
type Item struct { |
|||
Key string |
|||
Value interface{} |
|||
} |
|||
|
|||
// Return a channel from which each item (key:value pair) in the map can be read
|
|||
// You can't break the iterator
|
|||
func (m *ConcurrentMap) IterItems() <-chan Item { |
|||
ch := make(chan Item) |
|||
go func() { |
|||
m.mutex.RLock() |
|||
for key, value := range m.items { |
|||
ch <- Item{key, value} |
|||
} |
|||
m.mutex.RUnlock() |
|||
close(ch) |
|||
}() |
|||
return ch |
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
package util |
|||
|
|||
import ( |
|||
"sync" |
|||
) |
|||
|
|||
// A mostly for read map, which can thread-safely
|
|||
// initialize the map entries.
|
|||
type ConcurrentReadMap struct { |
|||
rwmutex sync.RWMutex |
|||
Items map[string]interface{} |
|||
} |
|||
|
|||
func NewConcurrentReadMap() *ConcurrentReadMap { |
|||
return &ConcurrentReadMap{Items: make(map[string]interface{})} |
|||
} |
|||
|
|||
func (m *ConcurrentReadMap) initMapEntry(key string, newEntry func() interface{}) (value interface{}) { |
|||
m.rwmutex.Lock() |
|||
defer m.rwmutex.Unlock() |
|||
if value, ok := m.Items[key]; ok { |
|||
return value |
|||
} |
|||
value = newEntry() |
|||
m.Items[key] = value |
|||
return value |
|||
} |
|||
|
|||
func (m *ConcurrentReadMap) Get(key string, newEntry func() interface{}) interface{} { |
|||
m.rwmutex.RLock() |
|||
value, ok := m.Items[key] |
|||
m.rwmutex.RUnlock() |
|||
if ok { |
|||
return value |
|||
} |
|||
return m.initMapEntry(key, newEntry) |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue