| 
									
										
										
										
											2016-12-02 19:16:14 -05:00
										 |  |  | // 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() | 
					
						
							| 
									
										
										
										
											2017-05-09 16:06:53 -04:00
										 |  |  | 	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 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-12-02 19:16:14 -05:00
										 |  |  | 		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 | 
					
						
							|  |  |  | } |