You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

173 lines
3.5 KiB

  1. // Copyright 2016 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package syncmap_test
  5. import (
  6. "math/rand"
  7. "reflect"
  8. "runtime"
  9. "sync"
  10. "testing"
  11. "testing/quick"
  12. "golang.org/x/sync/syncmap"
  13. )
  14. type mapOp string
  15. const (
  16. opLoad = mapOp("Load")
  17. opStore = mapOp("Store")
  18. opLoadOrStore = mapOp("LoadOrStore")
  19. opDelete = mapOp("Delete")
  20. )
  21. var mapOps = [...]mapOp{opLoad, opStore, opLoadOrStore, opDelete}
  22. // mapCall is a quick.Generator for calls on mapInterface.
  23. type mapCall struct {
  24. op mapOp
  25. k, v interface{}
  26. }
  27. func (c mapCall) apply(m mapInterface) (interface{}, bool) {
  28. switch c.op {
  29. case opLoad:
  30. return m.Load(c.k)
  31. case opStore:
  32. m.Store(c.k, c.v)
  33. return nil, false
  34. case opLoadOrStore:
  35. return m.LoadOrStore(c.k, c.v)
  36. case opDelete:
  37. m.Delete(c.k)
  38. return nil, false
  39. default:
  40. panic("invalid mapOp")
  41. }
  42. }
  43. type mapResult struct {
  44. value interface{}
  45. ok bool
  46. }
  47. func randValue(r *rand.Rand) interface{} {
  48. b := make([]byte, r.Intn(4))
  49. for i := range b {
  50. b[i] = 'a' + byte(rand.Intn(26))
  51. }
  52. return string(b)
  53. }
  54. func (mapCall) Generate(r *rand.Rand, size int) reflect.Value {
  55. c := mapCall{op: mapOps[rand.Intn(len(mapOps))], k: randValue(r)}
  56. switch c.op {
  57. case opStore, opLoadOrStore:
  58. c.v = randValue(r)
  59. }
  60. return reflect.ValueOf(c)
  61. }
  62. func applyCalls(m mapInterface, calls []mapCall) (results []mapResult, final map[interface{}]interface{}) {
  63. for _, c := range calls {
  64. v, ok := c.apply(m)
  65. results = append(results, mapResult{v, ok})
  66. }
  67. final = make(map[interface{}]interface{})
  68. m.Range(func(k, v interface{}) bool {
  69. final[k] = v
  70. return true
  71. })
  72. return results, final
  73. }
  74. func applyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
  75. return applyCalls(new(syncmap.Map), calls)
  76. }
  77. func applyRWMutexMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
  78. return applyCalls(new(RWMutexMap), calls)
  79. }
  80. func applyDeepCopyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
  81. return applyCalls(new(DeepCopyMap), calls)
  82. }
  83. func TestMapMatchesRWMutex(t *testing.T) {
  84. if err := quick.CheckEqual(applyMap, applyRWMutexMap, nil); err != nil {
  85. t.Error(err)
  86. }
  87. }
  88. func TestMapMatchesDeepCopy(t *testing.T) {
  89. if err := quick.CheckEqual(applyMap, applyDeepCopyMap, nil); err != nil {
  90. t.Error(err)
  91. }
  92. }
  93. func TestConcurrentRange(t *testing.T) {
  94. const mapSize = 1 << 10
  95. m := new(syncmap.Map)
  96. for n := int64(1); n <= mapSize; n++ {
  97. m.Store(n, int64(n))
  98. }
  99. done := make(chan struct{})
  100. var wg sync.WaitGroup
  101. defer func() {
  102. close(done)
  103. wg.Wait()
  104. }()
  105. for g := int64(runtime.GOMAXPROCS(0)); g > 0; g-- {
  106. r := rand.New(rand.NewSource(g))
  107. wg.Add(1)
  108. go func(g int64) {
  109. defer wg.Done()
  110. for i := int64(0); ; i++ {
  111. select {
  112. case <-done:
  113. return
  114. default:
  115. }
  116. for n := int64(1); n < mapSize; n++ {
  117. if r.Int63n(mapSize) == 0 {
  118. m.Store(n, n*i*g)
  119. } else {
  120. m.Load(n)
  121. }
  122. }
  123. }
  124. }(g)
  125. }
  126. iters := 1 << 10
  127. if testing.Short() {
  128. iters = 16
  129. }
  130. for n := iters; n > 0; n-- {
  131. seen := make(map[int64]bool, mapSize)
  132. m.Range(func(ki, vi interface{}) bool {
  133. k, v := ki.(int64), vi.(int64)
  134. if v%k != 0 {
  135. t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v)
  136. }
  137. if seen[k] {
  138. t.Fatalf("Range visited key %v twice", k)
  139. }
  140. seen[k] = true
  141. return true
  142. })
  143. if len(seen) != mapSize {
  144. t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize)
  145. }
  146. }
  147. }