- amended标识read里数据是否已被复制到dirty
- dirty存储map里所有的数据,只有当miss次数>=dirty长度了,才会把read的m字段指向dirty数据,同时清空dirty,设置amended为false.
- 查询时read里查到值的话:返回时判断是否是nil或expunged,是的话就返回nil,不是的话就返回值。
- 查询时read里没查到的话:返回的就是dirty里查的
- 删除时read里查到值的话:删除只是把val置为nil,后续将read复制到dirty的时候,会将val置为expunged.
- 删除时read里没查到值的话:删除是在dirty里删除的。
- 插入时read里查到的话就通过cas操作直接赋值。
- 插入时read里没有的话就会加锁,然后再次从read里读取,此时read里有的话会判断val是否是expunged,是的话则将expunged通过cas操作赋值为nil并把要插入的kv插入到dirty中。不是expunged的话则直接原子性赋值。read里没有dirty里查到的话,直接通过原子性操作更改值。read里没有dirty里也没有的话,先判断read是否被复制到dirty里过,如果没有的话则先将read里非nil和非expunged的kv复制到dirty里(此过程会同时将read里的v为nil的都换成expunged,标识此k在dirty不存在,且dirty不为nil.),然后想dirty里插入此kv对。
k就是代码里的key,v就是代码里的value
-
Load方法:
func (m *Map) Load(key interface{}) (value interface{}, ok bool) {
//首先查询map的read属性上是否有值,
read, _ := m.read.Load().(readOnly)
e, ok := read.m[key]
//没有值且read已经被复制了
if !ok && read.amended {
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.)
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.
//记录一次miss
m.missLocked()
}
m.mu.Unlock()
}
if !ok {
return nil, false
}
return e.load()
}
func (m *Map) missLocked() {
m.misses++
if m.misses < len(m.dirty) {
return
}
//此时miss数大于等于dirty长度了,将read指向dirty,然后dirty赋值空
m.read.Store(readOnly{m: m.dirty})
m.dirty = nil
m.misses = 0
}
//这个方法很重要,这个方法是说在read里查到了这个key,返回值的时候,会判断是否是nil或expunged,然后再回返回值。
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
}
-
插入值
func (m *Map) Store(key, value interface{}) {
//首先查询read中是否含有此key,有的话cas尝试赋值,失败则上锁
read, _ := m.read.Load().(readOnly)
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 {
//此key之前已被删除,且不在dirty里,cas操作把它置为nil。且将k、v插入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
}
//代表之前未被删除,在read里修改它的值
e.storeLocked(&value)
} else if e, ok := m.dirty[key]; ok {
//这个key在dirty里,直接赋值
e.storeLocked(&value)
} else {
//此时read没有被复制,dirty还是空的,所以先调用m.dirtyLocked()将read里未被删除的复制到dirty里
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.
//将read里的非nil和非expunged的kv复制到dirty里,且所有的v为nil的都通过cas操作赋值成expunged
m.dirtyLocked()
m.read.Store(readOnly{m: read.m, amended: true})
}
m.dirty[key] = newEntry(value)
}
m.mu.Unlock()
}
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
}
}
}
func (e *entry) tryExpungeLocked() (isExpunged bool) {
p := atomic.LoadPointer(&e.p)
for p == nil {
if atomic.CompareAndSwapPointer(&e.p, nil, expunged) {
return true
}
p = atomic.LoadPointer(&e.p)
}
return p == expunged
}
func (e *entry) storeLocked(i *interface{}) {
atomic.StorePointer(&e.p, unsafe.Pointer(i))
}
-
删除
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()
}
}
//删除只是把v置为nil,后续将read复制到dirty的时候,会将v置为expunged.
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
}
}
}