swarm/storage/localhost: add DB.gcSize

This commit is contained in:
Janos Guljas 2018-12-06 14:09:42 +01:00
parent 6e8b2ad46e
commit 7b8510e977
3 changed files with 76 additions and 0 deletions

View file

@ -20,6 +20,7 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/swarm/shed" "github.com/ethereum/go-ethereum/swarm/shed"
@ -63,6 +64,9 @@ type DB struct {
// garbage collection index // garbage collection index
gcIndex shed.Index gcIndex shed.Index
// number of elements in garbage collection index
gcSize int64
baseKey []byte baseKey []byte
updateLocks sync.Map updateLocks sync.Map
@ -288,6 +292,13 @@ func New(path string, baseKey []byte, o *Options) (db *DB, err error) {
return e, nil return e, nil
}, },
}) })
// count number of elements in garbage collection index
var gcSize int64
db.gcIndex.IterateAll(func(_ shed.IndexItem) (stop bool, err error) {
gcSize++
return false, nil
})
atomic.AddInt64(&db.gcSize, gcSize)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -18,6 +18,7 @@ package localstore
import ( import (
"encoding/hex" "encoding/hex"
"sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/swarm/shed" "github.com/ethereum/go-ethereum/swarm/shed"
@ -169,6 +170,11 @@ func (db *DB) update(mode Mode, item shed.IndexItem) (err error) {
// set access time for gc index // set access time for gc index
item.AccessTimestamp = now() item.AccessTimestamp = now()
db.retrievalCompositeIndex.PutInBatch(batch, item) db.retrievalCompositeIndex.PutInBatch(batch, item)
} else {
// the chunk is accessed before
// remove the current gc index item
db.gcIndex.DeleteInBatch(batch, item)
atomic.AddInt64(&db.gcSize, -1)
} }
} else { } else {
i, err := db.retrievalDataIndex.Get(item) i, err := db.retrievalDataIndex.Get(item)
@ -190,6 +196,7 @@ func (db *DB) update(mode Mode, item shed.IndexItem) (err error) {
case nil: case nil:
item.AccessTimestamp = i.AccessTimestamp item.AccessTimestamp = i.AccessTimestamp
db.gcIndex.DeleteInBatch(batch, item) db.gcIndex.DeleteInBatch(batch, item)
atomic.AddInt64(&db.gcSize, -1)
case leveldb.ErrNotFound: case leveldb.ErrNotFound:
// the chunk is not accessed before // the chunk is not accessed before
default: default:
@ -200,6 +207,7 @@ func (db *DB) update(mode Mode, item shed.IndexItem) (err error) {
} }
db.pushIndex.DeleteInBatch(batch, item) db.pushIndex.DeleteInBatch(batch, item)
db.gcIndex.PutInBatch(batch, item) db.gcIndex.PutInBatch(batch, item)
atomic.AddInt64(&db.gcSize, 1)
case modeAccess: case modeAccess:
// putting a chunk on mode access does not do anything // putting a chunk on mode access does not do anything
@ -241,6 +249,11 @@ func (db *DB) update(mode Mode, item shed.IndexItem) (err error) {
} }
db.pullIndex.DeleteInBatch(batch, item) db.pullIndex.DeleteInBatch(batch, item)
db.gcIndex.DeleteInBatch(batch, item) db.gcIndex.DeleteInBatch(batch, item)
// TODO: optimize in garbage collection
// get is too expensive operation
if _, err := db.gcIndex.Get(item); err == nil {
atomic.AddInt64(&db.gcSize, -1)
}
default: default:
return ErrInvalidMode return ErrInvalidMode

View file

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"math/rand" "math/rand"
"sort" "sort"
"sync/atomic"
"testing" "testing"
"time" "time"
@ -170,6 +171,8 @@ func testModeRequestValues(t *testing.T, db *DB) {
t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, uploadTimestamp, 0)) t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, uploadTimestamp, 0))
t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 0)) t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 0))
t.Run("gc size", newIndexGCSizeTest(db))
}) })
// set chunk to synced state // set chunk to synced state
@ -197,6 +200,8 @@ func testModeRequestValues(t *testing.T, db *DB) {
t.Run("gc index", newGCIndexTest(db, chunk, uploadTimestamp, uploadTimestamp)) t.Run("gc index", newGCIndexTest(db, chunk, uploadTimestamp, uploadTimestamp))
t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 1)) t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 1))
t.Run("gc size", newIndexGCSizeTest(db))
}) })
t.Run("second get", func(t *testing.T) { t.Run("second get", func(t *testing.T) {
@ -223,6 +228,8 @@ func testModeRequestValues(t *testing.T, db *DB) {
t.Run("gc index", newGCIndexTest(db, chunk, uploadTimestamp, accessTimestamp)) t.Run("gc index", newGCIndexTest(db, chunk, uploadTimestamp, accessTimestamp))
t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 1)) t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 1))
t.Run("gc size", newIndexGCSizeTest(db))
}) })
} }
@ -274,6 +281,10 @@ func testModeSyncedValues(t *testing.T, db *DB) {
t.Run("push index", newPushIndexTest(db, chunk, wantTimestamp, leveldb.ErrNotFound)) t.Run("push index", newPushIndexTest(db, chunk, wantTimestamp, leveldb.ErrNotFound))
t.Run("gc index", newGCIndexTest(db, chunk, wantTimestamp, wantTimestamp)) t.Run("gc index", newGCIndexTest(db, chunk, wantTimestamp, wantTimestamp))
t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 1))
t.Run("gc size", newIndexGCSizeTest(db))
} }
// TestModeAccess validates internal data operations and state // TestModeAccess validates internal data operations and state
@ -331,6 +342,8 @@ func testModeAccessValues(t *testing.T, db *DB) {
t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, uploadTimestamp, 0)) t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, uploadTimestamp, 0))
t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 0)) t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 0))
t.Run("gc size", newIndexGCSizeTest(db))
}) })
// set chunk to synced state // set chunk to synced state
@ -358,6 +371,8 @@ func testModeAccessValues(t *testing.T, db *DB) {
t.Run("gc index", newGCIndexTest(db, chunk, uploadTimestamp, uploadTimestamp)) t.Run("gc index", newGCIndexTest(db, chunk, uploadTimestamp, uploadTimestamp))
t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 1)) t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 1))
t.Run("gc size", newIndexGCSizeTest(db))
}) })
t.Run("second get", func(t *testing.T) { t.Run("second get", func(t *testing.T) {
@ -384,6 +399,8 @@ func testModeAccessValues(t *testing.T, db *DB) {
t.Run("gc index", newGCIndexTest(db, chunk, uploadTimestamp, accessTimestamp)) t.Run("gc index", newGCIndexTest(db, chunk, uploadTimestamp, accessTimestamp))
t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 1)) t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 1))
t.Run("gc size", newIndexGCSizeTest(db))
}) })
} }
@ -453,6 +470,9 @@ func testModeRemovalValues(t *testing.T, db *DB) {
t.Run("pull index count", newIndexItemsCountTest(db.pullIndex, 0)) t.Run("pull index count", newIndexItemsCountTest(db.pullIndex, 0))
t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 0)) t.Run("gc index count", newIndexItemsCountTest(db.gcIndex, 0))
t.Run("gc size", newIndexGCSizeTest(db))
} }
// TestDB_pullIndex validates the ordering of keys in pull index. // TestDB_pullIndex validates the ordering of keys in pull index.
@ -568,6 +588,8 @@ func testDB_gcIndex(t *testing.T, db *DB) {
// the chunk is not synced // the chunk is not synced
// should not be in the garbace collection index // should not be in the garbace collection index
newIndexItemsCountTest(db.gcIndex, 0)(t) newIndexItemsCountTest(db.gcIndex, 0)(t)
newIndexGCSizeTest(db)(t)
}) })
t.Run("request unsynced", func(t *testing.T) { t.Run("request unsynced", func(t *testing.T) {
@ -583,6 +605,8 @@ func testDB_gcIndex(t *testing.T, db *DB) {
// the chunk is not synced // the chunk is not synced
// should not be in the garbace collection index // should not be in the garbace collection index
newIndexItemsCountTest(db.gcIndex, 0)(t) newIndexItemsCountTest(db.gcIndex, 0)(t)
newIndexGCSizeTest(db)(t)
}) })
t.Run("sync one chunk", func(t *testing.T) { t.Run("sync one chunk", func(t *testing.T) {
@ -597,6 +621,8 @@ func testDB_gcIndex(t *testing.T, db *DB) {
// the chunk is synced and should be in gc index // the chunk is synced and should be in gc index
newIndexItemsCountTest(db.gcIndex, 1)(t) newIndexItemsCountTest(db.gcIndex, 1)(t)
newIndexGCSizeTest(db)(t)
}) })
t.Run("sync all chunks", func(t *testing.T) { t.Run("sync all chunks", func(t *testing.T) {
@ -610,6 +636,8 @@ func testDB_gcIndex(t *testing.T, db *DB) {
} }
testIndexItemsOrder(t, db.gcIndex, chunks, nil) testIndexItemsOrder(t, db.gcIndex, chunks, nil)
newIndexGCSizeTest(db)(t)
}) })
t.Run("access one chunk", func(t *testing.T) { t.Run("access one chunk", func(t *testing.T) {
@ -628,6 +656,8 @@ func testDB_gcIndex(t *testing.T, db *DB) {
chunks = append(chunks, c) chunks = append(chunks, c)
testIndexItemsOrder(t, db.gcIndex, chunks, nil) testIndexItemsOrder(t, db.gcIndex, chunks, nil)
newIndexGCSizeTest(db)(t)
}) })
t.Run("request one chunk", func(t *testing.T) { t.Run("request one chunk", func(t *testing.T) {
@ -646,6 +676,8 @@ func testDB_gcIndex(t *testing.T, db *DB) {
chunks = append(chunks, c) chunks = append(chunks, c)
testIndexItemsOrder(t, db.gcIndex, chunks, nil) testIndexItemsOrder(t, db.gcIndex, chunks, nil)
newIndexGCSizeTest(db)(t)
}) })
t.Run("random chunk access", func(t *testing.T) { t.Run("random chunk access", func(t *testing.T) {
@ -663,6 +695,8 @@ func testDB_gcIndex(t *testing.T, db *DB) {
} }
testIndexItemsOrder(t, db.gcIndex, chunks, nil) testIndexItemsOrder(t, db.gcIndex, chunks, nil)
newIndexGCSizeTest(db)(t)
}) })
t.Run("random chunk request", func(t *testing.T) { t.Run("random chunk request", func(t *testing.T) {
@ -680,6 +714,8 @@ func testDB_gcIndex(t *testing.T, db *DB) {
} }
testIndexItemsOrder(t, db.gcIndex, chunks, nil) testIndexItemsOrder(t, db.gcIndex, chunks, nil)
newIndexGCSizeTest(db)(t)
}) })
t.Run("remove one chunk", func(t *testing.T) { t.Run("remove one chunk", func(t *testing.T) {
@ -696,6 +732,8 @@ func testDB_gcIndex(t *testing.T, db *DB) {
chunks = append(chunks[:i], chunks[i+1:]...) chunks = append(chunks[:i], chunks[i+1:]...)
testIndexItemsOrder(t, db.gcIndex, chunks, nil) testIndexItemsOrder(t, db.gcIndex, chunks, nil)
newIndexGCSizeTest(db)(t)
}) })
} }
@ -819,6 +857,20 @@ func newIndexItemsCountTest(i shed.Index, want int) func(t *testing.T) {
} }
} }
func newIndexGCSizeTest(db *DB) func(t *testing.T) {
return func(t *testing.T) {
var want int64
db.gcIndex.IterateAll(func(item shed.IndexItem) (stop bool, err error) {
want++
return
})
got := atomic.LoadInt64(&db.gcSize)
if got != want {
t.Errorf("got gc size %v, want %v", got, want)
}
}
}
type testIndexChunk struct { type testIndexChunk struct {
storage.Chunk storage.Chunk
storeTimestamp int64 storeTimestamp int64