package cmap import ( "sync" ) var SHARD_COUNT = 32 // 一个分片的map存储器 可并发 const ShardCount = 31 // 分区数量 // ConcurrentMap A "thread" safe map of type string:Anything. // To avoid lock bottlenecks this map is dived to several (ShardCount) map shards. type ConcurrentMap []*ConcurrentMapShared // 分片存储map 可并发 // ConcurrentMapShared A "thread" safe string to anything map. type ConcurrentMapShared struct { items map[string]interface{} sync.RWMutex // Read Write mutex, guards access to internal map. } // New Creates a new concurrent map. func New() ConcurrentMap { m := make(ConcurrentMap, SHARD_COUNT) for i := 0; i < SHARD_COUNT; i++ { m[i] = &ConcurrentMapShared{items: make(map[string]interface{})} } return m } // GetNoLock retrieves an element from map under given key. func (m ConcurrentMap) GetNoLock(shard *ConcurrentMapShared, key string) (interface{}, bool) { // Get item from shard. val, ok := shard.items[key] return val, ok } // SetNoLock retrieves an element from map under given key. func (m ConcurrentMap) SetNoLock(shard *ConcurrentMapShared, key string, value interface{}) { shard.items[key] = value } // NewConcurrentMap 创建 func NewConcurrentMap() ConcurrentMap { m := make(ConcurrentMap, ShardCount) for i := 0; i < ShardCount; i++ { m[i] = &ConcurrentMapShared{items: make(map[string]interface{})} } return m } // GetShard 返回给定键下的分片 func (m ConcurrentMap) GetShard(key string) *ConcurrentMapShared { return m[fnv32(key)&ShardCount] } // MSet 存储一组map func (m ConcurrentMap) MSet(data map[string]interface{}) { for key, value := range data { shard := m.GetShard(key) shard.Lock() shard.items[key] = value shard.Unlock() } } // Set the given value under the specified key. // 在指定的键下设置给定的值。 func (m ConcurrentMap) Set(key string, value interface{}) { // Get map shard. shard := m.GetShard(key) shard.Lock() shard.items[key] = value shard.Unlock() } // UpsertCb Callback to return new element to be inserted into the map // It is called while lock is held, therefore it MUST NOT // try to access other keys in same map, as it can lead to deadlock since // Go sync.RWLock is not reentrant // 回调函数返回新元素插入到映射中。它在锁被持有时被调用,因此它一定不要试图访问同一映射中的其他键,因为它可能导致死锁。 RWLock是不可重入的 type UpsertCb func(exist bool, valueInMap interface{}, newValue interface{}) interface{} // Upsert Insert or Update - updates existing element or inserts a new one using UpsertCb // 插入或更新——使用UpsertCb更新现有元素或插入新元素 func (m ConcurrentMap) Upsert(key string, value interface{}, cb UpsertCb) (res interface{}) { shard := m.GetShard(key) shard.Lock() v, ok := shard.items[key] res = cb(ok, v, value) shard.items[key] = res shard.Unlock() return res } // SetIfAbsent Sets the given value under the specified key if no value was associated with it. // 如果没有值与指定键关联,则在指定键下设置给定值。 func (m ConcurrentMap) SetIfAbsent(key string, value interface{}) bool { // Get map shard. shard := m.GetShard(key) shard.Lock() _, ok := shard.items[key] if !ok { shard.items[key] = value } shard.Unlock() return !ok } // Get retrieves an element from map under given key. func (m ConcurrentMap) Get(key string) (interface{}, bool) { shard := m.GetShard(key) shard.RLock() val, ok := shard.items[key] shard.RUnlock() return val, ok } // Count returns the number of elements within the map. func (m ConcurrentMap) Count() int { count := 0 for i := 0; i < ShardCount; i++ { shard := m[i] shard.RLock() count += len(shard.items) shard.RUnlock() } return count } // Has Looks up an item under specified key 存在性 func (m ConcurrentMap) Has(key string) bool { shard := m.GetShard(key) shard.RLock() _, ok := shard.items[key] shard.RUnlock() return ok } // Remove removes an element from the map. 移除 func (m ConcurrentMap) Remove(key string) { // Try to get shard. shard := m.GetShard(key) shard.Lock() delete(shard.items, key) shard.Unlock() } // RemoveCb is a callback executed in a map.RemoveCb() call, while Lock is held // If returns true, the element will be removed from the map // 是一个在map.RemoveCb()调用中执行的回调函数,当Lock被持有时,如果返回true,该元素将从map中移除 type RemoveCb func(key string, v interface{}, exists bool) bool // RemoveCb locks the shard containing the key, retrieves its current value and calls the callback with those params // If callback returns true and element exists, it will remove it from the map // Returns the value returned by the callback (even if element was not present in the map) // 如果callback返回true且element存在,则将其从map中移除。返回callback返回的值(即使element不存在于map中) func (m ConcurrentMap) RemoveCb(key string, cb RemoveCb) bool { shard := m.GetShard(key) shard.Lock() v, ok := shard.items[key] remove := cb(key, v, ok) if remove && ok { delete(shard.items, key) } shard.Unlock() return remove } // Pop removes an element from the map and returns it // 从映射中移除一个元素并返回它 func (m ConcurrentMap) Pop(key string) (v interface{}, exists bool) { // Try to get shard. shard := m.GetShard(key) shard.Lock() v, exists = shard.items[key] delete(shard.items, key) shard.Unlock() return v, exists } // IsEmpty checks if map is empty. 是否是空的 func (m ConcurrentMap) IsEmpty() bool { return m.Count() == 0 } // 将键值映射为数字uint32 func fnv32(key string) uint32 { const prime32 = uint32(16777619) hash := uint32(2166136261) for i := 0; i < len(key); i++ { hash *= prime32 hash ^= uint32(key[i]) } return hash }