github.com/sandwich-go/boost@v1.3.29/xcontainer/smap/any.go (about) 1 package smap 2 3 import ( 4 "sync" 5 6 "github.com/sandwich-go/boost/z" 7 ) 8 9 //template type Concurrent(KType,VType,KeyHash) 10 11 // A thread safe map. 12 // To avoid lock bottlenecks this map is dived to several (DefaultShardCount) map shards. 13 14 var DefaultShardCount = uint64(32) 15 16 type mapKey interface { 17 int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | uintptr | float32 | float64 | complex64 | complex128 | string 18 } 19 20 type Concurrent[K mapKey, V any] struct { 21 shardedList []*Sharded[K, V] 22 shardedCount uint64 23 } 24 25 type Sharded[K mapKey, V any] struct { 26 items map[K]V 27 sync.RWMutex 28 } 29 30 type Tuple[K mapKey, V any] struct { 31 Key K 32 Val V 33 } 34 35 // NewWithSharedCount 返回协程安全版本 36 func NewWithSharedCount[K mapKey, V any](sharedCount uint64) *Concurrent[K, V] { 37 p := &Concurrent[K, V]{ 38 shardedCount: sharedCount, 39 shardedList: make([]*Sharded[K, V], sharedCount), 40 } 41 for i := uint64(0); i < sharedCount; i++ { 42 p.shardedList[i] = &Sharded[K, V]{items: make(map[K]V)} 43 } 44 return p 45 } 46 47 // New 返回协程安全版本 48 func New[K mapKey, V any]() *Concurrent[K, V] { 49 return NewWithSharedCount[K, V](DefaultShardCount) 50 } 51 52 // GetShard 返回key对应的分片 53 func (m *Concurrent[K, V]) GetShard(key K) *Sharded[K, V] { 54 return m.shardedList[z.KeyToHash(key)%m.shardedCount] 55 } 56 57 // IsEmpty 返回容器是否为空 58 func (m *Concurrent[K, V]) IsEmpty() bool { 59 return m.Count() == 0 60 } 61 62 // Set 设定元素 63 func (m *Concurrent[K, V]) Set(key K, value V) { 64 shard := m.GetShard(key) 65 shard.Lock() 66 shard.items[key] = value 67 shard.Unlock() 68 } 69 70 // Keys 返回所有的key列表 71 func (m *Concurrent[K, V]) Keys() []K { 72 var ret []K 73 for _, shard := range m.shardedList { 74 shard.RLock() 75 for key := range shard.items { 76 ret = append(ret, key) 77 } 78 shard.RUnlock() 79 } 80 return ret 81 } 82 83 // GetAll 返回所有元素副本,其中value浅拷贝 84 func (m *Concurrent[K, V]) GetAll() map[K]V { 85 data := make(map[K]V) 86 for _, shard := range m.shardedList { 87 shard.RLock() 88 for key, val := range shard.items { 89 data[key] = val 90 } 91 shard.RUnlock() 92 } 93 return data 94 } 95 96 // Clear 清空元素 97 func (m *Concurrent[K, V]) Clear() { 98 for _, shard := range m.shardedList { 99 shard.Lock() 100 shard.items = make(map[K]V) 101 shard.Unlock() 102 } 103 } 104 105 // ClearWithFuncLock 清空元素,onClear在对应分片的Lock内执行,执行完毕后对容器做整体clear操作 106 // 107 // Note: 不要在onClear对当前容器做读写操作,容易死锁 108 // 109 // data.ClearWithFuncLock(func(key string,val string) { 110 // data.Get(...) // 死锁 111 // }) 112 func (m *Concurrent[K, V]) ClearWithFuncLock(onClear func(key K, val V)) { 113 for _, shard := range m.shardedList { 114 shard.Lock() 115 for key, val := range shard.items { 116 onClear(key, val) 117 } 118 shard.items = make(map[K]V) 119 shard.Unlock() 120 } 121 } 122 123 // MGet 返回多个元素 124 func (m *Concurrent[K, V]) MGet(keys ...K) map[K]V { 125 data := make(map[K]V) 126 for _, key := range keys { 127 if val, ok := m.Get(key); ok { 128 data[key] = val 129 } 130 } 131 return data 132 } 133 134 // MSet 同时设定多个元素 135 func (m *Concurrent[K, V]) MSet(data map[K]V) { 136 for key, value := range data { 137 m.Set(key, value) 138 } 139 } 140 141 // SetNX 如果key不存在,则设定为value, 设定成功则返回true,否则返回false 142 func (m *Concurrent[K, V]) SetNX(key K, value V) (isSet bool) { 143 shard := m.GetShard(key) 144 shard.Lock() 145 if _, ok := shard.items[key]; !ok { 146 shard.items[key] = value 147 isSet = true 148 } 149 shard.Unlock() 150 return isSet 151 } 152 153 // LockFuncWithKey 对key对应的分片加写锁,并用f操作该分片内数据 154 // 155 // Note: 不要对f中对容器的该分片做读写操作,可以直接操作shardData数据源 156 // 157 // data.LockFuncWithKey("test",func(shardData map[string]string) { 158 // data.Remove("test") // 当前分片已被加读锁, 死锁 159 // }) 160 func (m *Concurrent[K, V]) LockFuncWithKey(key K, f func(shardData map[K]V)) { 161 shard := m.GetShard(key) 162 shard.Lock() 163 defer shard.Unlock() 164 f(shard.items) 165 } 166 167 // RLockFuncWithKey 对key对应的分片加读锁,并用f操作该分片内数据 168 // 169 // Note: 不要在f内对容器做写操作,否则会引起死锁,可以直接操作shardData数据源 170 // 171 // data.RLockFuncWithKey("test",func(shardData map[string]string) { 172 // data.Remove("test") // 当前分片已被加读锁, 死锁 173 // }) 174 func (m *Concurrent[K, V]) RLockFuncWithKey(key K, f func(shardData map[K]V)) { 175 shard := m.GetShard(key) 176 shard.RLock() 177 defer shard.RUnlock() 178 f(shard.items) 179 } 180 181 // LockFunc 遍历容器分片,f在Lock写锁内执行 182 // 183 // Note: 不要在f内对容器做读写操作,否则会引起死锁,可以直接操作shardData数据源 184 // 185 // data.LockFunc(func(shardData map[string]string) { 186 // data.Count() // 当前分片已被加写锁, 死锁 187 // }) 188 func (m *Concurrent[K, V]) LockFunc(f func(shardData map[K]V)) { 189 for _, shard := range m.shardedList { 190 shard.Lock() 191 f(shard.items) 192 shard.Unlock() 193 } 194 } 195 196 // RLockFunc 遍历容器分片,f在RLock读锁内执行 197 // 198 // Note: 不要在f内对容器做修改操作,否则会引起死锁,可以直接操作shardData数据源 199 // 200 // data.RLockFunc(func(shardData map[string]string) { 201 // data.Remove("test") // 当前分片已被加读锁, 死锁 202 // }) 203 func (m *Concurrent[K, V]) RLockFunc(f func(shardData map[K]V)) { 204 for _, shard := range m.shardedList { 205 shard.RLock() 206 f(shard.items) 207 shard.RUnlock() 208 } 209 } 210 211 func (m *Concurrent[K, V]) doSetWithLockCheck(key K, val V) (result V, isSet bool) { 212 shard := m.GetShard(key) 213 shard.Lock() 214 215 if got, ok := shard.items[key]; ok { 216 shard.Unlock() 217 return got, false 218 } 219 220 shard.items[key] = val 221 isSet = true 222 result = val 223 shard.Unlock() 224 return 225 } 226 227 func (m *Concurrent[K, V]) doSetWithLockCheckWithFunc(key K, f func(key K) V) (result V, isSet bool) { 228 shard := m.GetShard(key) 229 shard.Lock() 230 231 if got, ok := shard.items[key]; ok { 232 shard.Unlock() 233 return got, false 234 } 235 val := f(key) 236 shard.items[key] = val 237 isSet = true 238 result = val 239 shard.Unlock() 240 return 241 } 242 243 // GetOrSetFunc 获取或者设定数值,方法f在Lock写锁外执行, 如元素早已存在则返回false,设定成功返回true 244 func (m *Concurrent[K, V]) GetOrSetFunc(key K, f func(key K) V) (result V, isSet bool) { 245 if v, ok := m.Get(key); ok { 246 return v, false 247 } 248 return m.doSetWithLockCheck(key, f(key)) 249 } 250 251 // GetOrSetFuncLock 获取或者设定数值,方法f在Lock写锁内执行, 如元素早已存在则返回false,设定成功返回true 252 // 253 // Note: 不要在f内对容器做操作,否则会死锁 254 // 255 // data.GetOrSetFuncLock(“test”,func(key string)string { 256 // data.Count() // 死锁 257 // }) 258 func (m *Concurrent[K, V]) GetOrSetFuncLock(key K, f func(key K) V) (result V, isSet bool) { 259 if v, ok := m.Get(key); ok { 260 return v, false 261 } 262 return m.doSetWithLockCheckWithFunc(key, f) 263 } 264 265 // GetOrSet 获取或设定元素, 如元素早已存在则返回false,设定成功返回true 266 func (m *Concurrent[K, V]) GetOrSet(key K, val V) (V, bool) { 267 if v, ok := m.Get(key); ok { 268 return v, false 269 } 270 return m.doSetWithLockCheck(key, val) 271 } 272 273 // Get 返回key对应的元素,不存在返回false 274 func (m *Concurrent[K, V]) Get(key K) (V, bool) { 275 shard := m.GetShard(key) 276 shard.RLock() 277 val, ok := shard.items[key] 278 shard.RUnlock() 279 return val, ok 280 } 281 282 // Len Count方法别名 283 func (m *Concurrent[K, V]) Len() int { return m.Count() } 284 285 // Size Count方法别名 286 func (m *Concurrent[K, V]) Size() int { return m.Count() } 287 288 // Count 返回容器内元素数量 289 func (m *Concurrent[K, V]) Count() int { 290 count := 0 291 for i := uint64(0); i < m.shardedCount; i++ { 292 shard := m.shardedList[i] 293 shard.RLock() 294 count += len(shard.items) 295 shard.RUnlock() 296 } 297 return count 298 } 299 300 // Has 是否存在key对应的元素 301 func (m *Concurrent[K, V]) Has(key K) bool { 302 shard := m.GetShard(key) 303 shard.RLock() 304 _, ok := shard.items[key] 305 shard.RUnlock() 306 return ok 307 } 308 309 // Remove 删除key对应的元素 310 func (m *Concurrent[K, V]) Remove(key K) { 311 shard := m.GetShard(key) 312 shard.Lock() 313 delete(shard.items, key) 314 shard.Unlock() 315 } 316 317 // GetAndRemove 返回key对应的元素并将其由容器中删除,如果元素不存在则返回false 318 func (m *Concurrent[K, V]) GetAndRemove(key K) (V, bool) { 319 shard := m.GetShard(key) 320 shard.Lock() 321 val, ok := shard.items[key] 322 delete(shard.items, key) 323 shard.Unlock() 324 return val, ok 325 } 326 327 // Iter 迭代当前容器内所有元素,使用无缓冲chan 328 // 329 // Note: 不要在迭代过程中对当前容器作修改操作(申请写锁),容易会产生死锁 330 // 331 // for v:= data.Iter() { 332 // data.Remove(v.Key) // 尝试删除元素申请分片Lock,但是Iter内部的迭代协程对分片做了RLock,导致死锁 333 // } 334 func (m *Concurrent[K, V]) Iter() <-chan Tuple[K, V] { 335 ch := make(chan Tuple[K, V]) 336 go func() { 337 // Foreach shard. 338 for _, shard := range m.shardedList { 339 shard.RLock() 340 // Foreach key, value pair. 341 for key, val := range shard.items { 342 ch <- Tuple[K, V]{key, val} 343 } 344 shard.RUnlock() 345 } 346 close(ch) 347 }() 348 return ch 349 } 350 351 // IterBuffered 迭代当前容器内所有元素,使用有缓冲chan,缓冲区大小等于容器大小,迭代过程中操作容器是安全的 352 func (m *Concurrent[K, V]) IterBuffered() <-chan Tuple[K, V] { 353 ch := make(chan Tuple[K, V], m.Count()) 354 go func() { 355 // Foreach shard. 356 for _, shard := range m.shardedList { 357 // Foreach key, value pair. 358 shard.RLock() 359 for key, val := range shard.items { 360 ch <- Tuple[K, V]{key, val} 361 } 362 shard.RUnlock() 363 } 364 close(ch) 365 }() 366 return ch 367 }