结论
amended: 意思是被修改过的,为true就是表明dirty和readOnly中的map的数据不相同了
readOnly中的map数据为nil: 就是正常的Delete()操作会让readOnly中的map数据值为nil,key还在
readOnly中的map数据被标记为expunged(擦去;删掉): 就是只有在readOnly生成dirty数据时,如果遇到readOnly中标记为nil的值,则标记为expunged,并且不放在dirty中,没有对应key和值
因为一个readOnly数据被抹去分为2种情况:
- 情况一(dirty提升为readOnly的map):
- 在readOnly中标记key对应的值为nil,dirty中数据的key直接被删除
- 在readOnly中的miss命中率太低了,然后dirty_map提升为readOnly中的map,readOnly中的nil值key被抹去(之前之前的dirty的key已经被删除掉了)
- 情况二(readOnly先生成dirty,之后再被dirty替换):
- 在readOnly中标记key对应的值为nil,dirty中数据的key直接被删除
- 插入过程引发的readOnly刷新未删除的数据到dirty(此时会将已经删除标记为nil的数据标记为expunged)(expunged状态可以在Store存储的时候恢复为nil)
- 等到后面miss命中率太低,然后dirty_map提升为readOnly的map,去除掉相对应的key值
从上面可以看出,nil状态下,dirty中可能有对应的key值。而expunged状态下,dirty绝对没有对应的key值,除非在增(改)的时候添加对应的key到dirty中,此时也会相对应地把expunged状态转化为nil状态
sync.Map介绍与参考文章
由浅入深聊聊Golang的sync.Map
理解的hack过程
Delete()
为什么没有更改amended的状态
感觉这两个状态的理解要理解全部实现,发现删除Delete()
是没有更改amended的状态的!!!这样的话,就会造成dirty和readOnly数据不一致(先暂时如此假设,后面会证实为错误,其实是对先前的一些定义没有深入理解),但是可能amended还是false
那么两次删除同一个数据,第一次readOlny标记为nil删除掉数据,第二次,!ok
而且还amended为false,那就导致dirty中存在数据
之后再反复读这个数据,一直miss…然后再dirty同步到readOnly,那岂不是没删除掉???
一定是哪里理解有偏差
理解了,因为readOnly和dirty中的entry指向同一片地址,所以第一次删除一个数据后,不用修改掉amended,还是完全一致的
所以得出结论是,amended在删,查的时候都不会发生变化,只有在增(改)的时候发生变化
但是同样还有这个问题就是,如果增加一个值后,连续删除这个值两次,那么就会第一次dirty中有值,第二次dirty中没有值,当然这时候readOnly是nil,但是其实是科学的,得出的结论就是nil状态下,dirty中可能有对应的key值
看了go1.18的源码就更加清晰了,源码中确定了无论dirty中是否有对应的值,也即是证明了有可能有值,有可能没有值,然后都让miss增加,因为走的是先readOnly再dirty的最长查找路径,所以需要尽快把dirty提升到readOnly上面
// LoadAndDelete deletes the value for a key, returning the previous value if any.
// The loaded result reports whether the key was present.
func (m *Map) LoadAndDelete(key any) (value any, loaded bool) {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 {e, ok = m.dirty[key]delete(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()}m.mu.Unlock()}if ok {return e.delete()}return nil, false
}// Delete deletes the value for a key.
func (m *Map) Delete(key any) {m.LoadAndDelete(key)
}