mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-25 06:06:44 +00:00
swarm/storage: fix process leak in dpa
This commit is contained in:
parent
801e57f14f
commit
5097da7704
5 changed files with 47 additions and 37 deletions
|
|
@ -48,7 +48,7 @@ func (self *Api) Retrieve(key storage.Key) storage.LazySectionReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Api) Store(data io.Reader, size int64, wg *sync.WaitGroup) (key storage.Key, err error) {
|
func (self *Api) Store(data io.Reader, size int64, wg *sync.WaitGroup) (key storage.Key, err error) {
|
||||||
return self.dpa.Store(data, size, wg)
|
return self.dpa.Store(data, size, wg, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ErrResolve error
|
type ErrResolve error
|
||||||
|
|
@ -107,13 +107,13 @@ func (self *Api) parseAndResolve(uri string, nameresolver bool) (contentHash sto
|
||||||
func (self *Api) Put(content, contentType string) (string, error) {
|
func (self *Api) Put(content, contentType string) (string, error) {
|
||||||
r := strings.NewReader(content)
|
r := strings.NewReader(content)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
key, err := self.dpa.Store(r, int64(len(content)), wg)
|
key, err := self.dpa.Store(r, int64(len(content)), wg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType)
|
manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType)
|
||||||
r = strings.NewReader(manifest)
|
r = strings.NewReader(manifest)
|
||||||
key, err = self.dpa.Store(r, int64(len(manifest)), wg)
|
key, err = self.dpa.Store(r, int64(len(manifest)), wg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ func (self *FileSystem) Upload(lpath, index string) (string, error) {
|
||||||
stat, _ := f.Stat()
|
stat, _ := f.Stat()
|
||||||
var hash storage.Key
|
var hash storage.Key
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
hash, err = self.api.dpa.Store(f, stat.Size(), wg)
|
hash, err = self.api.dpa.Store(f, stat.Size(), wg, nil)
|
||||||
if hash != nil {
|
if hash != nil {
|
||||||
list[i].Hash = hash.String()
|
list[i].Hash = hash.String()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,7 @@ func (self *manifestTrie) recalcAndStore() error {
|
||||||
|
|
||||||
sr := bytes.NewReader(manifest)
|
sr := bytes.NewReader(manifest)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
key, err2 := self.dpa.Store(sr, int64(len(manifest)), wg)
|
key, err2 := self.dpa.Store(sr, int64(len(manifest)), wg, nil)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
self.hash = key
|
self.hash = key
|
||||||
return err2
|
return err2
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ const (
|
||||||
retrieveChanCapacity = 100
|
retrieveChanCapacity = 100
|
||||||
singletonSwarmDbCapacity = 50000
|
singletonSwarmDbCapacity = 50000
|
||||||
singletonSwarmCacheCapacity = 500
|
singletonSwarmCacheCapacity = 500
|
||||||
|
maxStoreProcesses = 100
|
||||||
|
maxRetrieveProcesses = 100
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -42,7 +44,7 @@ type DPA struct {
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
running bool
|
running bool
|
||||||
wg *sync.WaitGroup
|
wg *sync.WaitGroup
|
||||||
quitC chan bool
|
quitC chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// for testing locally
|
// for testing locally
|
||||||
|
|
@ -79,8 +81,8 @@ func (self *DPA) Retrieve(key Key) LazySectionReader {
|
||||||
|
|
||||||
// Public API. Main entry point for document storage directly. Used by the
|
// Public API. Main entry point for document storage directly. Used by the
|
||||||
// FS-aware API and httpaccess
|
// FS-aware API and httpaccess
|
||||||
func (self *DPA) Store(data io.Reader, size int64, wg *sync.WaitGroup) (key Key, err error) {
|
func (self *DPA) Store(data io.Reader, size int64, swg *sync.WaitGroup, wwg *sync.WaitGroup) (key Key, err error) {
|
||||||
return self.Chunker.Split(data, size, self.storeC, nil, wg)
|
return self.Chunker.Split(data, size, self.storeC, swg, wwg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *DPA) Start() {
|
func (self *DPA) Start() {
|
||||||
|
|
@ -90,6 +92,8 @@ func (self *DPA) Start() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.running = true
|
self.running = true
|
||||||
|
self.retrieveC = make(chan *Chunk, retrieveChanCapacity)
|
||||||
|
self.storeC = make(chan *Chunk, storeChanCapacity)
|
||||||
self.quitC = make(chan bool)
|
self.quitC = make(chan bool)
|
||||||
self.storeLoop()
|
self.storeLoop()
|
||||||
self.retrieveLoop()
|
self.retrieveLoop()
|
||||||
|
|
@ -108,13 +112,14 @@ func (self *DPA) Stop() {
|
||||||
// retrieveLoop dispatches the parallel chunk retrieval requests received on the
|
// retrieveLoop dispatches the parallel chunk retrieval requests received on the
|
||||||
// retrieve channel to its ChunkStore (NetStore or LocalStore)
|
// retrieve channel to its ChunkStore (NetStore or LocalStore)
|
||||||
func (self *DPA) retrieveLoop() {
|
func (self *DPA) retrieveLoop() {
|
||||||
self.retrieveC = make(chan *Chunk, retrieveChanCapacity)
|
for i:=0; i< maxRetrieveProcesses; i++ {
|
||||||
|
go self.retrieveWorker()
|
||||||
|
}
|
||||||
|
glog.V(logger.Detail).Infof("[BZZ] dpa: retrieve loop spawning %v workers", maxRetrieveProcesses)
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
func (self *DPA) retrieveWorker() {
|
||||||
RETRIEVE:
|
for chunk := range self.retrieveC {
|
||||||
for ch := range self.retrieveC {
|
|
||||||
|
|
||||||
go func(chunk *Chunk) {
|
|
||||||
glog.V(logger.Detail).Infof("[BZZ] dpa: retrieve loop : chunk %v", chunk.Key.Log())
|
glog.V(logger.Detail).Infof("[BZZ] dpa: retrieve loop : chunk %v", chunk.Key.Log())
|
||||||
storedChunk, err := self.Get(chunk.Key)
|
storedChunk, err := self.Get(chunk.Key)
|
||||||
if err == notFound {
|
if err == notFound {
|
||||||
|
|
@ -126,37 +131,39 @@ func (self *DPA) retrieveLoop() {
|
||||||
chunk.Size = storedChunk.Size
|
chunk.Size = storedChunk.Size
|
||||||
}
|
}
|
||||||
close(chunk.C)
|
close(chunk.C)
|
||||||
}(ch)
|
|
||||||
select {
|
select {
|
||||||
case <-self.quitC:
|
case <-self.quitC:
|
||||||
break RETRIEVE
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
|
|
||||||
|
// storeLoop dispatches the parallel chunk store request processors
|
||||||
|
// received on the store channel to its ChunkStore (NetStore or LocalStore)
|
||||||
|
func (self *DPA) storeLoop() {
|
||||||
|
for i:=0; i< maxStoreProcesses; i++ {
|
||||||
|
go self.storeWorker()
|
||||||
|
}
|
||||||
|
glog.V(logger.Detail).Infof("[BZZ] dpa: store spawning %v workers", maxStoreProcesses)
|
||||||
}
|
}
|
||||||
|
|
||||||
// storeLoop dispatches the parallel chunk store requests received on the
|
func (self *DPA) storeWorker() {
|
||||||
// store channel to its ChunkStore (NetStore or LocalStore)
|
|
||||||
func (self *DPA) storeLoop() {
|
for chunk := range self.storeC {
|
||||||
self.storeC = make(chan *Chunk)
|
|
||||||
go func() {
|
|
||||||
STORE:
|
|
||||||
for ch := range self.storeC {
|
|
||||||
go func(chunk *Chunk) {
|
|
||||||
self.Put(chunk)
|
self.Put(chunk)
|
||||||
if chunk.wg != nil {
|
if chunk.wg != nil {
|
||||||
glog.V(logger.Detail).Infof("[BZZ] dpa: store loop %v", chunk.Key.Log())
|
glog.V(logger.Detail).Infof("[BZZ] dpa: store processor %v", chunk.Key.Log())
|
||||||
chunk.wg.Done()
|
chunk.wg.Done()
|
||||||
|
|
||||||
}
|
}
|
||||||
}(ch)
|
select {
|
||||||
select {
|
|
||||||
case <-self.quitC:
|
case <-self.quitC:
|
||||||
break STORE
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DpaChunkStore implements the ChunkStore interface,
|
// DpaChunkStore implements the ChunkStore interface,
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,10 @@ const testDataSize = 0x1000000
|
||||||
func TestDPArandom(t *testing.T) {
|
func TestDPArandom(t *testing.T) {
|
||||||
os.RemoveAll("/tmp/bzz")
|
os.RemoveAll("/tmp/bzz")
|
||||||
dbStore, err := NewDbStore("/tmp/bzz", MakeHashFunc(defaultHash), defaultDbCapacity, defaultRadius)
|
dbStore, err := NewDbStore("/tmp/bzz", MakeHashFunc(defaultHash), defaultDbCapacity, defaultRadius)
|
||||||
dbStore.setCapacity(50000)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("DB error: %v", err)
|
t.Errorf("DB error: %v", err)
|
||||||
}
|
}
|
||||||
|
dbStore.setCapacity(50000)
|
||||||
memStore := NewMemStore(dbStore, defaultCacheCapacity)
|
memStore := NewMemStore(dbStore, defaultCacheCapacity)
|
||||||
localStore := &LocalStore{
|
localStore := &LocalStore{
|
||||||
memStore,
|
memStore,
|
||||||
|
|
@ -29,9 +29,12 @@ func TestDPArandom(t *testing.T) {
|
||||||
ChunkStore: localStore,
|
ChunkStore: localStore,
|
||||||
}
|
}
|
||||||
dpa.Start()
|
dpa.Start()
|
||||||
|
defer dpa.Stop()
|
||||||
|
defer os.RemoveAll("/tmp/bzz")
|
||||||
|
|
||||||
reader, slice := testDataReaderAndSlice(testDataSize)
|
reader, slice := testDataReaderAndSlice(testDataSize)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
key, err := dpa.Store(reader, testDataSize, wg)
|
key, err := dpa.Store(reader, testDataSize, wg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Store error: %v", err)
|
t.Errorf("Store error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +90,7 @@ func TestDPA_capacity(t *testing.T) {
|
||||||
dpa.Start()
|
dpa.Start()
|
||||||
reader, slice := testDataReaderAndSlice(testDataSize)
|
reader, slice := testDataReaderAndSlice(testDataSize)
|
||||||
wg := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
key, err := dpa.Store(reader, testDataSize, wg)
|
key, err := dpa.Store(reader, testDataSize, wg, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Store error: %v", err)
|
t.Errorf("Store error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue