结构
type Map struct {
mu Mutex
read atomic.Value // readOnly
dirty map[interface{}]*entry
misses int
}
type readOnly struct {
m map[interface{}]*entry
amended bool // true if the dirty map contains some key not in m.
}
type entry struct {
p unsafe.Pointer // *interface{}
}
写入
read转为readOnly- 如果在
read中存在,且不是expunged(即没有标记为删除),则使用CAS更新entry.p,成功则返回 - 加锁,再读取一次
read(dobule check) - 如果在
read中存在,且是expunged,则设置为nil,entry写入dirty,值原子写入entry.p - 如果在
dirty中存在,则原子写入entry.p - 如果都不存在
- 如果
amended为false,且dirty为nil,新建dirty,复制read中的非expunged到dirty,read中为nil的被设置为expunged - 原子设置
amended为true - 新建
entry,值写入dirty
- 如果
- 解锁
总结:entry.p为nil,entry一定同时存在read和dirty中,原子修改entry.p即可。entry.p为expunged,则在dirty中不存在,需要额外一步,将entry写入dirty
读取
read转为readOnly- 如果存在,且不是
expunged也不是nil,则返回存在,否则返回不存在 - 如果不存在,且
amended为true- 加锁,重新读取
read,如果仍然不存在,且amended为true,从dirty中读取 - 增加
misses计数,如果misses大于或等于len(m.dirty),dirty的map交换给read,dirty设为nil,清空misses,amended设为false - 解锁
- 加锁,重新读取
- 如果
dirty中也不存在,则返回不存在
总结:先读read,再读dirty,read多次不命中,交换read和dirty
删除
read转为readOnly- 如果不存在,且
amended为false,则直接返回 - 如果不存在,且
amended为true- 加锁,如果仍然不存,且
amended为true,从dirty中删除,存在则第4步 - 增加
misses计数... - 解锁
- 加锁,如果仍然不存,且
- 如果在
read中或者dirty中存在,则CAS设置entry.p设为nil
总结:在read中假删,在dirty中真删
遍历
read转为readOnly- 如果
amended为true,交换read和dirty的map,dirty的map置nil - 遍历
read中所有非nil非expunged的数据
总结:read和dirty不同步,则先同步。依靠read的只读性,可以进行安全的遍历、修改、删除。期间插入的数据不可见