safemap.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  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. func NewSafeMap() *SafeMap {
  18. return &SafeMap{
  19. dirtyOld: make(map[interface{}]interface{}),
  20. dirtyNew: make(map[interface{}]interface{}),
  21. }
  22. }
  23. func (m *SafeMap) Del(key interface{}) {
  24. m.lock.Lock()
  25. if _, ok := m.dirtyOld[key]; ok {
  26. delete(m.dirtyOld, key)
  27. m.deletionOld++
  28. } else if _, ok := m.dirtyNew[key]; ok {
  29. delete(m.dirtyNew, key)
  30. m.deletionNew++
  31. }
  32. if m.deletionOld >= maxDeletion && len(m.dirtyOld) < copyThreshold {
  33. for k, v := range m.dirtyOld {
  34. m.dirtyNew[k] = v
  35. }
  36. m.dirtyOld = m.dirtyNew
  37. m.deletionOld = m.deletionNew
  38. m.dirtyNew = make(map[interface{}]interface{})
  39. m.deletionNew = 0
  40. }
  41. if m.deletionNew >= maxDeletion && len(m.dirtyNew) < copyThreshold {
  42. for k, v := range m.dirtyNew {
  43. m.dirtyOld[k] = v
  44. }
  45. m.dirtyNew = make(map[interface{}]interface{})
  46. m.deletionNew = 0
  47. }
  48. m.lock.Unlock()
  49. }
  50. func (m *SafeMap) Get(key interface{}) (interface{}, bool) {
  51. m.lock.RLock()
  52. defer m.lock.RUnlock()
  53. if val, ok := m.dirtyOld[key]; ok {
  54. return val, true
  55. } else {
  56. val, ok := m.dirtyNew[key]
  57. return val, ok
  58. }
  59. }
  60. func (m *SafeMap) Set(key, value interface{}) {
  61. m.lock.Lock()
  62. if m.deletionOld <= maxDeletion {
  63. if _, ok := m.dirtyNew[key]; ok {
  64. delete(m.dirtyNew, key)
  65. m.deletionNew++
  66. }
  67. m.dirtyOld[key] = value
  68. } else {
  69. if _, ok := m.dirtyOld[key]; ok {
  70. delete(m.dirtyOld, key)
  71. m.deletionOld++
  72. }
  73. m.dirtyNew[key] = value
  74. }
  75. m.lock.Unlock()
  76. }
  77. func (m *SafeMap) Size() int {
  78. m.lock.RLock()
  79. size := len(m.dirtyOld) + len(m.dirtyNew)
  80. m.lock.RUnlock()
  81. return size
  82. }