- 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
}
}
}