mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
swarm/storage/localhost: add DB.gcSize
This commit is contained in:
parent
6e8b2ad46e
commit
7b8510e977
3 changed files with 76 additions and 0 deletions
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue