safemap.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package collection
  2. import "sync"
  3. const (
  4. copyThreshold = 1000
  5. maxDeletion = 10000
  6. )
  7. // SafeMap provides a map alternative to avoid memory leak.
  8. // This implementation is not needed until issue below fixed.
  9. // https://github.com/golang/go/issues/20135
  10. type SafeMap struct {
  11. lock sync.RWMutex
  12. deletionOld int
  13. deletionNew int
  14. dirtyOld map[interface{}]interface{}
  15. dirtyNew map[interface{}]interface{}
  16. }
  17. // NewSafeMap returns a SafeMap.
  18. func NewSafeMap() *SafeMap {
  19. return &SafeMap{
  20. dirtyOld: make(map[interface{}]interface{}),
  21. dirtyNew: make(map[interface{}]interface{}),
  22. }
  23. }
  24. // Del deletes the value with the given key from m.
  25. func (m *SafeMap) Del(key interface{}) {
  26. m.lock.Lock()
  27. if _, ok := m.dirtyOld[key]; ok {
  28. delete(m.dirtyOld, key)
  29. m.deletionOld++
  30. } else if _, ok := m.dirtyNew[key]; ok {
  31. delete(m.dirtyNew, key)
  32. m.deletionNew++
  33. }
  34. if m.deletionOld >= maxDeletion && len(m.dirtyOld) < copyThreshold {
  35. for k, v := range m.dirtyOld {
  36. m.dirtyNew[k] = v
  37. }
  38. m.dirtyOld = m.dirtyNew
  39. m.deletionOld = m.deletionNew
  40. m.dirtyNew = make(map[interface{}]interface{})
  41. m.deletionNew = 0
  42. }
  43. if m.deletionNew >= maxDeletion && len(m.dirtyNew) < copyThreshold {
  44. for k, v := range m.dirtyNew {
  45. m.dirtyOld[k] = v
  46. }
  47. m.dirtyNew = make(map[interface{}]interface{})
  48. m.deletionNew = 0
  49. }
  50. m.lock.Unlock()
  51. }
  52. // Get gets the value with the given key from m.
  53. func (m *SafeMap) Get(key interface{}) (interface{}, bool) {
  54. m.lock.RLock()
  55. defer m.lock.RUnlock()
  56. if val, ok := m.dirtyOld[key]; ok {
  57. return val, true
  58. }
  59. val, ok := m.dirtyNew[key]
  60. return val, ok
  61. }
  62. // Set sets the value into m with the given key.
  63. func (m *SafeMap) Set(key, value interface{}) {
  64. m.lock.Lock()
  65. if m.deletionOld <= maxDeletion {
  66. if _, ok := m.dirtyNew[key]; ok {
  67. delete(m.dirtyNew, key)
  68. m.deletionNew++
  69. }
  70. m.dirtyOld[key] = value
  71. } else {
  72. if _, ok := m.dirtyOld[key]; ok {
  73. delete(m.dirtyOld, key)
  74. m.deletionOld++
  75. }
  76. m.dirtyNew[key] = value
  77. }
  78. m.lock.Unlock()
  79. }
  80. // Size returns the size of m.
  81. func (m *SafeMap) Size() int {
  82. m.lock.RLock()
  83. size := len(m.dirtyOld) + len(m.dirtyNew)
  84. m.lock.RUnlock()
  85. return size
  86. }