mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-18 09:53:48 +00:00
swarm/storage: use two LRU caches for chunks containing data and requests
This commit is contained in:
parent
abbc732b05
commit
03412e0ea6
8 changed files with 82 additions and 18 deletions
|
|
@ -72,7 +72,7 @@ func NewLocalDPA(datadir string, basekey []byte) (*DPA, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewDPA(&LocalStore{
|
return NewDPA(&LocalStore{
|
||||||
memStore: NewMemStore(dbStore, singletonSwarmCacheCapacity),
|
memStore: NewMemStore(dbStore, singletonSwarmCacheCapacity, singletonSwarmDbCapacity),
|
||||||
DbStore: dbStore,
|
DbStore: dbStore,
|
||||||
}, NewDPAParams()), nil
|
}, NewDPAParams()), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ func testDpaRandom(toEncrypt bool, t *testing.T) {
|
||||||
defer tdb.close()
|
defer tdb.close()
|
||||||
db := tdb.LDBStore
|
db := tdb.LDBStore
|
||||||
db.setCapacity(50000)
|
db.setCapacity(50000)
|
||||||
memStore := NewMemStore(db, defaultCacheCapacity)
|
memStore := NewMemStore(db, defaultCacheCapacity, defaultCacheCapacity)
|
||||||
localStore := &LocalStore{
|
localStore := &LocalStore{
|
||||||
memStore: memStore,
|
memStore: memStore,
|
||||||
DbStore: db,
|
DbStore: db,
|
||||||
|
|
@ -68,7 +68,7 @@ func testDpaRandom(toEncrypt bool, t *testing.T) {
|
||||||
}
|
}
|
||||||
ioutil.WriteFile("/tmp/slice.bzz.16M", slice, 0666)
|
ioutil.WriteFile("/tmp/slice.bzz.16M", slice, 0666)
|
||||||
ioutil.WriteFile("/tmp/result.bzz.16M", resultSlice, 0666)
|
ioutil.WriteFile("/tmp/result.bzz.16M", resultSlice, 0666)
|
||||||
localStore.memStore = NewMemStore(db, defaultCacheCapacity)
|
localStore.memStore = NewMemStore(db, defaultCacheCapacity, defaultCacheCapacity)
|
||||||
resultReader = dpa.Retrieve(key)
|
resultReader = dpa.Retrieve(key)
|
||||||
for i := range resultSlice {
|
for i := range resultSlice {
|
||||||
resultSlice[i] = 0
|
resultSlice[i] = 0
|
||||||
|
|
@ -97,7 +97,7 @@ func testDPA_capacity(toEncrypt bool, t *testing.T) {
|
||||||
}
|
}
|
||||||
defer tdb.close()
|
defer tdb.close()
|
||||||
db := tdb.LDBStore
|
db := tdb.LDBStore
|
||||||
memStore := NewMemStore(db, 0)
|
memStore := NewMemStore(db, 0, 0)
|
||||||
localStore := &LocalStore{
|
localStore := &LocalStore{
|
||||||
memStore: memStore,
|
memStore: memStore,
|
||||||
DbStore: db,
|
DbStore: db,
|
||||||
|
|
|
||||||
|
|
@ -618,6 +618,10 @@ func (s *LDBStore) writeBatches() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(fmt.Sprintf("DbStore: spawn batch write (%d chunks): %v", b.Len(), err))
|
log.Error(fmt.Sprintf("DbStore: spawn batch write (%d chunks): %v", b.Len(), err))
|
||||||
}
|
}
|
||||||
|
if e >= s.capacity {
|
||||||
|
log.Trace(fmt.Sprintf("DbStore: collecting garbage...(%d chunks)", e))
|
||||||
|
s.collectGarbage(gcArrayFreeRatio)
|
||||||
|
}
|
||||||
close(c)
|
close(c)
|
||||||
}
|
}
|
||||||
log.Trace(fmt.Sprintf("DbStore: quit batch write loop"))
|
log.Trace(fmt.Sprintf("DbStore: quit batch write loop"))
|
||||||
|
|
@ -758,6 +762,9 @@ func (s *LDBStore) setCapacity(c uint64) {
|
||||||
if ratio > 1 {
|
if ratio > 1 {
|
||||||
ratio = 1
|
ratio = 1
|
||||||
}
|
}
|
||||||
|
for s.entryCnt > c {
|
||||||
|
s.collectGarbage(ratio)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ func NewLocalStore(hash SwarmHasher, params *StoreParams, basekey []byte, mockSt
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &LocalStore{
|
return &LocalStore{
|
||||||
memStore: NewMemStore(dbStore, params.CacheCapacity),
|
memStore: NewMemStore(dbStore, params.CacheCapacity, singletonSwarmDbCapacity),
|
||||||
DbStore: dbStore,
|
DbStore: dbStore,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +72,7 @@ func NewTestLocalStoreForAddr(path string, basekey []byte) (*LocalStore, error)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
localStore := &LocalStore{
|
localStore := &LocalStore{
|
||||||
memStore: NewMemStore(dbStore, singletonSwarmDbCapacity),
|
memStore: NewMemStore(dbStore, singletonSwarmDbCapacity, singletonSwarmDbCapacity),
|
||||||
DbStore: dbStore,
|
DbStore: dbStore,
|
||||||
}
|
}
|
||||||
return localStore, nil
|
return localStore, nil
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ package storage
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
)
|
)
|
||||||
|
|
@ -31,11 +32,13 @@ const (
|
||||||
|
|
||||||
type MemStore struct {
|
type MemStore struct {
|
||||||
cache *lru.Cache
|
cache *lru.Cache
|
||||||
|
requests *lru.Cache
|
||||||
|
mu sync.Mutex
|
||||||
disabled bool
|
disabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMemStore(_ *LDBStore, capacity uint) (m *MemStore) {
|
func NewMemStore(_ *LDBStore, cacheCapacity uint, requestsCapacity uint) (m *MemStore) {
|
||||||
if capacity == 0 {
|
if cacheCapacity == 0 {
|
||||||
return &MemStore{
|
return &MemStore{
|
||||||
disabled: true,
|
disabled: true,
|
||||||
}
|
}
|
||||||
|
|
@ -45,13 +48,19 @@ func NewMemStore(_ *LDBStore, capacity uint) (m *MemStore) {
|
||||||
v := value.(*Chunk)
|
v := value.(*Chunk)
|
||||||
<-v.dbStoredC
|
<-v.dbStoredC
|
||||||
}
|
}
|
||||||
c, err := lru.NewWithEvict(int(capacity), onEvicted)
|
c, err := lru.NewWithEvict(int(cacheCapacity), onEvicted)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := lru.New(int(requestsCapacity))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &MemStore{
|
return &MemStore{
|
||||||
cache: c,
|
cache: c,
|
||||||
|
requests: r,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,6 +69,16 @@ func (m *MemStore) Get(key Key) (*Chunk, error) {
|
||||||
return nil, ErrChunkNotFound
|
return nil, ErrChunkNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
r, ok := m.requests.Get(string(key))
|
||||||
|
// it is a request
|
||||||
|
if ok {
|
||||||
|
return r.(*Chunk), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// it is not a request
|
||||||
c, ok := m.cache.Get(string(key))
|
c, ok := m.cache.Get(string(key))
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrChunkNotFound
|
return nil, ErrChunkNotFound
|
||||||
|
|
@ -75,14 +94,37 @@ func (m *MemStore) Put(c *Chunk) {
|
||||||
if m.disabled {
|
if m.disabled {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
// it is a request
|
||||||
|
if c.ReqC != nil {
|
||||||
|
select {
|
||||||
|
case <-c.ReqC:
|
||||||
|
ok := c.GetErrored()
|
||||||
|
if !ok {
|
||||||
|
m.requests.Remove(string(c.Key))
|
||||||
|
return
|
||||||
|
}
|
||||||
m.cache.Add(string(c.Key), c)
|
m.cache.Add(string(c.Key), c)
|
||||||
|
m.requests.Remove(string(c.Key))
|
||||||
|
default:
|
||||||
|
m.requests.Add(string(c.Key), c)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// it is not a request
|
||||||
|
m.cache.Add(string(c.Key), c)
|
||||||
|
m.requests.Remove(string(c.Key))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MemStore) setCapacity(n int) {
|
func (m *MemStore) setCapacity(n int) {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
m.disabled = true
|
m.disabled = true
|
||||||
} else {
|
} else {
|
||||||
m = NewMemStore(nil, uint(n))
|
m = NewMemStore(nil, uint(n), singletonSwarmDbCapacity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,12 @@ func newLDBStore(t *testing.T) (*LDBStore, func()) {
|
||||||
|
|
||||||
func TestMemStoreAndLDBStore(t *testing.T) {
|
func TestMemStoreAndLDBStore(t *testing.T) {
|
||||||
ldb, cleanup := newLDBStore(t)
|
ldb, cleanup := newLDBStore(t)
|
||||||
ldb.setCapacity(50000)
|
ldb.setCapacity(4000)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
memStore := NewMemStore(ldb, defaultCacheCapacity)
|
cacheCap := 200
|
||||||
|
requestsCap := 10000
|
||||||
|
memStore := NewMemStore(ldb, uint(cacheCap), uint(requestsCap))
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
n int // number of chunks to push to memStore
|
n int // number of chunks to push to memStore
|
||||||
|
|
@ -73,15 +75,20 @@ func TestMemStoreAndLDBStore(t *testing.T) {
|
||||||
request: false,
|
request: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
n: 60001,
|
n: 501,
|
||||||
chunkSize: 4096,
|
chunkSize: 4096,
|
||||||
request: false,
|
request: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
n: 60001,
|
n: 15001,
|
||||||
chunkSize: 4096,
|
chunkSize: 4096,
|
||||||
request: true,
|
request: false,
|
||||||
},
|
},
|
||||||
|
//{
|
||||||
|
//n: 60001,
|
||||||
|
//chunkSize: 4096,
|
||||||
|
//request: true,
|
||||||
|
//},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
|
|
@ -102,6 +109,14 @@ func TestMemStoreAndLDBStore(t *testing.T) {
|
||||||
for i := 0; i < tt.n; i++ {
|
for i := 0; i < tt.n; i++ {
|
||||||
go ldb.Put(chunks[i])
|
go ldb.Put(chunks[i])
|
||||||
memStore.Put(chunks[i])
|
memStore.Put(chunks[i])
|
||||||
|
|
||||||
|
if got := memStore.cache.Len(); got > cacheCap {
|
||||||
|
t.Fatalf("expected to get cache capacity less than %v, but got %v", cacheCap, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := memStore.requests.Len(); got > requestsCap {
|
||||||
|
t.Fatalf("expected to get requests capacity less than %v, but got %v", requestsCap, got)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < tt.n; i++ {
|
for i := 0; i < tt.n; i++ {
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ package storage
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func newTestMemStore() *MemStore {
|
func newTestMemStore() *MemStore {
|
||||||
return NewMemStore(nil, defaultCacheCapacity)
|
return NewMemStore(nil, defaultCacheCapacity, singletonSwarmDbCapacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMemStoreRandom(n int, processors int, chunksize int, t *testing.T) {
|
func testMemStoreRandom(n int, processors int, chunksize int, t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -903,7 +903,7 @@ func NewTestResourceHandler(datadir string, ethClient headerGetter, validator Re
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
localStore := &LocalStore{
|
localStore := &LocalStore{
|
||||||
memStore: NewMemStore(dbStore, singletonSwarmDbCapacity),
|
memStore: NewMemStore(dbStore, singletonSwarmCacheCapacity, singletonSwarmDbCapacity),
|
||||||
DbStore: dbStore,
|
DbStore: dbStore,
|
||||||
}
|
}
|
||||||
resourceChunkStore := NewResourceChunkStore(localStore, nil)
|
resourceChunkStore := NewResourceChunkStore(localStore, nil)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue