mu是在阻塞操作时加的锁;
read和dirty是两个map,可以把read理解为dirty的缓存(之后会详解sync.map中的读操作),且需要注意read和dirty中存储的value都是指针;
misses是一个int值,用于记录在read中没有读到但在dirty中存在的值的次数(缓存未命中)且在misses值到一个阈值之后会发生一次dirty转换为read(后面简称dr转换);
Load方法比较简单,用于从map中获取对应key的value,主要逻辑是先从read中查找key,如果read中没有找到,再去dirty中找,并调用missLocked方法使misses值加一,missLocked方法中如果misses值大于dirty的长度后,会进行一次dr转换。
注意:
a.这里用到了加锁双重检查,具体原因后面再解释,sync.Map中很多地方都用了这个。
b.amended是一个bool值,当dirty中有read中没有的kv对时为true,只有在dr转换发生后且没有新的kv store进来,dirty为nil,才会为false
然后是Store方法,用于存储kv
在调用Store方法时有两种情况,一种是新增kv,一种是替换一个key的旧value值。如果是进行值的替换,sync.Map在进行值的替换的时候,先是直接在read中进行替换,因为前面说过read和dirty中存储的都是指针,所以在read中替换值,dirty也是可见的。如果替换失败(该key在read中的value为expunged)或是read中没有找到这个key,则进入下面的逻辑。首先如果确定该key在read中的value为expunged,则重新在dirty新增该kv,并将v进行替换;如果是在read中没有这个key,但dirty中有,说明这个kv是新增到dirty的且之后未发生dr转换,此时在dirty中对旧v进行替换;如果dirty中也没有这个kv,先判断是否刚进行过一次dr转换(判断amended的值),如果是则调用dirtylocked方法,然后在dirty中新增kv
dirtylocked方法将read中的v不为nil的kv复制到dirty中,read为nil的kv(后面可以知道这是被delete掉的kv)则将v设置为expunged,在下次dr转换时即被永久删除。
最后再看看Delete方法,调用Delete后先看在read中是否有该kv,如果有,就调用e.delete方法进行删除,如果没有再看dirty中是否存在该kv,如果有则用golang的delete方法从dirty中删除
e.delete方法是是惰性删除,调用后将read中该kv的v设置为nil。
有疑问加站长微信联系(非本文作者)