memstore_test.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. // Copyright 2016 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package storage
  17. import (
  18. "context"
  19. "crypto/rand"
  20. "encoding/binary"
  21. "io/ioutil"
  22. "os"
  23. "sync"
  24. "testing"
  25. "github.com/ethereum/go-ethereum/swarm/log"
  26. )
  27. func newTestMemStore() *MemStore {
  28. storeparams := NewDefaultStoreParams()
  29. return NewMemStore(storeparams, nil)
  30. }
  31. func testMemStoreRandom(n int, processors int, chunksize int64, t *testing.T) {
  32. m := newTestMemStore()
  33. defer m.Close()
  34. testStoreRandom(m, processors, n, chunksize, t)
  35. }
  36. func testMemStoreCorrect(n int, processors int, chunksize int64, t *testing.T) {
  37. m := newTestMemStore()
  38. defer m.Close()
  39. testStoreCorrect(m, processors, n, chunksize, t)
  40. }
  41. func TestMemStoreRandom_1(t *testing.T) {
  42. testMemStoreRandom(1, 1, 0, t)
  43. }
  44. func TestMemStoreCorrect_1(t *testing.T) {
  45. testMemStoreCorrect(1, 1, 4104, t)
  46. }
  47. func TestMemStoreRandom_1_1k(t *testing.T) {
  48. testMemStoreRandom(1, 1000, 0, t)
  49. }
  50. func TestMemStoreCorrect_1_1k(t *testing.T) {
  51. testMemStoreCorrect(1, 100, 4096, t)
  52. }
  53. func TestMemStoreRandom_8_1k(t *testing.T) {
  54. testMemStoreRandom(8, 1000, 0, t)
  55. }
  56. func TestMemStoreCorrect_8_1k(t *testing.T) {
  57. testMemStoreCorrect(8, 1000, 4096, t)
  58. }
  59. func TestMemStoreNotFound(t *testing.T) {
  60. m := newTestMemStore()
  61. defer m.Close()
  62. _, err := m.Get(context.TODO(), ZeroAddr)
  63. if err != ErrChunkNotFound {
  64. t.Errorf("Expected ErrChunkNotFound, got %v", err)
  65. }
  66. }
  67. func benchmarkMemStorePut(n int, processors int, chunksize int64, b *testing.B) {
  68. m := newTestMemStore()
  69. defer m.Close()
  70. benchmarkStorePut(m, processors, n, chunksize, b)
  71. }
  72. func benchmarkMemStoreGet(n int, processors int, chunksize int64, b *testing.B) {
  73. m := newTestMemStore()
  74. defer m.Close()
  75. benchmarkStoreGet(m, processors, n, chunksize, b)
  76. }
  77. func BenchmarkMemStorePut_1_500(b *testing.B) {
  78. benchmarkMemStorePut(500, 1, 4096, b)
  79. }
  80. func BenchmarkMemStorePut_8_500(b *testing.B) {
  81. benchmarkMemStorePut(500, 8, 4096, b)
  82. }
  83. func BenchmarkMemStoreGet_1_500(b *testing.B) {
  84. benchmarkMemStoreGet(500, 1, 4096, b)
  85. }
  86. func BenchmarkMemStoreGet_8_500(b *testing.B) {
  87. benchmarkMemStoreGet(500, 8, 4096, b)
  88. }
  89. func newLDBStore(t *testing.T) (*LDBStore, func()) {
  90. dir, err := ioutil.TempDir("", "bzz-storage-test")
  91. if err != nil {
  92. t.Fatal(err)
  93. }
  94. log.Trace("memstore.tempdir", "dir", dir)
  95. ldbparams := NewLDBStoreParams(NewDefaultStoreParams(), dir)
  96. db, err := NewLDBStore(ldbparams)
  97. if err != nil {
  98. t.Fatal(err)
  99. }
  100. cleanup := func() {
  101. db.Close()
  102. err := os.RemoveAll(dir)
  103. if err != nil {
  104. t.Fatal(err)
  105. }
  106. }
  107. return db, cleanup
  108. }
  109. func TestMemStoreAndLDBStore(t *testing.T) {
  110. ldb, cleanup := newLDBStore(t)
  111. ldb.setCapacity(4000)
  112. defer cleanup()
  113. cacheCap := 200
  114. requestsCap := 200
  115. memStore := NewMemStore(NewStoreParams(4000, 200, 200, nil, nil), nil)
  116. tests := []struct {
  117. n int // number of chunks to push to memStore
  118. chunkSize uint64 // size of chunk (by default in Swarm - 4096)
  119. request bool // whether or not to set the ReqC channel on the random chunks
  120. }{
  121. {
  122. n: 1,
  123. chunkSize: 4096,
  124. request: false,
  125. },
  126. {
  127. n: 201,
  128. chunkSize: 4096,
  129. request: false,
  130. },
  131. {
  132. n: 501,
  133. chunkSize: 4096,
  134. request: false,
  135. },
  136. {
  137. n: 3100,
  138. chunkSize: 4096,
  139. request: false,
  140. },
  141. {
  142. n: 100,
  143. chunkSize: 4096,
  144. request: true,
  145. },
  146. }
  147. for i, tt := range tests {
  148. log.Info("running test", "idx", i, "tt", tt)
  149. var chunks []*Chunk
  150. for i := 0; i < tt.n; i++ {
  151. var c *Chunk
  152. if tt.request {
  153. c = NewRandomRequestChunk(tt.chunkSize)
  154. } else {
  155. c = NewRandomChunk(tt.chunkSize)
  156. }
  157. chunks = append(chunks, c)
  158. }
  159. for i := 0; i < tt.n; i++ {
  160. go ldb.Put(context.TODO(), chunks[i])
  161. memStore.Put(context.TODO(), chunks[i])
  162. if got := memStore.cache.Len(); got > cacheCap {
  163. t.Fatalf("expected to get cache capacity less than %v, but got %v", cacheCap, got)
  164. }
  165. if got := memStore.requests.Len(); got > requestsCap {
  166. t.Fatalf("expected to get requests capacity less than %v, but got %v", requestsCap, got)
  167. }
  168. }
  169. for i := 0; i < tt.n; i++ {
  170. _, err := memStore.Get(context.TODO(), chunks[i].Addr)
  171. if err != nil {
  172. if err == ErrChunkNotFound {
  173. _, err := ldb.Get(context.TODO(), chunks[i].Addr)
  174. if err != nil {
  175. t.Fatalf("couldn't get chunk %v from ldb, got error: %v", i, err)
  176. }
  177. } else {
  178. t.Fatalf("got error from memstore: %v", err)
  179. }
  180. }
  181. }
  182. // wait for all chunks to be stored before ending the test are cleaning up
  183. for i := 0; i < tt.n; i++ {
  184. <-chunks[i].dbStoredC
  185. }
  186. }
  187. }
  188. func NewRandomChunk(chunkSize uint64) *Chunk {
  189. c := &Chunk{
  190. Addr: make([]byte, 32),
  191. ReqC: nil,
  192. SData: make([]byte, chunkSize+8), // SData should be chunkSize + 8 bytes reserved for length
  193. dbStoredC: make(chan bool),
  194. dbStoredMu: &sync.Mutex{},
  195. }
  196. rand.Read(c.SData)
  197. binary.LittleEndian.PutUint64(c.SData[:8], chunkSize)
  198. hasher := MakeHashFunc(SHA3Hash)()
  199. hasher.Write(c.SData)
  200. copy(c.Addr, hasher.Sum(nil))
  201. return c
  202. }
  203. func NewRandomRequestChunk(chunkSize uint64) *Chunk {
  204. c := NewRandomChunk(chunkSize)
  205. c.ReqC = make(chan bool)
  206. return c
  207. }