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  }