123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- package collection
- import "sync"
- const (
- copyThreshold = 1000
- maxDeletion = 10000
- )
- // SafeMap provides a map alternative to avoid memory leak.
- // This implementation is not needed until issue below fixed.
- // https://github.com/golang/go/issues/20135
- type SafeMap struct {
- lock sync.RWMutex
- deletionOld int
- deletionNew int
- dirtyOld map[any]any
- dirtyNew map[any]any
- }
- // NewSafeMap returns a SafeMap.
- func NewSafeMap() *SafeMap {
- return &SafeMap{
- dirtyOld: make(map[any]any),
- dirtyNew: make(map[any]any),
- }
- }
- // Del deletes the value with the given key from m.
- func (m *SafeMap) Del(key any) {
- m.lock.Lock()
- defer m.lock.Unlock()
- if _, ok := m.dirtyOld[key]; ok {
- delete(m.dirtyOld, key)
- m.deletionOld++
- } else if _, ok := m.dirtyNew[key]; ok {
- delete(m.dirtyNew, key)
- m.deletionNew++
- }
- if m.deletionOld >= maxDeletion && len(m.dirtyOld) < copyThreshold {
- for k, v := range m.dirtyOld {
- m.dirtyNew[k] = v
- }
- m.dirtyOld = m.dirtyNew
- m.deletionOld = m.deletionNew
- m.dirtyNew = make(map[any]any)
- m.deletionNew = 0
- }
- if m.deletionNew >= maxDeletion && len(m.dirtyNew) < copyThreshold {
- for k, v := range m.dirtyNew {
- m.dirtyOld[k] = v
- }
- m.dirtyNew = make(map[any]any)
- m.deletionNew = 0
- }
- }
- // Get gets the value with the given key from m.
- func (m *SafeMap) Get(key any) (any, bool) {
- m.lock.RLock()
- defer m.lock.RUnlock()
- if val, ok := m.dirtyOld[key]; ok {
- return val, true
- }
- val, ok := m.dirtyNew[key]
- return val, ok
- }
- // Range calls f sequentially for each key and value present in the map.
- // If f returns false, range stops the iteration.
- func (m *SafeMap) Range(f func(key, val any) bool) {
- m.lock.RLock()
- defer m.lock.RUnlock()
- for k, v := range m.dirtyOld {
- if !f(k, v) {
- return
- }
- }
- for k, v := range m.dirtyNew {
- if !f(k, v) {
- return
- }
- }
- }
- // Set sets the value into m with the given key.
- func (m *SafeMap) Set(key, value any) {
- m.lock.Lock()
- defer m.lock.Unlock()
- if m.deletionOld <= maxDeletion {
- if _, ok := m.dirtyNew[key]; ok {
- delete(m.dirtyNew, key)
- m.deletionNew++
- }
- m.dirtyOld[key] = value
- } else {
- if _, ok := m.dirtyOld[key]; ok {
- delete(m.dirtyOld, key)
- m.deletionOld++
- }
- m.dirtyNew[key] = value
- }
- }
- // Size returns the size of m.
- func (m *SafeMap) Size() int {
- m.lock.RLock()
- size := len(m.dirtyOld) + len(m.dirtyNew)
- m.lock.RUnlock()
- return size
- }
|