175 lines
3.9 KiB
Go
175 lines
3.9 KiB
Go
// Copyright 2016 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package sync_test
|
|
|
|
import (
|
|
"sync"
|
|
"sync/atomic"
|
|
)
|
|
|
|
// This file contains reference map implementations for unit-tests.
|
|
|
|
// mapInterface is the interface Map implements.
|
|
type mapInterface interface {
|
|
Load(interface{}) (interface{}, bool)
|
|
Store(key, value interface{})
|
|
LoadOrStore(key, value interface{}) (actual interface{}, loaded bool)
|
|
LoadAndDelete(key interface{}) (value interface{}, loaded bool)
|
|
Delete(interface{})
|
|
Range(func(key, value interface{}) (shouldContinue bool))
|
|
}
|
|
|
|
// RWMutexMap is an implementation of mapInterface using a sync.RWMutex.
|
|
type RWMutexMap struct {
|
|
mu sync.RWMutex
|
|
dirty map[interface{}]interface{}
|
|
}
|
|
|
|
func (m *RWMutexMap) Load(key interface{}) (value interface{}, ok bool) {
|
|
m.mu.RLock()
|
|
value, ok = m.dirty[key]
|
|
m.mu.RUnlock()
|
|
return
|
|
}
|
|
|
|
func (m *RWMutexMap) Store(key, value interface{}) {
|
|
m.mu.Lock()
|
|
if m.dirty == nil {
|
|
m.dirty = make(map[interface{}]interface{})
|
|
}
|
|
m.dirty[key] = value
|
|
m.mu.Unlock()
|
|
}
|
|
|
|
func (m *RWMutexMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
|
|
m.mu.Lock()
|
|
actual, loaded = m.dirty[key]
|
|
if !loaded {
|
|
actual = value
|
|
if m.dirty == nil {
|
|
m.dirty = make(map[interface{}]interface{})
|
|
}
|
|
m.dirty[key] = value
|
|
}
|
|
m.mu.Unlock()
|
|
return actual, loaded
|
|
}
|
|
|
|
func (m *RWMutexMap) LoadAndDelete(key interface{}) (value interface{}, loaded bool) {
|
|
m.mu.Lock()
|
|
value, loaded = m.dirty[key]
|
|
if !loaded {
|
|
m.mu.Unlock()
|
|
return nil, false
|
|
}
|
|
delete(m.dirty, key)
|
|
m.mu.Unlock()
|
|
return value, loaded
|
|
}
|
|
|
|
func (m *RWMutexMap) Delete(key interface{}) {
|
|
m.mu.Lock()
|
|
delete(m.dirty, key)
|
|
m.mu.Unlock()
|
|
}
|
|
|
|
func (m *RWMutexMap) Range(f func(key, value interface{}) (shouldContinue bool)) {
|
|
m.mu.RLock()
|
|
keys := make([]interface{}, 0, len(m.dirty))
|
|
for k := range m.dirty {
|
|
keys = append(keys, k)
|
|
}
|
|
m.mu.RUnlock()
|
|
|
|
for _, k := range keys {
|
|
v, ok := m.Load(k)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if !f(k, v) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// DeepCopyMap is an implementation of mapInterface using a Mutex and
|
|
// atomic.Value. It makes deep copies of the map on every write to avoid
|
|
// acquiring the Mutex in Load.
|
|
type DeepCopyMap struct {
|
|
mu sync.Mutex
|
|
clean atomic.Value
|
|
}
|
|
|
|
func (m *DeepCopyMap) Load(key interface{}) (value interface{}, ok bool) {
|
|
clean, _ := m.clean.Load().(map[interface{}]interface{})
|
|
value, ok = clean[key]
|
|
return value, ok
|
|
}
|
|
|
|
func (m *DeepCopyMap) Store(key, value interface{}) {
|
|
m.mu.Lock()
|
|
dirty := m.dirty()
|
|
dirty[key] = value
|
|
m.clean.Store(dirty)
|
|
m.mu.Unlock()
|
|
}
|
|
|
|
func (m *DeepCopyMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
|
|
clean, _ := m.clean.Load().(map[interface{}]interface{})
|
|
actual, loaded = clean[key]
|
|
if loaded {
|
|
return actual, loaded
|
|
}
|
|
|
|
m.mu.Lock()
|
|
// Reload clean in case it changed while we were waiting on m.mu.
|
|
clean, _ = m.clean.Load().(map[interface{}]interface{})
|
|
actual, loaded = clean[key]
|
|
if !loaded {
|
|
dirty := m.dirty()
|
|
dirty[key] = value
|
|
actual = value
|
|
m.clean.Store(dirty)
|
|
}
|
|
m.mu.Unlock()
|
|
return actual, loaded
|
|
}
|
|
|
|
func (m *DeepCopyMap) LoadAndDelete(key interface{}) (value interface{}, loaded bool) {
|
|
m.mu.Lock()
|
|
dirty := m.dirty()
|
|
value, loaded = dirty[key]
|
|
delete(dirty, key)
|
|
m.clean.Store(dirty)
|
|
m.mu.Unlock()
|
|
return
|
|
}
|
|
|
|
func (m *DeepCopyMap) Delete(key interface{}) {
|
|
m.mu.Lock()
|
|
dirty := m.dirty()
|
|
delete(dirty, key)
|
|
m.clean.Store(dirty)
|
|
m.mu.Unlock()
|
|
}
|
|
|
|
func (m *DeepCopyMap) Range(f func(key, value interface{}) (shouldContinue bool)) {
|
|
clean, _ := m.clean.Load().(map[interface{}]interface{})
|
|
for k, v := range clean {
|
|
if !f(k, v) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func (m *DeepCopyMap) dirty() map[interface{}]interface{} {
|
|
clean, _ := m.clean.Load().(map[interface{}]interface{})
|
|
dirty := make(map[interface{}]interface{}, len(clean)+1)
|
|
for k, v := range clean {
|
|
dirty[k] = v
|
|
}
|
|
return dirty
|
|
}
|