aboutsummaryrefslogtreecommitdiff
path: root/src/sync/map_reference_test.go
diff options
context:
space:
mode:
authorBryan C. Mills <bcmills@google.com>2017-02-09 11:21:42 -0500
committerBryan Mills <bcmills@google.com>2017-04-26 18:05:06 +0000
commit959025c0ac97ec3533ef9f3f70d64453352a7b56 (patch)
treeb011c6b6ccb61a8b5edebf1db2587e6456d1abc4 /src/sync/map_reference_test.go
parente1a7db7f3b9c2d684c0ac4b0cc2c845f8b70fd85 (diff)
downloadgo-959025c0ac97ec3533ef9f3f70d64453352a7b56.tar.xz
sync: import Map from x/sync/syncmap
This is a direct port of the version from commit a60ad46e0ed33d02e09bda439efaf9c9727dbc6c (https://go-review.googlesource.com/c/37342/). updates #17973 updates #18177 Change-Id: I63fa5ef6951b1edd39f84927d1181a4df9b15385 Reviewed-on: https://go-review.googlesource.com/36617 Reviewed-by: Russ Cox <rsc@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Diffstat (limited to 'src/sync/map_reference_test.go')
-rw-r--r--src/sync/map_reference_test.go142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/sync/map_reference_test.go b/src/sync/map_reference_test.go
new file mode 100644
index 0000000000..b21018c47f
--- /dev/null
+++ b/src/sync/map_reference_test.go
@@ -0,0 +1,142 @@
+// 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)
+ 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) 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()
+ defer m.mu.RUnlock()
+ for k, v := range m.dirty {
+ 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) 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
+}