github.com/gobitfly/go-ethereum@v1.8.12/swarm/storage/common_test.go (about) 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 17 package storage 18 19 import ( 20 "bytes" 21 "crypto/rand" 22 "flag" 23 "fmt" 24 "io" 25 "sync" 26 "testing" 27 "time" 28 29 "github.com/ethereum/go-ethereum/log" 30 colorable "github.com/mattn/go-colorable" 31 ) 32 33 var ( 34 loglevel = flag.Int("loglevel", 3, "verbosity of logs") 35 ) 36 37 func init() { 38 flag.Parse() 39 log.PrintOrigins(true) 40 log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) 41 } 42 43 type brokenLimitedReader struct { 44 lr io.Reader 45 errAt int 46 off int 47 size int 48 } 49 50 func brokenLimitReader(data io.Reader, size int, errAt int) *brokenLimitedReader { 51 return &brokenLimitedReader{ 52 lr: data, 53 errAt: errAt, 54 size: size, 55 } 56 } 57 58 func mputRandomChunks(store ChunkStore, processors int, n int, chunksize int64) (hs []Address) { 59 return mput(store, processors, n, GenerateRandomChunk) 60 } 61 62 func mput(store ChunkStore, processors int, n int, f func(i int64) *Chunk) (hs []Address) { 63 wg := sync.WaitGroup{} 64 wg.Add(processors) 65 c := make(chan *Chunk) 66 for i := 0; i < processors; i++ { 67 go func() { 68 defer wg.Done() 69 for chunk := range c { 70 wg.Add(1) 71 chunk := chunk 72 store.Put(chunk) 73 go func() { 74 defer wg.Done() 75 <-chunk.dbStoredC 76 }() 77 } 78 }() 79 } 80 fa := f 81 if _, ok := store.(*MemStore); ok { 82 fa = func(i int64) *Chunk { 83 chunk := f(i) 84 chunk.markAsStored() 85 return chunk 86 } 87 } 88 for i := 0; i < n; i++ { 89 chunk := fa(int64(i)) 90 hs = append(hs, chunk.Addr) 91 c <- chunk 92 } 93 close(c) 94 wg.Wait() 95 return hs 96 } 97 98 func mget(store ChunkStore, hs []Address, f func(h Address, chunk *Chunk) error) error { 99 wg := sync.WaitGroup{} 100 wg.Add(len(hs)) 101 errc := make(chan error) 102 103 for _, k := range hs { 104 go func(h Address) { 105 defer wg.Done() 106 chunk, err := store.Get(h) 107 if err != nil { 108 errc <- err 109 return 110 } 111 if f != nil { 112 err = f(h, chunk) 113 if err != nil { 114 errc <- err 115 return 116 } 117 } 118 }(k) 119 } 120 go func() { 121 wg.Wait() 122 close(errc) 123 }() 124 var err error 125 select { 126 case err = <-errc: 127 case <-time.NewTimer(5 * time.Second).C: 128 err = fmt.Errorf("timed out after 5 seconds") 129 } 130 return err 131 } 132 133 func testDataReader(l int) (r io.Reader) { 134 return io.LimitReader(rand.Reader, int64(l)) 135 } 136 137 func (r *brokenLimitedReader) Read(buf []byte) (int, error) { 138 if r.off+len(buf) > r.errAt { 139 return 0, fmt.Errorf("Broken reader") 140 } 141 r.off += len(buf) 142 return r.lr.Read(buf) 143 } 144 145 func generateRandomData(l int) (r io.Reader, slice []byte) { 146 slice = make([]byte, l) 147 if _, err := rand.Read(slice); err != nil { 148 panic("rand error") 149 } 150 r = io.LimitReader(bytes.NewReader(slice), int64(l)) 151 return 152 } 153 154 func testStoreRandom(m ChunkStore, processors int, n int, chunksize int64, t *testing.T) { 155 hs := mputRandomChunks(m, processors, n, chunksize) 156 err := mget(m, hs, nil) 157 if err != nil { 158 t.Fatalf("testStore failed: %v", err) 159 } 160 } 161 162 func testStoreCorrect(m ChunkStore, processors int, n int, chunksize int64, t *testing.T) { 163 hs := mputRandomChunks(m, processors, n, chunksize) 164 f := func(h Address, chunk *Chunk) error { 165 if !bytes.Equal(h, chunk.Addr) { 166 return fmt.Errorf("key does not match retrieved chunk Key") 167 } 168 hasher := MakeHashFunc(DefaultHash)() 169 hasher.ResetWithLength(chunk.SData[:8]) 170 hasher.Write(chunk.SData[8:]) 171 exp := hasher.Sum(nil) 172 if !bytes.Equal(h, exp) { 173 return fmt.Errorf("key is not hash of chunk data") 174 } 175 return nil 176 } 177 err := mget(m, hs, f) 178 if err != nil { 179 t.Fatalf("testStore failed: %v", err) 180 } 181 } 182 183 func benchmarkStorePut(store ChunkStore, processors int, n int, chunksize int64, b *testing.B) { 184 chunks := make([]*Chunk, n) 185 i := 0 186 f := func(dataSize int64) *Chunk { 187 chunk := GenerateRandomChunk(dataSize) 188 chunks[i] = chunk 189 i++ 190 return chunk 191 } 192 193 mput(store, processors, n, f) 194 195 f = func(dataSize int64) *Chunk { 196 chunk := chunks[i] 197 i++ 198 return chunk 199 } 200 201 b.ReportAllocs() 202 b.ResetTimer() 203 204 for j := 0; j < b.N; j++ { 205 i = 0 206 mput(store, processors, n, f) 207 } 208 } 209 210 func benchmarkStoreGet(store ChunkStore, processors int, n int, chunksize int64, b *testing.B) { 211 hs := mputRandomChunks(store, processors, n, chunksize) 212 b.ReportAllocs() 213 b.ResetTimer() 214 for i := 0; i < b.N; i++ { 215 err := mget(store, hs, nil) 216 if err != nil { 217 b.Fatalf("mget failed: %v", err) 218 } 219 } 220 }