package mymap
import (
"fmt"
"sync"
"sync/atomic"
"unsafe"
)
type Map struct {
//用来锁dirty
mu sync.Mutex
//白桶
read atomic.Value
//黑桶
dirty map[interface{}]*entry
//脏值
misses int
}
type readOnly struct {
//封装的map
m map[interface{}]*entry
//白条
amended bool
}
//expunged是一个指针指向一个空对象,也就是指向interface{}
var expunged = unsafe.Pointer(new(interface{}))
//entry就是一个指针
type entry struct {
p unsafe.Pointer
}
func newEntry(i interface{}) *entry {
return &entry{p: unsafe.Pointer(&i)}
}
//从sync.map读数据
func (m *Map) Load(key interface{}) (value interface{}, ok bool) {
//先看白桶里面有没有key
read, _ := m.read.Load().(readOnly)
//有则直接返回
e, ok := read.m[key]
//如果白桶里没有这个key,而且白条写着“欠收拾”,说明黑桶里面可能有key
if !ok && read.amended {
m.mu.Lock()
//上面白桶获取时没有加锁,上锁后再检查一次
read, _ = m.read.Load().(readOnly)
e, ok = read.m[key]
//再检查一次也没有,则直接从黑桶里面读取数据
if !ok && read.amended {
e, ok = m.dirty[key]
//脏值+1, 如果脏值比黑桶数据数量还大,则收拾黑桶
m.missLocked()
}
m.mu.Unlock()
}
//如果白桶黑桶里都没有数据,返回nil
if !ok {
return nil, false
}
//返回entry指针对应的值
return e.load()
}
//获取entry指针对应的值
func (e *entry) load() (value interface{}, ok bool) {
p := atomic.LoadPointer(&e.p)
if p == nil || p == expunged {
return nil, false
}
return *(*interface{})(p), true
}
//往sync.map写数据
func (m *Map) Store(key, value interface{}) {
//先看白桶里面有没有key
read, _ := m.read.Load().(readOnly)
//白桶存在key直接更新白桶里面的数据
if e, ok := read.m[key]; ok && e.tryStore(&value) {
return
}
m.mu.Lock()
//上面白桶获取没有加锁,上锁后再写入一次白桶
read, _ = m.read.Load().(readOnly)
if e, ok := read.m[key]; ok {
if e.unexpungeLocked() {
//白桶存在key直接更新白桶里面的数据
m.dirty[key] = e
}
//将黑桶里面的key也指向value,相当于黑桶和白桶都指向同一份数据
e.storeLocked(&value)
} else if e, ok := m.dirty[key]; ok {
//如果白桶里面没有这个key,但是黑桶里面有,直接更新黑桶里面的数据
e.storeLocked(&value)
} else {
//白桶和黑桶都没有这个key
if !read.amended {
//如果黑桶刚刚被收拾过,白条“已收拾”,则需要将白桶里的数据,复制一份到黑桶
m.dirtyLocked()
//设置白条为“欠收拾”
m.read.Store(readOnly{m: read.m, amended: true})
}
//将新数据丢到黑桶
m.dirty[key] = newEntry(value)
}
m.mu.Unlock()
}
//tryStore就是一个基于CAS的原子写操作
func (e *entry) tryStore(i *interface{}) bool {
for {
p := atomic.LoadPointer(&e.p)
//如果原先key对应的值是一个interface{}空对象,返回失败
if p == expunged {
return false
}
//CAS原子写入entity
if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)) {
return true
}
}
}
//判断entry是否=expunged(interface{}),如果是将entry设置为nil
func (e *entry) unexpungeLocked() (wasExpunged bool) {
return atomic.CompareAndSwapPointer(&e.p, expunged, nil)
}
//原子写入entry
func (e *entry) storeLocked(i *interface{}) {
atomic.StorePointer(&e.p, unsafe.Pointer(i))
}
//参照Store
func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
read, _ := m.read.Load().(readOnly)
if e, ok := read.m[key]; ok {
actual, loaded, ok := e.tryLoadOrStore(value)
if ok {
return actual, loaded
}
}
m.mu.Lock()
read, _ = m.read.Load().(readOnly)
if e, ok := read.m[key]; ok {
if e.unexpungeLocked() {
m.dirty[key] = e
}
actual, loaded, _ = e.tryLoadOrStore(value)
} else if e, ok := m.dirty[key]; ok {
actual, loaded, _ = e.tryLoadOrStore(value)
m.missLocked()
} else {
if !read.amended {
m.dirtyLocked()
m.read.Store(readOnly{m: read.m, amended: true})
}
m.dirty[key] = newEntry(value)
actual, loaded = value, false
}
m.mu.Unlock()
return actual, loaded
}
func (e *entry) tryLoadOrStore(i interface{}) (actual interface{}, loaded, ok bool) {
p := atomic.LoadPointer(&e.p)
if p == expunged {
return nil, false, false
}
if p != nil {
return *(*interface{})(p), true, true
}
ic := i
for {
if atomic.CompareAndSwapPointer(&e.p, nil, unsafe.Pointer(&ic)) {
return i, false, true
}
p = atomic.LoadPointer(&e.p)
if p == expunged {
return nil, false, false
}
if p != nil {
return *(*interface{})(p), true, true
}
}
}
func (m *Map) Delete(key interface{}) {
read, _ := m.read.Load().(readOnly)
//数据在白桶,直接删除白桶里面的数据
e, ok := read.m[key]
if !ok && read.amended {
m.mu.Lock()
read, _ = m.read.Load().(readOnly)
e, ok = read.m[key]
//数据不在白桶,黑桶“欠收拾”
if !ok && read.amended {
//直接黑桶清除数据
delete(m.dirty, key)
}
m.mu.Unlock()
}
if ok {
e.delete()
}
}
func (e *entry) delete() (hadValue bool) {
for {
p := atomic.LoadPointer(&e.p)
if p == nil || p == expunged {
return false
}
if atomic.CompareAndSwapPointer(&e.p, p, nil) {
return true
}
}
}
func (m *Map) Range(f func(key, value interface{}) bool) {
read, _ := m.read.Load().(readOnly)
if read.amended {
m.mu.Lock()
read, _ = m.read.Load().(readOnly)
if read.amended {
read = readOnly{m: m.dirty}
m.read.Store(read)
m.dirty = nil
m.misses = 0
}
m.mu.Unlock()
}
for k, e := range read.m {
v, ok := e.load()
if !ok {
continue
}
if !f(k, v) {
break
}
}
}
//脏值+1,
func (m *Map) missLocked() {
//脏值+1,
m.misses++
//如果脏值比黑桶数据数量还大,则收拾黑桶
if m.misses < len(m.dirty) {
return
}
m.read.Store(readOnly{m: m.dirty})
//将黑桶map清空
m.dirty = nil
//将脏值清零
m.misses = 0
}
func (m *Map) dirtyLocked() {
if m.dirty != nil {
return
}
//黑桶已经被清洗过了,这里要重新初始化黑桶
read, _ := m.read.Load().(readOnly)
m.dirty = make(map[interface{}]*entry, len(read.m))
//将白桶里面的复制一份到黑桶
for k, e := range read.m {
if !e.tryExpungeLocked() {
m.dirty[k] = e
}
}
}
//这里就是判断entry是不是指向空对象或者是nil
//如果entry=是nil,赋值为空对象,也返回true
func (e *entry) tryExpungeLocked() (isExpunged bool) {
p := atomic.LoadPointer(&e.p)
for p == nil {
//如果entry指向nil,给entry赋值空对象interface{},返回true
if atomic.CompareAndSwapPointer(&e.p, nil, expunged) {
return true
}
p = atomic.LoadPointer(&e.p)
}
return p == expunged
}
评论