type Map struct{
mu Mutex // 互斥锁,用以处理并发读写的问题
read atomic.Value // 包含可以并发访问的map部分,可以直接Load,但Store必须先持有mu
dirty map[interface{}]*entry //包含需要持有mu才能访问的部分,为确保dirty快速升级为read,dirty中还包含read中未删除的部分
misses int//记录从dirty表查询的次数。misses大到超过dirty拷贝的消耗时,会直接将dirty提升至read,后续的store操作会生成新的dirty。 }
read的类型为readOnly,其结构如下:
type readOnly struct{
m map[interface{}]*entry
amended bool// true if the dirty map contains some key not in m. dirty表有没有新数据的标记 amended}type entry struct{
p unsafe.Pointer // *interface{}}
// Store sets the value for a key.func(m *Map)Store(key, value interface{}){
read,_:= m.read.Load().(readOnly)// 获取read表if e, ok := read.m[key]; ok && e.tryStore(&value){// 如果read表中能找到对应key,尝试插入read表对应的key中return}
m.mu.Lock()
read,_= m.read.Load().(readOnly)// 对m加锁,重新获取read表,避免虚假报告if e, ok := read.m[key]; ok {// 在read表能查询到,但标记为expunged,则dirty表现创建entry,再存入数据到dirty表if e.unexpungeLocked(){// The entry was previously expunged, which implies that there is a// non-nil dirty map and this entry is not in it.
m.dirty[key]= e
}
e.storeLocked(&value)}elseif e, ok := m.dirty[key]; ok {// read表不存在对应key,则判断dirty表是否存在,存在则进行store操作
e.storeLocked(&value)}else{if!read.amended {// 如果// We're adding the first new key to the dirty map.// Make sure it is allocated and mark the read-only map as incomplete.
m.dirtyLocked()
m.read.Store(readOnly{m: read.m, amended:true})}
m.dirty[key]=newEntry(value)}
m.mu.Unlock()}func(e *entry)tryStore(i *interface{})bool{for{
p := atomic.LoadPointer(&e.p)if p == expunged {returnfalse}if atomic.CompareAndSwapPointer(&e.p, p, unsafe.Pointer(i)){returntrue}}}
func(m *Map)Load(key interface{})(value interface{}, ok bool){
read,_:= m.read.Load().(readOnly)
e, ok := read.m[key]if!ok && read.amended {// 如果read表没有找到则判断amended为true,表示dirty有比read表多新元素
m.mu.Lock()// Avoid reporting a spurious miss if m.dirty got promoted while we were// blocked on m.mu. (If further loads of the same key will not miss, it's// not worth copying the dirty map for this key.) // 锁住m,再去read表查询是否有想要的数据,再查一遍是为了防止dirty转为read表,避免虚假报告
read,_= m.read.Load().(readOnly)
e, ok = read.m[key]if!ok && read.amended {// 再查询一次还是没有查询到,那么从dirty表中查找
e, ok = m.dirty[key]// Regardless of whether the entry was present, record a miss: this key// will take the slow path until the dirty map is promoted to the read// map.
m.missLocked()// 判断messes次数是否小于len(dirty),大于时,将dirty表转成read表,dirty表置为nil}
m.mu.Unlock()}if!ok {// 如果read表和dirty都没有查询到,返回nilreturnnil,false}return e.load()// 找到了,返回数据}func(m *Map)missLocked(){
m.misses++if m.misses <len(m.dirty){// 如果misses小于len(dirty),继续从dirty查询,大于时将dirty转为read表且dirty置为nilreturn}
m.read.Store(readOnly{m: m.dirty})// 将dirty转为read表且dirty
m.dirty =nil// dirty表置为nil
m.misses =0}func(e *entry)load()(value interface{}, ok bool){
p := atomic.LoadPointer(&e.p)if p ==nil|| p == expunged {returnnil,false}return*(*interface{})(p),true}