Fix race condition with map

master
bel 2019-12-07 13:33:04 -07:00
parent c960b6db83
commit 08b2e8461a
1 changed files with 33 additions and 19 deletions

52
map.go
View File

@ -2,19 +2,26 @@ package storage
import ( import (
"fmt" "fmt"
"sync"
) )
type Map map[string]map[string][]byte type Map struct {
m map[string]map[string][]byte
lock *sync.RWMutex
}
func NewMap() *Map { func NewMap() *Map {
m := make(map[string]map[string][]byte) return &Map{
n := Map(m) m: make(map[string]map[string][]byte),
return &n lock: &sync.RWMutex{},
}
} }
func (m *Map) String() string { func (m *Map) String() string {
m.lock.RLock()
defer m.lock.RUnlock()
s := "" s := ""
for k, v := range *m { for k, v := range m.m {
if s != "" { if s != "" {
s += ",\n" s += ",\n"
} }
@ -24,20 +31,23 @@ func (m *Map) String() string {
} }
func (m *Map) Close() error { func (m *Map) Close() error {
m = nil m.lock.Lock()
defer m.lock.Unlock()
m.m = nil
return nil return nil
} }
func (m *Map) List(ns []string, limits ...string) ([]string, error) { func (m *Map) List(ns []string, limits ...string) ([]string, error) {
m.lock.RLock()
defer m.lock.RUnlock()
namespace := resolveNamespace(ns) namespace := resolveNamespace(ns)
limits = resolveLimits(limits) limits = resolveLimits(limits)
keys := []string{} keys := []string{}
n, _ := (*m)[DefaultNamespace] if _, ok := m.m[namespace]; !ok {
if v, ok := (*m)[namespace]; ok { namespace = DefaultNamespace
n = v
} }
for k := range n { for k := range m.m[namespace] {
if k >= limits[0] && k <= limits[1] { if k >= limits[0] && k <= limits[1] {
keys = append(keys, k) keys = append(keys, k)
} }
@ -47,29 +57,33 @@ func (m *Map) List(ns []string, limits ...string) ([]string, error) {
} }
func (m *Map) Get(key string, ns ...string) ([]byte, error) { func (m *Map) Get(key string, ns ...string) ([]byte, error) {
m.lock.RLock()
defer m.lock.RUnlock()
namespace := resolveNamespace(ns) namespace := resolveNamespace(ns)
if _, ok := (*m)[namespace]; !ok { if _, ok := m.m[namespace]; !ok {
return nil, ErrNotFound return nil, ErrNotFound
} }
if _, ok := (*m)[namespace][key]; !ok { if _, ok := m.m[namespace][key]; !ok {
return nil, ErrNotFound return nil, ErrNotFound
} }
return (*m)[namespace][key], nil return m.m[namespace][key], nil
} }
func (m *Map) Set(key string, value []byte, ns ...string) error { func (m *Map) Set(key string, value []byte, ns ...string) error {
m.lock.Lock()
defer m.lock.Unlock()
namespace := resolveNamespace(ns) namespace := resolveNamespace(ns)
if value == nil { if value == nil {
if _, ok := (*m)[namespace]; !ok { if _, ok := m.m[namespace]; !ok {
return nil return nil
} else if _, ok := (*m)[namespace][key]; ok { } else if _, ok := m.m[namespace][key]; ok {
delete((*m)[namespace], key) delete(m.m[namespace], key)
} }
} else { } else {
if _, ok := (*m)[namespace]; !ok { if _, ok := m.m[namespace]; !ok {
(*m)[namespace] = make(map[string][]byte) m.m[namespace] = make(map[string][]byte)
} }
(*m)[namespace][key] = value m.m[namespace][key] = value
} }
return nil return nil
} }