swarm/storage: Remove races + >maxround test to uneven thrsld

This commit is contained in:
lash 2018-10-11 11:25:55 +02:00
parent 3592dfb9c6
commit 9edf35e76c
2 changed files with 24 additions and 16 deletions

View file

@ -322,13 +322,14 @@ func (s *LDBStore) collectGarbage() error {
s.gc.running = false s.gc.running = false
s.lock.Unlock() s.lock.Unlock()
}() }()
entryCnt := s.entryCnt
s.lock.Unlock() s.lock.Unlock()
metrics.GetOrRegisterCounter("ldbstore.collectgarbage", nil).Inc(1) metrics.GetOrRegisterCounter("ldbstore.collectgarbage", nil).Inc(1)
// calculate the amount of chunks to collect and reset counter // calculate the amount of chunks to collect and reset counter
s.startGC(int(s.entryCnt)) s.startGC(int(entryCnt))
log.Debug("collectGarbage", "target", s.gc.target, "entryCnt", s.entryCnt) log.Debug("collectGarbage", "target", s.gc.target, "entryCnt", entryCnt)
var totalDeleted int var totalDeleted int
for s.gc.count < s.gc.target { for s.gc.count < s.gc.target {

View file

@ -299,22 +299,29 @@ func TestLDBStoreWithoutCollectGarbage(t *testing.T) {
} }
} }
// TestLDBStoreCollectGarbage tests that we can put more chunks than LevelDB's capacity, and
// retrieve only some of them, because garbage collection must have partially cleared the store
// Also tests that we can delete chunks and that we can trigger garbage collection
func TestLDBStoreCollectGarbage(t *testing.T) { func TestLDBStoreCollectGarbage(t *testing.T) {
cap := defaultMaxGCRound / 2 var cap int
// below max ronud
cap = defaultMaxGCRound / 2
t.Run(fmt.Sprintf("A/%d/%d", cap, cap*4), testLDBStoreCollectGarbage) t.Run(fmt.Sprintf("A/%d/%d", cap, cap*4), testLDBStoreCollectGarbage)
t.Run(fmt.Sprintf("B/%d/%d", cap, cap*4), testLDBStoreRemoveThenCollectGarbage) t.Run(fmt.Sprintf("B/%d/%d", cap, cap*4), testLDBStoreRemoveThenCollectGarbage)
// at max round
cap = defaultMaxGCRound cap = defaultMaxGCRound
t.Run(fmt.Sprintf("A/%d/%d", cap, cap*4), testLDBStoreCollectGarbage) t.Run(fmt.Sprintf("A/%d/%d", cap, cap*4), testLDBStoreCollectGarbage)
t.Run(fmt.Sprintf("B/%d/%d", cap, cap*4), testLDBStoreRemoveThenCollectGarbage) t.Run(fmt.Sprintf("B/%d/%d", cap, cap*4), testLDBStoreRemoveThenCollectGarbage)
cap = defaultMaxGCRound * 2 // more than max around, not on threshold
cap = defaultMaxGCRound * 1.1
t.Run(fmt.Sprintf("A/%d/%d", cap, cap*4), testLDBStoreCollectGarbage) t.Run(fmt.Sprintf("A/%d/%d", cap, cap*4), testLDBStoreCollectGarbage)
t.Run(fmt.Sprintf("B/%d/%d", cap, cap*4), testLDBStoreRemoveThenCollectGarbage) t.Run(fmt.Sprintf("B/%d/%d", cap, cap*4), testLDBStoreRemoveThenCollectGarbage)
} }
// TestLDBStoreCollectGarbage tests that we can put more chunks than LevelDB's capacity, and
// retrieve only some of them, because garbage collection must have cleared some of them
func testLDBStoreCollectGarbage(t *testing.T) { func testLDBStoreCollectGarbage(t *testing.T) {
params := strings.Split(t.Name(), "/") params := strings.Split(t.Name(), "/")
capacity, err := strconv.Atoi(params[2]) capacity, err := strconv.Atoi(params[2])
@ -326,8 +333,6 @@ func testLDBStoreCollectGarbage(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
surplus := n - capacity
ldb, cleanup := newLDBStore(t) ldb, cleanup := newLDBStore(t)
ldb.setCapacity(uint64(capacity)) ldb.setCapacity(uint64(capacity))
defer cleanup() defer cleanup()
@ -379,8 +384,9 @@ func testLDBStoreCollectGarbage(t *testing.T) {
} }
// all surplus chunks should be missing // all surplus chunks should be missing
if missing != surplus+roundTarget { expectMissing := roundTarget + (((n - capacity) / roundTarget) * roundTarget)
t.Fatalf("gc failure: expected to miss %v chunks, but only %v are actually missing", surplus-roundTarget, missing) if missing != expectMissing {
t.Fatalf("gc failure: expected to miss %v chunks, but only %v are actually missing", expectMissing, missing)
} }
log.Info("ldbstore", "total", n, "missing", missing, "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt) log.Info("ldbstore", "total", n, "missing", missing, "entrycnt", ldb.entryCnt, "accesscnt", ldb.accessCnt)
@ -428,7 +434,6 @@ func TestLDBStoreAddRemove(t *testing.T) {
} }
} }
// TestLDBStoreRemoveThenCollectGarbage tests that we can delete chunks and that we can trigger garbage collection
func testLDBStoreRemoveThenCollectGarbage(t *testing.T) { func testLDBStoreRemoveThenCollectGarbage(t *testing.T) {
params := strings.Split(t.Name(), "/") params := strings.Split(t.Name(), "/")
@ -445,8 +450,6 @@ func testLDBStoreRemoveThenCollectGarbage(t *testing.T) {
defer cleanup() defer cleanup()
ldb.setCapacity(uint64(capacity)) ldb.setCapacity(uint64(capacity))
surplus := n - capacity
// put capacity count number of chunks // put capacity count number of chunks
chunks := make([]Chunk, n) chunks := make([]Chunk, n)
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
@ -514,7 +517,8 @@ func testLDBStoreRemoveThenCollectGarbage(t *testing.T) {
} }
// expect first surplus chunks to be missing, because they have the smallest access value // expect first surplus chunks to be missing, because they have the smallest access value
for i := 0; i < surplus+roundTarget; i++ { expectMissing := roundTarget + (((n - capacity) / roundTarget) * roundTarget)
for i := 0; i < expectMissing; i++ {
_, err := ldb.Get(context.TODO(), chunks[i].Address()) _, err := ldb.Get(context.TODO(), chunks[i].Address())
if err == nil { if err == nil {
t.Fatalf("expected surplus chunk %d to be missing, but got no error", i) t.Fatalf("expected surplus chunk %d to be missing, but got no error", i)
@ -522,7 +526,7 @@ func testLDBStoreRemoveThenCollectGarbage(t *testing.T) {
} }
// expect last chunks to be present, as they have the largest access value // expect last chunks to be present, as they have the largest access value
for i := surplus + roundTarget; i < n; i++ { for i := expectMissing; i < n; i++ {
ret, err := ldb.Get(context.TODO(), chunks[i].Address()) ret, err := ldb.Get(context.TODO(), chunks[i].Address())
if err != nil { if err != nil {
t.Fatalf("chunk %v: expected no error, but got %s", i, err) t.Fatalf("chunk %v: expected no error, but got %s", i, err)
@ -590,7 +594,10 @@ func waitGc(ctx context.Context, ldb *LDBStore) error {
case <-ctx.Done(): case <-ctx.Done():
return errors.New("timeout") return errors.New("timeout")
case <-ticker: case <-ticker:
if !ldb.gc.running { ldb.lock.Lock()
running := ldb.gc.running
ldb.lock.Unlock()
if !running {
return nil return nil
} }
} }