From 7a333e41046e818604f07fcfd6654af30fe70bf9 Mon Sep 17 00:00:00 2001 From: holisticode Date: Tue, 12 Feb 2019 18:17:44 -0500 Subject: swarm/storage: fix HashExplore concurrency bug ethersphere#1211 (#19028) * swarm/storage: fix HashExplore concurrency bug ethersphere#1211 * swarm/storage: lock as value not pointer * swarm/storage: wait for to complete * swarm/storage: fix linter problems * swarm/storage: append to nil slice (cherry picked from commit 3d22a46c94f1d842dbada665b36a453362adda74) --- swarm/storage/filestore.go | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'swarm/storage') diff --git a/swarm/storage/filestore.go b/swarm/storage/filestore.go index 4240f5b1c..0bad944ee 100644 --- a/swarm/storage/filestore.go +++ b/swarm/storage/filestore.go @@ -20,6 +20,7 @@ import ( "context" "io" "sort" + "sync" ) /* @@ -101,38 +102,45 @@ func (f *FileStore) HashSize() int { // GetAllReferences is a public API. This endpoint returns all chunk hashes (only) for a given file func (f *FileStore) GetAllReferences(ctx context.Context, data io.Reader, toEncrypt bool) (addrs AddressCollection, err error) { // create a special kind of putter, which only will store the references - putter := &HashExplorer{ + putter := &hashExplorer{ hasherStore: NewHasherStore(f.ChunkStore, f.hashFunc, toEncrypt), - References: make([]Reference, 0), } // do the actual splitting anyway, no way around it - _, _, err = PyramidSplit(ctx, data, putter, putter) + _, wait, err := PyramidSplit(ctx, data, putter, putter) + if err != nil { + return nil, err + } + // wait for splitting to be complete and all chunks processed + err = wait(ctx) if err != nil { return nil, err } // collect all references addrs = NewAddressCollection(0) - for _, ref := range putter.References { + for _, ref := range putter.references { addrs = append(addrs, Address(ref)) } sort.Sort(addrs) return addrs, nil } -// HashExplorer is a special kind of putter which will only store chunk references -type HashExplorer struct { +// hashExplorer is a special kind of putter which will only store chunk references +type hashExplorer struct { *hasherStore - References []Reference + references []Reference + lock sync.Mutex } // HashExplorer's Put will add just the chunk hashes to its `References` -func (he *HashExplorer) Put(ctx context.Context, chunkData ChunkData) (Reference, error) { +func (he *hashExplorer) Put(ctx context.Context, chunkData ChunkData) (Reference, error) { // Need to do the actual Put, which returns the references ref, err := he.hasherStore.Put(ctx, chunkData) if err != nil { return nil, err } // internally store the reference - he.References = append(he.References, ref) + he.lock.Lock() + he.references = append(he.references, ref) + he.lock.Unlock() return ref, nil } -- cgit