The mainline syncmap.Map has allowed mutations within Range callbacks since https://golang.org/cl/37342. The reference implementations used in map_bench_test need to do the same. Change-Id: Id73d254fa01cc64a1f00eb1903488796e1282423 Reviewed-on: https://go-review.googlesource.com/42956 Run-TryBot: Bryan Mills <bcmills@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
		
			
				
	
	
		
			151 lines
		
	
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			151 lines
		
	
	
	
		
			3.4 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 syncmap_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()
 | |
| 	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) 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
 | |
| }
 |