github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/storage/chunker_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 //</624450118346608640> 11 12 13 package storage 14 15 import ( 16 "bytes" 17 "context" 18 "encoding/binary" 19 "fmt" 20 "io" 21 "testing" 22 23 "github.com/ethereum/go-ethereum/swarm/testutil" 24 "golang.org/x/crypto/sha3" 25 ) 26 27 /* 28 通过拆分和连接随机字节片测试TreeChunker 29 **/ 30 31 32 type test interface { 33 Fatalf(string, ...interface{}) 34 Logf(string, ...interface{}) 35 } 36 37 type chunkerTester struct { 38 inputs map[uint64][]byte 39 t test 40 } 41 42 func newTestHasherStore(store ChunkStore, hash string) *hasherStore { 43 return NewHasherStore(store, MakeHashFunc(hash), false) 44 } 45 46 func testRandomBrokenData(n int, tester *chunkerTester) { 47 data := testutil.RandomReader(1, n) 48 brokendata := brokenLimitReader(data, n, n/2) 49 50 buf := make([]byte, n) 51 _, err := brokendata.Read(buf) 52 if err == nil || err.Error() != "Broken reader" { 53 tester.t.Fatalf("Broken reader is not broken, hence broken. Returns: %v", err) 54 } 55 56 data = testutil.RandomReader(2, n) 57 brokendata = brokenLimitReader(data, n, n/2) 58 59 putGetter := newTestHasherStore(NewMapChunkStore(), SHA3Hash) 60 61 expectedError := fmt.Errorf("Broken reader") 62 ctx := context.Background() 63 key, _, err := TreeSplit(ctx, brokendata, int64(n), putGetter) 64 if err == nil || err.Error() != expectedError.Error() { 65 tester.t.Fatalf("Not receiving the correct error! Expected %v, received %v", expectedError, err) 66 } 67 tester.t.Logf(" Address = %v\n", key) 68 } 69 70 func testRandomData(usePyramid bool, hash string, n int, tester *chunkerTester) Address { 71 if tester.inputs == nil { 72 tester.inputs = make(map[uint64][]byte) 73 } 74 input, found := tester.inputs[uint64(n)] 75 var data io.Reader 76 if !found { 77 input = testutil.RandomBytes(1, n) 78 data = bytes.NewReader(input) 79 tester.inputs[uint64(n)] = input 80 } else { 81 data = io.LimitReader(bytes.NewReader(input), int64(n)) 82 } 83 84 putGetter := newTestHasherStore(NewMapChunkStore(), hash) 85 86 var addr Address 87 var wait func(context.Context) error 88 var err error 89 ctx := context.TODO() 90 if usePyramid { 91 addr, wait, err = PyramidSplit(ctx, data, putGetter, putGetter) 92 } else { 93 addr, wait, err = TreeSplit(ctx, data, int64(n), putGetter) 94 } 95 if err != nil { 96 tester.t.Fatalf(err.Error()) 97 } 98 tester.t.Logf(" Address = %v\n", addr) 99 err = wait(ctx) 100 if err != nil { 101 tester.t.Fatalf(err.Error()) 102 } 103 104 reader := TreeJoin(ctx, addr, putGetter, 0) 105 output := make([]byte, n) 106 r, err := reader.Read(output) 107 if r != n || err != io.EOF { 108 tester.t.Fatalf("read error read: %v n = %v err = %v\n", r, n, err) 109 } 110 if input != nil { 111 if !bytes.Equal(output, input) { 112 tester.t.Fatalf("input and output mismatch\n IN: %v\nOUT: %v\n", input, output) 113 } 114 } 115 116 //测试部分读取 117 for i := 1; i < n; i += 10000 { 118 readableLength := n - i 119 r, err := reader.ReadAt(output, int64(i)) 120 if r != readableLength || err != io.EOF { 121 tester.t.Fatalf("readAt error with offset %v read: %v n = %v err = %v\n", i, r, readableLength, err) 122 } 123 if input != nil { 124 if !bytes.Equal(output[:readableLength], input[i:]) { 125 tester.t.Fatalf("input and output mismatch\n IN: %v\nOUT: %v\n", input[i:], output[:readableLength]) 126 } 127 } 128 } 129 130 return addr 131 } 132 133 func TestSha3ForCorrectness(t *testing.T) { 134 tester := &chunkerTester{t: t} 135 136 size := 4096 137 input := make([]byte, size+8) 138 binary.LittleEndian.PutUint64(input[:8], uint64(size)) 139 140 io.LimitReader(bytes.NewReader(input[8:]), int64(size)) 141 142 rawSha3 := sha3.NewLegacyKeccak256() 143 rawSha3.Reset() 144 rawSha3.Write(input) 145 rawSha3Output := rawSha3.Sum(nil) 146 147 sha3FromMakeFunc := MakeHashFunc(SHA3Hash)() 148 sha3FromMakeFunc.ResetWithLength(input[:8]) 149 sha3FromMakeFunc.Write(input[8:]) 150 sha3FromMakeFuncOutput := sha3FromMakeFunc.Sum(nil) 151 152 if len(rawSha3Output) != len(sha3FromMakeFuncOutput) { 153 tester.t.Fatalf("Original SHA3 and abstracted Sha3 has different length %v:%v\n", len(rawSha3Output), len(sha3FromMakeFuncOutput)) 154 } 155 156 if !bytes.Equal(rawSha3Output, sha3FromMakeFuncOutput) { 157 tester.t.Fatalf("Original SHA3 and abstracted Sha3 mismatch %v:%v\n", rawSha3Output, sha3FromMakeFuncOutput) 158 } 159 160 } 161 162 func TestDataAppend(t *testing.T) { 163 sizes := []int{1, 1, 1, 4095, 4096, 4097, 1, 1, 1, 123456, 2345678, 2345678} 164 appendSizes := []int{4095, 4096, 4097, 1, 1, 1, 8191, 8192, 8193, 9000, 3000, 5000} 165 166 tester := &chunkerTester{t: t} 167 for i := range sizes { 168 n := sizes[i] 169 m := appendSizes[i] 170 171 if tester.inputs == nil { 172 tester.inputs = make(map[uint64][]byte) 173 } 174 input, found := tester.inputs[uint64(n)] 175 var data io.Reader 176 if !found { 177 input = testutil.RandomBytes(i, n) 178 data = bytes.NewReader(input) 179 tester.inputs[uint64(n)] = input 180 } else { 181 data = io.LimitReader(bytes.NewReader(input), int64(n)) 182 } 183 184 store := NewMapChunkStore() 185 putGetter := newTestHasherStore(store, SHA3Hash) 186 187 ctx := context.TODO() 188 addr, wait, err := PyramidSplit(ctx, data, putGetter, putGetter) 189 if err != nil { 190 tester.t.Fatalf(err.Error()) 191 } 192 err = wait(ctx) 193 if err != nil { 194 tester.t.Fatalf(err.Error()) 195 } 196 //创建附加数据流 197 appendInput, found := tester.inputs[uint64(m)] 198 var appendData io.Reader 199 if !found { 200 appendInput = testutil.RandomBytes(i, m) 201 appendData = bytes.NewReader(appendInput) 202 tester.inputs[uint64(m)] = appendInput 203 } else { 204 appendData = io.LimitReader(bytes.NewReader(appendInput), int64(m)) 205 } 206 207 putGetter = newTestHasherStore(store, SHA3Hash) 208 newAddr, wait, err := PyramidAppend(ctx, addr, appendData, putGetter, putGetter) 209 if err != nil { 210 tester.t.Fatalf(err.Error()) 211 } 212 err = wait(ctx) 213 if err != nil { 214 tester.t.Fatalf(err.Error()) 215 } 216 217 reader := TreeJoin(ctx, newAddr, putGetter, 0) 218 newOutput := make([]byte, n+m) 219 r, err := reader.Read(newOutput) 220 if r != (n + m) { 221 tester.t.Fatalf("read error read: %v n = %v m = %v err = %v\n", r, n, m, err) 222 } 223 224 newInput := append(input, appendInput...) 225 if !bytes.Equal(newOutput, newInput) { 226 tester.t.Fatalf("input and output mismatch\n IN: %v\nOUT: %v\n", newInput, newOutput) 227 } 228 } 229 } 230 231 func TestRandomData(t *testing.T) { 232 //这个测试可以验证文件到一个相对较短的长度,因为树分块器会大大减慢速度。 233 //较长文件的验证由testlocalstore完成,并在swarm包中进行检索。 234 //尺寸:=[]int 1、60、83、179、253、1024、4095、4096、4097、8191、8192、8193、12287、12288、12289、524288、524288+1、524288+4097、7*524288、7*524288+1、7*524288+4097 235 sizes := []int{1, 60, 83, 179, 253, 1024, 4095, 4097, 8191, 8192, 12288, 12289, 524288} 236 tester := &chunkerTester{t: t} 237 238 for _, s := range sizes { 239 treeChunkerAddress := testRandomData(false, SHA3Hash, s, tester) 240 pyramidChunkerAddress := testRandomData(true, SHA3Hash, s, tester) 241 if treeChunkerAddress.String() != pyramidChunkerAddress.String() { 242 tester.t.Fatalf("tree chunker and pyramid chunker key mismatch for size %v\n TC: %v\n PC: %v\n", s, treeChunkerAddress.String(), pyramidChunkerAddress.String()) 243 } 244 } 245 246 for _, s := range sizes { 247 treeChunkerAddress := testRandomData(false, BMTHash, s, tester) 248 pyramidChunkerAddress := testRandomData(true, BMTHash, s, tester) 249 if treeChunkerAddress.String() != pyramidChunkerAddress.String() { 250 tester.t.Fatalf("tree chunker and pyramid chunker key mismatch for size %v\n TC: %v\n PC: %v\n", s, treeChunkerAddress.String(), pyramidChunkerAddress.String()) 251 } 252 } 253 } 254 255 func TestRandomBrokenData(t *testing.T) { 256 sizes := []int{1, 60, 83, 179, 253, 1024, 4095, 4096, 4097, 8191, 8192, 8193, 12287, 12288, 12289, 123456, 2345678} 257 tester := &chunkerTester{t: t} 258 for _, s := range sizes { 259 testRandomBrokenData(s, tester) 260 } 261 } 262 263 func benchReadAll(reader LazySectionReader) { 264 size, _ := reader.Size(context.TODO(), nil) 265 output := make([]byte, 1000) 266 for pos := int64(0); pos < size; pos += 1000 { 267 reader.ReadAt(output, pos) 268 } 269 } 270 271 func benchmarkSplitJoin(n int, t *testing.B) { 272 t.ReportAllocs() 273 for i := 0; i < t.N; i++ { 274 data := testutil.RandomReader(i, n) 275 276 putGetter := newTestHasherStore(NewMapChunkStore(), SHA3Hash) 277 ctx := context.TODO() 278 key, wait, err := PyramidSplit(ctx, data, putGetter, putGetter) 279 if err != nil { 280 t.Fatalf(err.Error()) 281 } 282 err = wait(ctx) 283 if err != nil { 284 t.Fatalf(err.Error()) 285 } 286 reader := TreeJoin(ctx, key, putGetter, 0) 287 benchReadAll(reader) 288 } 289 } 290 291 func benchmarkSplitTreeSHA3(n int, t *testing.B) { 292 t.ReportAllocs() 293 for i := 0; i < t.N; i++ { 294 data := testutil.RandomReader(i, n) 295 putGetter := newTestHasherStore(&FakeChunkStore{}, SHA3Hash) 296 297 ctx := context.Background() 298 _, wait, err := TreeSplit(ctx, data, int64(n), putGetter) 299 if err != nil { 300 t.Fatalf(err.Error()) 301 } 302 err = wait(ctx) 303 if err != nil { 304 t.Fatalf(err.Error()) 305 } 306 307 } 308 } 309 310 func benchmarkSplitTreeBMT(n int, t *testing.B) { 311 t.ReportAllocs() 312 for i := 0; i < t.N; i++ { 313 data := testutil.RandomReader(i, n) 314 putGetter := newTestHasherStore(&FakeChunkStore{}, BMTHash) 315 316 ctx := context.Background() 317 _, wait, err := TreeSplit(ctx, data, int64(n), putGetter) 318 if err != nil { 319 t.Fatalf(err.Error()) 320 } 321 err = wait(ctx) 322 if err != nil { 323 t.Fatalf(err.Error()) 324 } 325 } 326 } 327 328 func benchmarkSplitPyramidBMT(n int, t *testing.B) { 329 t.ReportAllocs() 330 for i := 0; i < t.N; i++ { 331 data := testutil.RandomReader(i, n) 332 putGetter := newTestHasherStore(&FakeChunkStore{}, BMTHash) 333 334 ctx := context.Background() 335 _, wait, err := PyramidSplit(ctx, data, putGetter, putGetter) 336 if err != nil { 337 t.Fatalf(err.Error()) 338 } 339 err = wait(ctx) 340 if err != nil { 341 t.Fatalf(err.Error()) 342 } 343 } 344 } 345 346 func benchmarkSplitPyramidSHA3(n int, t *testing.B) { 347 t.ReportAllocs() 348 for i := 0; i < t.N; i++ { 349 data := testutil.RandomReader(i, n) 350 putGetter := newTestHasherStore(&FakeChunkStore{}, SHA3Hash) 351 352 ctx := context.Background() 353 _, wait, err := PyramidSplit(ctx, data, putGetter, putGetter) 354 if err != nil { 355 t.Fatalf(err.Error()) 356 } 357 err = wait(ctx) 358 if err != nil { 359 t.Fatalf(err.Error()) 360 } 361 } 362 } 363 364 func benchmarkSplitAppendPyramid(n, m int, t *testing.B) { 365 t.ReportAllocs() 366 for i := 0; i < t.N; i++ { 367 data := testutil.RandomReader(i, n) 368 data1 := testutil.RandomReader(t.N+i, m) 369 370 store := NewMapChunkStore() 371 putGetter := newTestHasherStore(store, SHA3Hash) 372 373 ctx := context.Background() 374 key, wait, err := PyramidSplit(ctx, data, putGetter, putGetter) 375 if err != nil { 376 t.Fatalf(err.Error()) 377 } 378 err = wait(ctx) 379 if err != nil { 380 t.Fatalf(err.Error()) 381 } 382 383 putGetter = newTestHasherStore(store, SHA3Hash) 384 _, wait, err = PyramidAppend(ctx, key, data1, putGetter, putGetter) 385 if err != nil { 386 t.Fatalf(err.Error()) 387 } 388 err = wait(ctx) 389 if err != nil { 390 t.Fatalf(err.Error()) 391 } 392 } 393 } 394 395 func BenchmarkSplitJoin_2(t *testing.B) { benchmarkSplitJoin(100, t) } 396 func BenchmarkSplitJoin_3(t *testing.B) { benchmarkSplitJoin(1000, t) } 397 func BenchmarkSplitJoin_4(t *testing.B) { benchmarkSplitJoin(10000, t) } 398 func BenchmarkSplitJoin_5(t *testing.B) { benchmarkSplitJoin(100000, t) } 399 func BenchmarkSplitJoin_6(t *testing.B) { benchmarkSplitJoin(1000000, t) } 400 func BenchmarkSplitJoin_7(t *testing.B) { benchmarkSplitJoin(10000000, t) } 401 402 //Func BenchmarkSplitJoin_8(t*testing.b)BenchmarkJoin(100000000,t) 403 404 func BenchmarkSplitTreeSHA3_2(t *testing.B) { benchmarkSplitTreeSHA3(100, t) } 405 func BenchmarkSplitTreeSHA3_2h(t *testing.B) { benchmarkSplitTreeSHA3(500, t) } 406 func BenchmarkSplitTreeSHA3_3(t *testing.B) { benchmarkSplitTreeSHA3(1000, t) } 407 func BenchmarkSplitTreeSHA3_3h(t *testing.B) { benchmarkSplitTreeSHA3(5000, t) } 408 func BenchmarkSplitTreeSHA3_4(t *testing.B) { benchmarkSplitTreeSHA3(10000, t) } 409 func BenchmarkSplitTreeSHA3_4h(t *testing.B) { benchmarkSplitTreeSHA3(50000, t) } 410 func BenchmarkSplitTreeSHA3_5(t *testing.B) { benchmarkSplitTreeSHA3(100000, t) } 411 func BenchmarkSplitTreeSHA3_6(t *testing.B) { benchmarkSplitTreeSHA3(1000000, t) } 412 func BenchmarkSplitTreeSHA3_7(t *testing.B) { benchmarkSplitTreeSHA3(10000000, t) } 413 414 //func基准点拆分图3_8(t*testing.b)基准点拆分图3(100000000,t) 415 416 func BenchmarkSplitTreeBMT_2(t *testing.B) { benchmarkSplitTreeBMT(100, t) } 417 func BenchmarkSplitTreeBMT_2h(t *testing.B) { benchmarkSplitTreeBMT(500, t) } 418 func BenchmarkSplitTreeBMT_3(t *testing.B) { benchmarkSplitTreeBMT(1000, t) } 419 func BenchmarkSplitTreeBMT_3h(t *testing.B) { benchmarkSplitTreeBMT(5000, t) } 420 func BenchmarkSplitTreeBMT_4(t *testing.B) { benchmarkSplitTreeBMT(10000, t) } 421 func BenchmarkSplitTreeBMT_4h(t *testing.B) { benchmarkSplitTreeBMT(50000, t) } 422 func BenchmarkSplitTreeBMT_5(t *testing.B) { benchmarkSplitTreeBMT(100000, t) } 423 func BenchmarkSplitTreeBMT_6(t *testing.B) { benchmarkSplitTreeBMT(1000000, t) } 424 func BenchmarkSplitTreeBMT_7(t *testing.B) { benchmarkSplitTreeBMT(10000000, t) } 425 426 //func基准拆分树b t_8(t*testing.b)基准拆分树b t(100000000,t) 427 428 func BenchmarkSplitPyramidSHA3_2(t *testing.B) { benchmarkSplitPyramidSHA3(100, t) } 429 func BenchmarkSplitPyramidSHA3_2h(t *testing.B) { benchmarkSplitPyramidSHA3(500, t) } 430 func BenchmarkSplitPyramidSHA3_3(t *testing.B) { benchmarkSplitPyramidSHA3(1000, t) } 431 func BenchmarkSplitPyramidSHA3_3h(t *testing.B) { benchmarkSplitPyramidSHA3(5000, t) } 432 func BenchmarkSplitPyramidSHA3_4(t *testing.B) { benchmarkSplitPyramidSHA3(10000, t) } 433 func BenchmarkSplitPyramidSHA3_4h(t *testing.B) { benchmarkSplitPyramidSHA3(50000, t) } 434 func BenchmarkSplitPyramidSHA3_5(t *testing.B) { benchmarkSplitPyramidSHA3(100000, t) } 435 func BenchmarkSplitPyramidSHA3_6(t *testing.B) { benchmarkSplitPyramidSHA3(1000000, t) } 436 func BenchmarkSplitPyramidSHA3_7(t *testing.B) { benchmarkSplitPyramidSHA3(10000000, t) } 437 438 //func基准拆分金字塔3_8(t*testing.b)基准拆分金字塔3(100000000,t) 439 440 func BenchmarkSplitPyramidBMT_2(t *testing.B) { benchmarkSplitPyramidBMT(100, t) } 441 func BenchmarkSplitPyramidBMT_2h(t *testing.B) { benchmarkSplitPyramidBMT(500, t) } 442 func BenchmarkSplitPyramidBMT_3(t *testing.B) { benchmarkSplitPyramidBMT(1000, t) } 443 func BenchmarkSplitPyramidBMT_3h(t *testing.B) { benchmarkSplitPyramidBMT(5000, t) } 444 func BenchmarkSplitPyramidBMT_4(t *testing.B) { benchmarkSplitPyramidBMT(10000, t) } 445 func BenchmarkSplitPyramidBMT_4h(t *testing.B) { benchmarkSplitPyramidBMT(50000, t) } 446 func BenchmarkSplitPyramidBMT_5(t *testing.B) { benchmarkSplitPyramidBMT(100000, t) } 447 func BenchmarkSplitPyramidBMT_6(t *testing.B) { benchmarkSplitPyramidBMT(1000000, t) } 448 func BenchmarkSplitPyramidBMT_7(t *testing.B) { benchmarkSplitPyramidBMT(10000000, t) } 449 450 //func基准点拆分金字塔bmt_8(t*testing.b)基准点拆分金字塔bmt(100000000,t) 451 452 func BenchmarkSplitAppendPyramid_2(t *testing.B) { benchmarkSplitAppendPyramid(100, 1000, t) } 453 func BenchmarkSplitAppendPyramid_2h(t *testing.B) { benchmarkSplitAppendPyramid(500, 1000, t) } 454 func BenchmarkSplitAppendPyramid_3(t *testing.B) { benchmarkSplitAppendPyramid(1000, 1000, t) } 455 func BenchmarkSplitAppendPyramid_4(t *testing.B) { benchmarkSplitAppendPyramid(10000, 1000, t) } 456 func BenchmarkSplitAppendPyramid_4h(t *testing.B) { benchmarkSplitAppendPyramid(50000, 1000, t) } 457 func BenchmarkSplitAppendPyramid_5(t *testing.B) { benchmarkSplitAppendPyramid(1000000, 1000, t) } 458 func BenchmarkSplitAppendPyramid_6(t *testing.B) { benchmarkSplitAppendPyramid(1000000, 1000, t) } 459 func BenchmarkSplitAppendPyramid_7(t *testing.B) { benchmarkSplitAppendPyramid(10000000, 1000, t) } 460 461 //Func BenchmarkAppendPyramid_8(t*testing.b)BenchmarkAppendPyramid(100000000,1000,t) 462 463 //通过测试-超时20M-CPU 4-工作台=/Swarm/存储-运行编号 464 //如果不在上面添加超时参数..基准将超时并转储 465