github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/storage/ldbstore_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 //</624342681455169536> 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 "fmt" 34 "io/ioutil" 35 "os" 36 "sync" 37 "testing" 38 "time" 39 40 "github.com/ethereum/go-ethereum/common" 41 "github.com/ethereum/go-ethereum/swarm/chunk" 42 "github.com/ethereum/go-ethereum/swarm/log" 43 "github.com/ethereum/go-ethereum/swarm/storage/mock/mem" 44 45 ldberrors "github.com/syndtr/goleveldb/leveldb/errors" 46 ) 47 48 type testDbStore struct { 49 *LDBStore 50 dir string 51 } 52 53 func newTestDbStore(mock bool, trusted bool) (*testDbStore, func(), error) { 54 dir, err := ioutil.TempDir("", "bzz-storage-test") 55 if err != nil { 56 return nil, func() {}, err 57 } 58 59 var db *LDBStore 60 storeparams := NewDefaultStoreParams() 61 params := NewLDBStoreParams(storeparams, dir) 62 params.Po = testPoFunc 63 64 if mock { 65 globalStore := mem.NewGlobalStore() 66 addr := common.HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed") 67 mockStore := globalStore.NewNodeStore(addr) 68 69 db, err = NewMockDbStore(params, mockStore) 70 } else { 71 db, err = NewLDBStore(params) 72 } 73 74 cleanup := func() { 75 if db != nil { 76 db.Close() 77 } 78 err = os.RemoveAll(dir) 79 if err != nil { 80 panic(fmt.Sprintf("db cleanup failed: %v", err)) 81 } 82 } 83 84 return &testDbStore{db, dir}, cleanup, err 85 } 86 87 func testPoFunc(k Address) (ret uint8) { 88 basekey := make([]byte, 32) 89 return uint8(Proximity(basekey[:], k[:])) 90 } 91 92 func (db *testDbStore) close() { 93 db.Close() 94 err := os.RemoveAll(db.dir) 95 if err != nil { 96 panic(err) 97 } 98 } 99 100 func testDbStoreRandom(n int, processors int, chunksize int64, mock bool, t *testing.T) { 101 db, cleanup, err := newTestDbStore(mock, true) 102 defer cleanup() 103 if err != nil { 104 t.Fatalf("init dbStore failed: %v", err) 105 } 106 testStoreRandom(db, processors, n, chunksize, t) 107 } 108 109 func testDbStoreCorrect(n int, processors int, chunksize int64, mock bool, t *testing.T) { 110 db, cleanup, err := newTestDbStore(mock, false) 111 defer cleanup() 112 if err != nil { 113 t.Fatalf("init dbStore failed: %v", err) 114 } 115 testStoreCorrect(db, processors, n, chunksize, t) 116 } 117 118 func TestDbStoreRandom_1(t *testing.T) { 119 testDbStoreRandom(1, 1, 0, false, t) 120 } 121 122 func TestDbStoreCorrect_1(t *testing.T) { 123 testDbStoreCorrect(1, 1, 4096, false, t) 124 } 125 126 func TestDbStoreRandom_1_5k(t *testing.T) { 127 testDbStoreRandom(8, 5000, 0, false, t) 128 } 129 130 func TestDbStoreRandom_8_5k(t *testing.T) { 131 testDbStoreRandom(8, 5000, 0, false, t) 132 } 133 134 func TestDbStoreCorrect_1_5k(t *testing.T) { 135 testDbStoreCorrect(1, 5000, 4096, false, t) 136 } 137 138 func TestDbStoreCorrect_8_5k(t *testing.T) { 139 testDbStoreCorrect(8, 5000, 4096, false, t) 140 } 141 142 func TestMockDbStoreRandom_1(t *testing.T) { 143 testDbStoreRandom(1, 1, 0, true, t) 144 } 145 146 func TestMockDbStoreCorrect_1(t *testing.T) { 147 testDbStoreCorrect(1, 1, 4096, true, t) 148 } 149 150 func TestMockDbStoreRandom_1_5k(t *testing.T) { 151 testDbStoreRandom(8, 5000, 0, true, t) 152 } 153 154 func TestMockDbStoreRandom_8_5k(t *testing.T) { 155 testDbStoreRandom(8, 5000, 0, true, t) 156 } 157 158 func TestMockDbStoreCorrect_1_5k(t *testing.T) { 159 testDbStoreCorrect(1, 5000, 4096, true, t) 160 } 161 162 func TestMockDbStoreCorrect_8_5k(t *testing.T) { 163 testDbStoreCorrect(8, 5000, 4096, true, t) 164 } 165 166 func testDbStoreNotFound(t *testing.T, mock bool) { 167 db, cleanup, err := newTestDbStore(mock, false) 168 defer cleanup() 169 if err != nil { 170 t.Fatalf("init dbStore failed: %v", err) 171 } 172 173 _, err = db.Get(context.TODO(), ZeroAddr) 174 if err != ErrChunkNotFound { 175 t.Errorf("Expected ErrChunkNotFound, got %v", err) 176 } 177 } 178 179 func TestDbStoreNotFound(t *testing.T) { 180 testDbStoreNotFound(t, false) 181 } 182 func TestMockDbStoreNotFound(t *testing.T) { 183 testDbStoreNotFound(t, true) 184 } 185 186 func testIterator(t *testing.T, mock bool) { 187 var chunkcount int = 32 188 var i int 189 var poc uint 190 chunkkeys := NewAddressCollection(chunkcount) 191 chunkkeys_results := NewAddressCollection(chunkcount) 192 193 db, cleanup, err := newTestDbStore(mock, false) 194 defer cleanup() 195 if err != nil { 196 t.Fatalf("init dbStore failed: %v", err) 197 } 198 199 chunks := GenerateRandomChunks(chunk.DefaultSize, chunkcount) 200 201 wg := &sync.WaitGroup{} 202 wg.Add(len(chunks)) 203 for i = 0; i < len(chunks); i++ { 204 db.Put(context.TODO(), chunks[i]) 205 chunkkeys[i] = chunks[i].Addr 206 j := i 207 go func() { 208 defer wg.Done() 209 <-chunks[j].dbStoredC 210 }() 211 } 212 213 // 214 215 for i = 0; i < len(chunkkeys); i++ { 216 log.Trace(fmt.Sprintf("Chunk array pos %d/%d: '%v'", i, chunkcount, chunkkeys[i])) 217 } 218 wg.Wait() 219 i = 0 220 for poc = 0; poc <= 255; poc++ { 221 err := db.SyncIterator(0, uint64(chunkkeys.Len()), uint8(poc), func(k Address, n uint64) bool { 222 log.Trace(fmt.Sprintf("Got key %v number %d poc %d", k, n, uint8(poc))) 223 chunkkeys_results[n-1] = k 224 i++ 225 return true 226 }) 227 if err != nil { 228 t.Fatalf("Iterator call failed: %v", err) 229 } 230 } 231 232 for i = 0; i < chunkcount; i++ { 233 if !bytes.Equal(chunkkeys[i], chunkkeys_results[i]) { 234 t.Fatalf("Chunk put #%d key '%v' does not match iterator's key '%v'", i, chunkkeys[i], chunkkeys_results[i]) 235 } 236 } 237 238 } 239 240 func TestIterator(t *testing.T) { 241 testIterator(t, false) 242 } 243 func TestMockIterator(t *testing.T) { 244 testIterator(t, true) 245 } 246 247 func benchmarkDbStorePut(n int, processors int, chunksize int64, mock bool, b *testing.B) { 248 db, cleanup, err := newTestDbStore(mock, true) 249 defer cleanup() 250 if err != nil { 251 b.Fatalf("init dbStore failed: %v", err) 252 } 253 benchmarkStorePut(db, processors, n, chunksize, b) 254 } 255 256 func benchmarkDbStoreGet(n int, processors int, chunksize int64, mock bool, b *testing.B) { 257 db, cleanup, err := newTestDbStore(mock, true) 258 defer cleanup() 259 if err != nil { 260 b.Fatalf("init dbStore failed: %v", err) 261 } 262 benchmarkStoreGet(db, processors, n, chunksize, b) 263 } 264 265 func BenchmarkDbStorePut_1_500(b *testing.B) { 266 benchmarkDbStorePut(500, 1, 4096, false, b) 267 } 268 269 func BenchmarkDbStorePut_8_500(b *testing.B) { 270 benchmarkDbStorePut(500, 8, 4096, false, b) 271 } 272 273 func BenchmarkDbStoreGet_1_500(b *testing.B) { 274 benchmarkDbStoreGet(500, 1, 4096, false, b) 275 } 276 277 func BenchmarkDbStoreGet_8_500(b *testing.B) { 278 benchmarkDbStoreGet(500, 8, 4096, false, b) 279 } 280 281 func BenchmarkMockDbStorePut_1_500(b *testing.B) { 282 benchmarkDbStorePut(500, 1, 4096, true, b) 283 } 284 285 func BenchmarkMockDbStorePut_8_500(b *testing.B) { 286 benchmarkDbStorePut(500, 8, 4096, true, b) 287 } 288 289 func BenchmarkMockDbStoreGet_1_500(b *testing.B) { 290 benchmarkDbStoreGet(500, 1, 4096, true, b) 291 } 292 293 func BenchmarkMockDbStoreGet_8_500(b *testing.B) { 294 benchmarkDbStoreGet(500, 8, 4096, true, b) 295 } 296 297 // 298 // 299 func TestLDBStoreWithoutCollectGarbage(t *testing.T) { 300 capacity := 50 301 n := 10 302 303 ldb, cleanup := newLDBStore(t) 304 ldb.setCapacity(uint64(capacity)) 305 defer cleanup() 306 307 chunks := []*Chunk{} 308 for i := 0; i < n; i++ { 309 c := GenerateRandomChunk(chunk.DefaultSize) 310 chunks = append(chunks, c) 311 log.Trace("generate random chunk", "idx", i, "chunk", c) 312 } 313 314 for i := 0; i < n; i++ { 315 go ldb.Put(context.TODO(), chunks[i]) 316 } 317 318 // 319 for i := 0; i < n; i++ { 320 <-chunks[i].dbStoredC 321 } 322 323 log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) 324 325 for i := 0; i < n; i++ { 326 ret, err := ldb.Get(context.TODO(), chunks[i].Addr) 327 if err != nil { 328 t.Fatal(err) 329 } 330 331 if !bytes.Equal(ret.SData, chunks[i].SData) { 332 t.Fatal("expected to get the same data back, but got smth else") 333 } 334 335 log.Info("got back chunk", "chunk", ret) 336 } 337 338 if ldb.entryCnt != uint64(n+1) { 339 t.Fatalf("expected entryCnt to be equal to %v, but got %v", n+1, ldb.entryCnt) 340 } 341 342 if ldb.accessCnt != uint64(2*n+1) { 343 t.Fatalf("expected accessCnt to be equal to %v, but got %v", n+1, ldb.accessCnt) 344 } 345 } 346 347 // 348 // 349 func TestLDBStoreCollectGarbage(t *testing.T) { 350 capacity := 500 351 n := 2000 352 353 ldb, cleanup := newLDBStore(t) 354 ldb.setCapacity(uint64(capacity)) 355 defer cleanup() 356 357 chunks := []*Chunk{} 358 for i := 0; i < n; i++ { 359 c := GenerateRandomChunk(chunk.DefaultSize) 360 chunks = append(chunks, c) 361 log.Trace("generate random chunk", "idx", i, "chunk", c) 362 } 363 364 for i := 0; i < n; i++ { 365 ldb.Put(context.TODO(), chunks[i]) 366 } 367 368 // 369 for i := 0; i < n; i++ { 370 <-chunks[i].dbStoredC 371 } 372 373 log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) 374 375 // 376 time.Sleep(5 * time.Second) 377 378 var missing int 379 for i := 0; i < n; i++ { 380 ret, err := ldb.Get(context.TODO(), chunks[i].Addr) 381 if err == ErrChunkNotFound || err == ldberrors.ErrNotFound { 382 missing++ 383 continue 384 } 385 if err != nil { 386 t.Fatal(err) 387 } 388 389 if !bytes.Equal(ret.SData, chunks[i].SData) { 390 t.Fatal("expected to get the same data back, but got smth else") 391 } 392 393 log.Trace("got back chunk", "chunk", ret) 394 } 395 396 if missing < n-capacity { 397 t.Fatalf("gc failure: expected to miss %v chunks, but only %v are actually missing", n-capacity, missing) 398 } 399 400 log.Info("ldbstore", "total", n, "missing", missing, "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) 401 } 402 403 // 404 func TestLDBStoreAddRemove(t *testing.T) { 405 ldb, cleanup := newLDBStore(t) 406 ldb.setCapacity(200) 407 defer cleanup() 408 409 n := 100 410 411 chunks := []*Chunk{} 412 for i := 0; i < n; i++ { 413 c := GenerateRandomChunk(chunk.DefaultSize) 414 chunks = append(chunks, c) 415 log.Trace("generate random chunk", "idx", i, "chunk", c) 416 } 417 418 for i := 0; i < n; i++ { 419 go ldb.Put(context.TODO(), chunks[i]) 420 } 421 422 // 423 for i := 0; i < n; i++ { 424 <-chunks[i].dbStoredC 425 } 426 427 for i := 0; i < n; i++ { 428 // 429 if i%2 == 0 { 430 431 key := chunks[i].Addr 432 ikey := getIndexKey(key) 433 434 var indx dpaDBIndex 435 ldb.tryAccessIdx(ikey, &indx) 436 437 ldb.delete(indx.Idx, ikey, ldb.po(key)) 438 } 439 } 440 441 log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) 442 443 for i := 0; i < n; i++ { 444 ret, err := ldb.Get(context.TODO(), chunks[i].Addr) 445 446 if i%2 == 0 { 447 // 448 if err == nil || ret != nil { 449 t.Fatal("expected chunk to be missing, but got no error") 450 } 451 } else { 452 // 453 if err != nil { 454 t.Fatalf("expected no error, but got %s", err) 455 } 456 457 if !bytes.Equal(ret.SData, chunks[i].SData) { 458 t.Fatal("expected to get the same data back, but got smth else") 459 } 460 } 461 } 462 } 463 464 // 465 func TestLDBStoreRemoveThenCollectGarbage(t *testing.T) { 466 capacity := 10 467 468 ldb, cleanup := newLDBStore(t) 469 ldb.setCapacity(uint64(capacity)) 470 471 n := 7 472 473 chunks := []*Chunk{} 474 for i := 0; i < capacity; i++ { 475 c := GenerateRandomChunk(chunk.DefaultSize) 476 chunks = append(chunks, c) 477 log.Trace("generate random chunk", "idx", i, "chunk", c) 478 } 479 480 for i := 0; i < n; i++ { 481 ldb.Put(context.TODO(), chunks[i]) 482 } 483 484 // 485 for i := 0; i < n; i++ { 486 <-chunks[i].dbStoredC 487 } 488 489 // 490 for i := 0; i < n; i++ { 491 key := chunks[i].Addr 492 ikey := getIndexKey(key) 493 494 var indx dpaDBIndex 495 ldb.tryAccessIdx(ikey, &indx) 496 497 ldb.delete(indx.Idx, ikey, ldb.po(key)) 498 } 499 500 log.Info("ldbstore", "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) 501 502 cleanup() 503 504 ldb, cleanup = newLDBStore(t) 505 ldb.setCapacity(uint64(capacity)) 506 507 n = 10 508 509 for i := 0; i < n; i++ { 510 ldb.Put(context.TODO(), chunks[i]) 511 } 512 513 // 514 for i := 0; i < n; i++ { 515 <-chunks[i].dbStoredC 516 } 517 518 // 519 idx := 0 520 ret, err := ldb.Get(context.TODO(), chunks[idx].Addr) 521 if err == nil || ret != nil { 522 t.Fatal("expected first chunk to be missing, but got no error") 523 } 524 525 // 526 idx = 9 527 ret, err = ldb.Get(context.TODO(), chunks[idx].Addr) 528 if err != nil { 529 t.Fatalf("expected no error, but got %s", err) 530 } 531 532 if !bytes.Equal(ret.SData, chunks[idx].SData) { 533 t.Fatal("expected to get the same data back, but got smth else") 534 } 535 } 536