github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:44</date> 10 //</624450118405328896> 11 12 13 package storage 14 15 import ( 16 "bytes" 17 "context" 18 "flag" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "os" 23 "sync" 24 "testing" 25 "time" 26 27 "github.com/ethereum/go-ethereum/log" 28 ch "github.com/ethereum/go-ethereum/swarm/chunk" 29 "github.com/mattn/go-colorable" 30 ) 31 32 var ( 33 loglevel = flag.Int("loglevel", 3, "verbosity of logs") 34 getTimeout = 30 * time.Second 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 newLDBStore(t *testing.T) (*LDBStore, func()) { 59 dir, err := ioutil.TempDir("", "bzz-storage-test") 60 if err != nil { 61 t.Fatal(err) 62 } 63 log.Trace("memstore.tempdir", "dir", dir) 64 65 ldbparams := NewLDBStoreParams(NewDefaultStoreParams(), dir) 66 db, err := NewLDBStore(ldbparams) 67 if err != nil { 68 t.Fatal(err) 69 } 70 71 cleanup := func() { 72 db.Close() 73 err := os.RemoveAll(dir) 74 if err != nil { 75 t.Fatal(err) 76 } 77 } 78 79 return db, cleanup 80 } 81 82 func mputRandomChunks(store ChunkStore, n int, chunksize int64) ([]Chunk, error) { 83 return mput(store, n, GenerateRandomChunk) 84 } 85 86 func mput(store ChunkStore, n int, f func(i int64) Chunk) (hs []Chunk, err error) { 87 //放入本地存储并等待存储的通道 88 //不检查传递错误状态 89 errc := make(chan error) 90 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 91 defer cancel() 92 for i := int64(0); i < int64(n); i++ { 93 chunk := f(ch.DefaultSize) 94 go func() { 95 select { 96 case errc <- store.Put(ctx, chunk): 97 case <-ctx.Done(): 98 } 99 }() 100 hs = append(hs, chunk) 101 } 102 103 //等待存储所有块 104 for i := 0; i < n; i++ { 105 err := <-errc 106 if err != nil { 107 return nil, err 108 } 109 } 110 return hs, nil 111 } 112 113 func mget(store ChunkStore, hs []Address, f func(h Address, chunk Chunk) error) error { 114 wg := sync.WaitGroup{} 115 wg.Add(len(hs)) 116 errc := make(chan error) 117 118 for _, k := range hs { 119 go func(h Address) { 120 defer wg.Done() 121 //TODO:使用上下文写入超时 122 chunk, err := store.Get(context.TODO(), h) 123 if err != nil { 124 errc <- err 125 return 126 } 127 if f != nil { 128 err = f(h, chunk) 129 if err != nil { 130 errc <- err 131 return 132 } 133 } 134 }(k) 135 } 136 go func() { 137 wg.Wait() 138 close(errc) 139 }() 140 var err error 141 select { 142 case err = <-errc: 143 case <-time.NewTimer(5 * time.Second).C: 144 err = fmt.Errorf("timed out after 5 seconds") 145 } 146 return err 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 testStoreRandom(m ChunkStore, n int, chunksize int64, t *testing.T) { 158 chunks, err := mputRandomChunks(m, n, chunksize) 159 if err != nil { 160 t.Fatalf("expected no error, got %v", err) 161 } 162 err = mget(m, chunkAddresses(chunks), nil) 163 if err != nil { 164 t.Fatalf("testStore failed: %v", err) 165 } 166 } 167 168 func testStoreCorrect(m ChunkStore, n int, chunksize int64, t *testing.T) { 169 chunks, err := mputRandomChunks(m, n, chunksize) 170 if err != nil { 171 t.Fatalf("expected no error, got %v", err) 172 } 173 f := func(h Address, chunk Chunk) error { 174 if !bytes.Equal(h, chunk.Address()) { 175 return fmt.Errorf("key does not match retrieved chunk Address") 176 } 177 hasher := MakeHashFunc(DefaultHash)() 178 data := chunk.Data() 179 hasher.ResetWithLength(data[:8]) 180 hasher.Write(data[8:]) 181 exp := hasher.Sum(nil) 182 if !bytes.Equal(h, exp) { 183 return fmt.Errorf("key is not hash of chunk data") 184 } 185 return nil 186 } 187 err = mget(m, chunkAddresses(chunks), f) 188 if err != nil { 189 t.Fatalf("testStore failed: %v", err) 190 } 191 } 192 193 func benchmarkStorePut(store ChunkStore, n int, chunksize int64, b *testing.B) { 194 chunks := make([]Chunk, n) 195 i := 0 196 f := func(dataSize int64) Chunk { 197 chunk := GenerateRandomChunk(dataSize) 198 chunks[i] = chunk 199 i++ 200 return chunk 201 } 202 203 mput(store, n, f) 204 205 f = func(dataSize int64) Chunk { 206 chunk := chunks[i] 207 i++ 208 return chunk 209 } 210 211 b.ReportAllocs() 212 b.ResetTimer() 213 214 for j := 0; j < b.N; j++ { 215 i = 0 216 mput(store, n, f) 217 } 218 } 219 220 func benchmarkStoreGet(store ChunkStore, n int, chunksize int64, b *testing.B) { 221 chunks, err := mputRandomChunks(store, n, chunksize) 222 if err != nil { 223 b.Fatalf("expected no error, got %v", err) 224 } 225 b.ReportAllocs() 226 b.ResetTimer() 227 addrs := chunkAddresses(chunks) 228 for i := 0; i < b.N; i++ { 229 err := mget(store, addrs, nil) 230 if err != nil { 231 b.Fatalf("mget failed: %v", err) 232 } 233 } 234 } 235 236 //map chunkstore是一个非常简单的chunkstore实现,用于将块存储在内存中的映射中。 237 type MapChunkStore struct { 238 chunks map[string]Chunk 239 mu sync.RWMutex 240 } 241 242 func NewMapChunkStore() *MapChunkStore { 243 return &MapChunkStore{ 244 chunks: make(map[string]Chunk), 245 } 246 } 247 248 func (m *MapChunkStore) Put(_ context.Context, ch Chunk) error { 249 m.mu.Lock() 250 defer m.mu.Unlock() 251 m.chunks[ch.Address().Hex()] = ch 252 return nil 253 } 254 255 func (m *MapChunkStore) Get(_ context.Context, ref Address) (Chunk, error) { 256 m.mu.RLock() 257 defer m.mu.RUnlock() 258 chunk := m.chunks[ref.Hex()] 259 if chunk == nil { 260 return nil, ErrChunkNotFound 261 } 262 return chunk, nil 263 } 264 265 func (m *MapChunkStore) Close() { 266 } 267 268 func chunkAddresses(chunks []Chunk) []Address { 269 addrs := make([]Address, len(chunks)) 270 for i, ch := range chunks { 271 addrs[i] = ch.Address() 272 } 273 return addrs 274 } 275