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