bufferpool_test.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // Copyright (C) 2019 The Protocol Authors.
  2. package protocol
  3. import (
  4. "sync"
  5. "testing"
  6. "time"
  7. "github.com/syncthing/syncthing/lib/rand"
  8. )
  9. func TestGetBucketNumbers(t *testing.T) {
  10. cases := []struct {
  11. size int
  12. bkt int
  13. panics bool
  14. }{
  15. {size: 1024, bkt: 0},
  16. {size: MinBlockSize, bkt: 0},
  17. {size: MinBlockSize + 1, bkt: 1},
  18. {size: 2*MinBlockSize - 1, bkt: 1},
  19. {size: 2 * MinBlockSize, bkt: 1},
  20. {size: 2*MinBlockSize + 1, bkt: 2},
  21. {size: MaxBlockSize, bkt: len(BlockSizes) - 1},
  22. {size: MaxBlockSize + 1, panics: true},
  23. }
  24. for _, tc := range cases {
  25. if tc.panics {
  26. shouldPanic(t, func() { getBucketForLen(tc.size) })
  27. } else {
  28. res := getBucketForLen(tc.size)
  29. if res != tc.bkt {
  30. t.Errorf("block of size %d should get from bucket %d, not %d", tc.size, tc.bkt, res)
  31. }
  32. }
  33. }
  34. }
  35. func TestPutBucketNumbers(t *testing.T) {
  36. cases := []struct {
  37. size int
  38. bkt int
  39. panics bool
  40. }{
  41. {size: 1024, panics: true},
  42. {size: MinBlockSize, bkt: 0},
  43. {size: MinBlockSize + 1, panics: true},
  44. {size: 2 * MinBlockSize, bkt: 1},
  45. {size: MaxBlockSize, bkt: len(BlockSizes) - 1},
  46. {size: MaxBlockSize + 1, panics: true},
  47. }
  48. for _, tc := range cases {
  49. if tc.panics {
  50. shouldPanic(t, func() { putBucketForCap(tc.size) })
  51. } else {
  52. res := putBucketForCap(tc.size)
  53. if res != tc.bkt {
  54. t.Errorf("block of size %d should put into bucket %d, not %d", tc.size, tc.bkt, res)
  55. }
  56. }
  57. }
  58. }
  59. func TestStressBufferPool(t *testing.T) {
  60. if testing.Short() {
  61. t.Skip()
  62. }
  63. const routines = 10
  64. const runtime = 2 * time.Second
  65. bp := newBufferPool()
  66. t0 := time.Now()
  67. var wg sync.WaitGroup
  68. fail := make(chan struct{}, routines)
  69. for i := 0; i < routines; i++ {
  70. wg.Add(1)
  71. go func() {
  72. defer wg.Done()
  73. for time.Since(t0) < runtime {
  74. blocks := make([][]byte, 10)
  75. for i := range blocks {
  76. // Request a block of random size with the range
  77. // covering smaller-than-min to larger-than-max and
  78. // everything in between.
  79. want := rand.Intn(1.5 * MaxBlockSize)
  80. blocks[i] = bp.Get(want)
  81. if len(blocks[i]) != want {
  82. fail <- struct{}{}
  83. return
  84. }
  85. }
  86. for i := range blocks {
  87. bp.Put(blocks[i])
  88. }
  89. }
  90. }()
  91. }
  92. wg.Wait()
  93. select {
  94. case <-fail:
  95. t.Fatal("a block was bad size")
  96. default:
  97. }
  98. t.Log(bp.puts.Load(), bp.skips.Load(), bp.misses.Load(), bp.hits)
  99. if bp.puts.Load() == 0 || bp.skips.Load() == 0 || bp.misses.Load() == 0 {
  100. t.Error("didn't exercise some paths")
  101. }
  102. var hits int64
  103. for i := range bp.hits {
  104. hits += bp.hits[i].Load()
  105. }
  106. if hits == 0 {
  107. t.Error("didn't exercise some paths")
  108. }
  109. }
  110. func shouldPanic(t *testing.T, fn func()) {
  111. defer func() {
  112. if r := recover(); r == nil {
  113. t.Errorf("did not panic")
  114. }
  115. }()
  116. fn()
  117. }