swarm: Adding context to more functions

This commit is contained in:
Balint Gabor 2018-07-04 11:47:12 +02:00 committed by Anton Evangelatov
parent ef67a8fdc8
commit f5d08ca6b7
23 changed files with 175 additions and 82 deletions

View file

@ -239,7 +239,7 @@ func (a *API) Retrieve(ctx context.Context, addr storage.Address) (reader storag
} }
// Store wraps the Store API call of the embedded FileStore // Store wraps the Store API call of the embedded FileStore
func (a *API) Store(ctx context.Context, data io.Reader, size int64, toEncrypt bool) (addr storage.Address, wait func(), err error) { func (a *API) Store(ctx context.Context, data io.Reader, size int64, toEncrypt bool) (addr storage.Address, wait func(ctx context.Context) error, err error) {
log.Debug("api.store", "size", size) log.Debug("api.store", "size", size)
return a.fileStore.Store(ctx, data, size, toEncrypt) return a.fileStore.Store(ctx, data, size, toEncrypt)
} }
@ -286,7 +286,7 @@ func (a *API) Resolve(ctx context.Context, uri *URI) (storage.Address, error) {
} }
// Put provides singleton manifest creation on top of FileStore store // Put provides singleton manifest creation on top of FileStore store
func (a *API) Put(ctx context.Context, content string, contentType string, toEncrypt bool) (k storage.Address, wait func(), err error) { func (a *API) Put(ctx context.Context, content string, contentType string, toEncrypt bool) (k storage.Address, wait func(context.Context) error, err error) {
apiPutCount.Inc(1) apiPutCount.Inc(1)
r := strings.NewReader(content) r := strings.NewReader(content)
key, waitContent, err := a.fileStore.Store(ctx, r, int64(len(content)), toEncrypt) key, waitContent, err := a.fileStore.Store(ctx, r, int64(len(content)), toEncrypt)
@ -301,9 +301,12 @@ func (a *API) Put(ctx context.Context, content string, contentType string, toEnc
apiPutFail.Inc(1) apiPutFail.Inc(1)
return nil, nil, err return nil, nil, err
} }
return key, func() { return key, func(ctx context.Context) error {
waitContent() err := waitContent(ctx)
waitManifest() if err != nil {
return err
}
return waitManifest(ctx)
}, nil }, nil
} }

View file

@ -109,11 +109,15 @@ func TestApiPut(t *testing.T) {
testAPI(t, func(api *API, toEncrypt bool) { testAPI(t, func(api *API, toEncrypt bool) {
content := "hello" content := "hello"
exp := expResponse(content, "text/plain", 0) exp := expResponse(content, "text/plain", 0)
addr, wait, err := api.Put(context.TODO(), content, exp.MimeType, toEncrypt) ctx := context.TODO()
addr, wait, err := api.Put(ctx, content, exp.MimeType, toEncrypt)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
err = wait(ctx)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
wait()
resp := testGet(t, api, addr.Hex(), "") resp := testGet(t, api, addr.Hex(), "")
checkResponse(t, resp, exp) checkResponse(t, resp, exp)
}) })

View file

@ -114,12 +114,13 @@ func (fs *FileSystem) Upload(lpath, index string, toEncrypt bool) (string, error
if err == nil { if err == nil {
stat, _ := f.Stat() stat, _ := f.Stat()
var hash storage.Address var hash storage.Address
var wait func() var wait func(context.Context) error
hash, wait, err = fs.api.fileStore.Store(context.TODO(), f, stat.Size(), toEncrypt) ctx := context.TODO()
hash, wait, err = fs.api.fileStore.Store(ctx, f, stat.Size(), toEncrypt)
if hash != nil { if hash != nil {
list[i].Hash = hash.Hex() list[i].Hash = hash.Hex()
} }
wait() err = wait(ctx)
awg.Done() awg.Done()
if err == nil { if err == nil {
first512 := make([]byte, 512) first512 := make([]byte, 512)

View file

@ -106,8 +106,13 @@ func TestApiDirUploadModify(t *testing.T) {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
return return
} }
hash, wait, err := api.Store(context.TODO(), bytes.NewReader(index), int64(len(index)), toEncrypt) ctx := context.TODO()
wait() hash, wait, err := api.Store(ctx, bytes.NewReader(index), int64(len(index)), toEncrypt)
if err != nil {
t.Errorf("unexpected error: %v", err)
return
}
err = wait(ctx)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
return return

View file

@ -383,15 +383,19 @@ func testBzzGetPath(encrypted bool, t *testing.T) {
for i, mf := range testmanifest { for i, mf := range testmanifest {
reader[i] = bytes.NewReader([]byte(mf)) reader[i] = bytes.NewReader([]byte(mf))
var wait func() var wait func(context.Context) error
addr[i], wait, err = srv.FileStore.Store(context.TODO(), reader[i], int64(len(mf)), encrypted) ctx := context.TODO()
addr[i], wait, err = srv.FileStore.Store(ctx, reader[i], int64(len(mf)), encrypted)
for j := i + 1; j < len(testmanifest); j++ { for j := i + 1; j < len(testmanifest); j++ {
testmanifest[j] = strings.Replace(testmanifest[j], fmt.Sprintf("<key%v>", i), addr[i].Hex(), -1) testmanifest[j] = strings.Replace(testmanifest[j], fmt.Sprintf("<key%v>", i), addr[i].Hex(), -1)
} }
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
wait() err = wait(ctx)
if err != nil {
t.Fatal(err)
}
} }
rootRef := addr[2].Hex() rootRef := addr[2].Hex()

View file

@ -69,7 +69,7 @@ func (a *API) NewManifest(ctx context.Context, toEncrypt bool) (storage.Address,
return nil, err return nil, err
} }
key, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), toEncrypt) key, wait, err := a.Store(ctx, bytes.NewReader(data), int64(len(data)), toEncrypt)
wait() wait(ctx)
return key, err return key, err
} }
@ -382,8 +382,12 @@ func (mt *manifestTrie) recalcAndStore() error {
} }
sr := bytes.NewReader(manifest) sr := bytes.NewReader(manifest)
key, wait, err2 := mt.fileStore.Store(context.TODO(), sr, int64(len(manifest)), mt.encrypted) ctx := context.TODO()
wait() key, wait, err2 := mt.fileStore.Store(ctx, sr, int64(len(manifest)), mt.encrypted)
if err2 != nil {
return err2
}
err2 = wait(ctx)
mt.ref = key mt.ref = key
return err2 return err2
} }

View file

@ -46,7 +46,7 @@ func NewStorage(api *API) *Storage {
// its content type // its content type
// //
// DEPRECATED: Use the HTTP API instead // DEPRECATED: Use the HTTP API instead
func (s *Storage) Put(ctx context.Context, content string, contentType string, toEncrypt bool) (storage.Address, func(), error) { func (s *Storage) Put(ctx context.Context, content string, contentType string, toEncrypt bool) (storage.Address, func(context.Context) error, error) {
return s.api.Put(ctx, content, contentType, toEncrypt) return s.api.Put(ctx, content, contentType, toEncrypt)
} }

View file

@ -32,11 +32,15 @@ func TestStoragePutGet(t *testing.T) {
content := "hello" content := "hello"
exp := expResponse(content, "text/plain", 0) exp := expResponse(content, "text/plain", 0)
// exp := expResponse([]byte(content), "text/plain", 0) // exp := expResponse([]byte(content), "text/plain", 0)
bzzkey, wait, err := api.Put(context.TODO(), content, exp.MimeType, toEncrypt) ctx := context.TODO()
bzzkey, wait, err := api.Put(ctx, content, exp.MimeType, toEncrypt)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
err = wait(ctx)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
wait()
bzzhash := bzzkey.Hex() bzzhash := bzzkey.Hex()
// to check put against the API#Get // to check put against the API#Get
resp0 := testGet(t, api.api, bzzhash, "") resp0 := testGet(t, api.api, bzzhash, "")

View file

@ -345,9 +345,13 @@ func testDeliveryFromNodes(t *testing.T, nodes, conns, chunkCount int, skipCheck
// here we distribute chunks of a random file into Stores of nodes 1 to nodes // here we distribute chunks of a random file into Stores of nodes 1 to nodes
rrFileStore := storage.NewFileStore(newRoundRobinStore(sim.Stores[1:]...), storage.NewFileStoreParams()) rrFileStore := storage.NewFileStore(newRoundRobinStore(sim.Stores[1:]...), storage.NewFileStoreParams())
size := chunkCount * chunkSize size := chunkCount * chunkSize
fileHash, wait, err := rrFileStore.Store(context.TODO(), io.LimitReader(crand.Reader, int64(size)), int64(size), false) ctx := context.TODO()
fileHash, wait, err := rrFileStore.Store(ctx, io.LimitReader(crand.Reader, int64(size)), int64(size), false)
// wait until all chunks stored // wait until all chunks stored
wait() if err != nil {
t.Fatal(err.Error())
}
err = wait(ctx)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
@ -627,9 +631,13 @@ Loop:
hashes := make([]storage.Address, chunkCount) hashes := make([]storage.Address, chunkCount)
for i := 0; i < chunkCount; i++ { for i := 0; i < chunkCount; i++ {
// create actual size real chunks // create actual size real chunks
hash, wait, err := remoteFileStore.Store(context.TODO(), io.LimitReader(crand.Reader, int64(chunkSize)), int64(chunkSize), false) ctx := context.TODO()
hash, wait, err := remoteFileStore.Store(ctx, io.LimitReader(crand.Reader, int64(chunkSize)), int64(chunkSize), false)
if err != nil {
b.Fatalf("expected no error. got %v", err)
}
// wait until all chunks stored // wait until all chunks stored
wait() err = wait(ctx)
if err != nil { if err != nil {
b.Fatalf("expected no error. got %v", err) b.Fatalf("expected no error. got %v", err)
} }

View file

@ -117,8 +117,12 @@ func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) {
fileStore := storage.NewFileStore(sim.Stores[0], storage.NewFileStoreParams()) fileStore := storage.NewFileStore(sim.Stores[0], storage.NewFileStoreParams())
size := chunkCount * chunkSize size := chunkCount * chunkSize
_, wait, err := fileStore.Store(context.TODO(), io.LimitReader(crand.Reader, int64(size)), int64(size), false) ctx := context.TODO()
wait() _, wait, err := fileStore.Store(ctx, io.LimitReader(crand.Reader, int64(size)), int64(size), false)
if err != nil {
t.Fatal(err)
}
err = wait(ctx)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }

View file

@ -765,9 +765,13 @@ func uploadFilesToNodes(nodes []*simulations.Node) ([]storage.Address, []string,
return nil, nil, err return nil, nil, err
} }
//store it (upload it) on the FileStore //store it (upload it) on the FileStore
rk, wait, err := fileStore.Store(context.TODO(), strings.NewReader(rfiles[i]), int64(len(rfiles[i])), false) ctx := context.TODO()
rk, wait, err := fileStore.Store(ctx, strings.NewReader(rfiles[i]), int64(len(rfiles[i])), false)
log.Debug("Uploaded random string file to node") log.Debug("Uploaded random string file to node")
wait() if err != nil {
return nil, nil, err
}
err = wait(ctx)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

View file

@ -581,8 +581,12 @@ func uploadFileToSingleNodeStore(id discover.NodeID, chunkCount int) ([]storage.
fileStore := storage.NewFileStore(lstore, storage.NewFileStoreParams()) fileStore := storage.NewFileStore(lstore, storage.NewFileStoreParams())
var rootAddrs []storage.Address var rootAddrs []storage.Address
for i := 0; i < chunkCount; i++ { for i := 0; i < chunkCount; i++ {
rk, wait, err := fileStore.Store(context.TODO(), io.LimitReader(crand.Reader, int64(size)), int64(size), false) ctx := context.TODO()
wait() rk, wait, err := fileStore.Store(ctx, io.LimitReader(crand.Reader, int64(size)), int64(size), false)
if err != nil {
return nil, err
}
err = wait(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -202,9 +202,12 @@ func testSyncBetweenNodes(t *testing.T, nodes, conns, chunkCount int, skipCheck
// here we distribute chunks of a random file into stores 1...nodes // here we distribute chunks of a random file into stores 1...nodes
rrFileStore := storage.NewFileStore(newRoundRobinStore(sim.Stores[1:]...), storage.NewFileStoreParams()) rrFileStore := storage.NewFileStore(newRoundRobinStore(sim.Stores[1:]...), storage.NewFileStoreParams())
size := chunkCount * chunkSize size := chunkCount * chunkSize
_, wait, err := rrFileStore.Store(context.TODO(), io.LimitReader(crand.Reader, int64(size)), int64(size), false) _, wait, err := rrFileStore.Store(ctx, io.LimitReader(crand.Reader, int64(size)), int64(size), false)
if err != nil {
t.Fatal(err.Error())
}
// need to wait cos we then immediately collect the relevant bin content // need to wait cos we then immediately collect the relevant bin content
wait() wait(ctx)
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }

View file

@ -508,14 +508,15 @@ func uploadFile(swarm *Swarm) (storage.Address, string, error) {
// File data is very short, but it is ensured that its // File data is very short, but it is ensured that its
// uniqueness is very certain. // uniqueness is very certain.
data := fmt.Sprintf("test content %s %x", time.Now().Round(0), b) data := fmt.Sprintf("test content %s %x", time.Now().Round(0), b)
k, wait, err := swarm.api.Put(context.TODO(), data, "text/plain", false) ctx := context.TODO()
k, wait, err := swarm.api.Put(ctx, data, "text/plain", false)
if err != nil { if err != nil {
return nil, "", err return nil, "", err
} }
if wait != nil { if wait != nil {
wait() err = wait(ctx)
} }
return k, data, nil return k, data, err
} }
// retrieve is the function that is used for checking the availability of // retrieve is the function that is used for checking the availability of

View file

@ -16,6 +16,7 @@
package storage package storage
import ( import (
"context"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
@ -126,7 +127,7 @@ type TreeChunker struct {
The chunks are not meant to be validated by the chunker when joining. This The chunks are not meant to be validated by the chunker when joining. This
is because it is left to the DPA to decide which sources are trusted. is because it is left to the DPA to decide which sources are trusted.
*/ */
func TreeJoin(addr Address, getter Getter, depth int) *LazyChunkReader { func TreeJoin(ctx context.Context, addr Address, getter Getter, depth int) *LazyChunkReader {
jp := &JoinerParams{ jp := &JoinerParams{
ChunkerParams: ChunkerParams{ ChunkerParams: ChunkerParams{
chunkSize: DefaultChunkSize, chunkSize: DefaultChunkSize,
@ -137,14 +138,14 @@ func TreeJoin(addr Address, getter Getter, depth int) *LazyChunkReader {
depth: depth, depth: depth,
} }
return NewTreeJoiner(jp).Join() return NewTreeJoiner(jp).Join(ctx)
} }
/* /*
When splitting, data is given as a SectionReader, and the key is a hashSize long byte slice (Key), the root hash of the entire content will fill this once processing finishes. When splitting, data is given as a SectionReader, and the key is a hashSize long byte slice (Key), the root hash of the entire content will fill this once processing finishes.
New chunks to store are store using the putter which the caller provides. New chunks to store are store using the putter which the caller provides.
*/ */
func TreeSplit(data io.Reader, size int64, putter Putter) (k Address, wait func(), err error) { func TreeSplit(ctx context.Context, data io.Reader, size int64, putter Putter) (k Address, wait func(context.Context) error, err error) {
tsp := &TreeSplitterParams{ tsp := &TreeSplitterParams{
SplitterParams: SplitterParams{ SplitterParams: SplitterParams{
ChunkerParams: ChunkerParams{ ChunkerParams: ChunkerParams{
@ -156,7 +157,7 @@ func TreeSplit(data io.Reader, size int64, putter Putter) (k Address, wait func(
}, },
size: size, size: size,
} }
return NewTreeSplitter(tsp).Split() return NewTreeSplitter(tsp).Split(ctx)
} }
func NewTreeJoiner(params *JoinerParams) *TreeChunker { func NewTreeJoiner(params *JoinerParams) *TreeChunker {
@ -224,7 +225,7 @@ func (tc *TreeChunker) decrementWorkerCount() {
tc.workerCount -= 1 tc.workerCount -= 1
} }
func (tc *TreeChunker) Split() (k Address, wait func(), err error) { func (tc *TreeChunker) Split(ctx context.Context) (k Address, wait func(context.Context) error, err error) {
if tc.chunkSize <= 0 { if tc.chunkSize <= 0 {
panic("chunker must be initialised") panic("chunker must be initialised")
} }
@ -380,7 +381,7 @@ type LazyChunkReader struct {
getter Getter getter Getter
} }
func (tc *TreeChunker) Join() *LazyChunkReader { func (tc *TreeChunker) Join(ctx context.Context) *LazyChunkReader {
return &LazyChunkReader{ return &LazyChunkReader{
key: tc.addr, key: tc.addr,
chunkSize: tc.chunkSize, chunkSize: tc.chunkSize,

View file

@ -18,6 +18,7 @@ package storage
import ( import (
"bytes" "bytes"
"context"
"crypto/rand" "crypto/rand"
"encoding/binary" "encoding/binary"
"errors" "errors"
@ -81,7 +82,7 @@ func testRandomBrokenData(n int, tester *chunkerTester) {
putGetter := newTestHasherStore(NewMapChunkStore(), SHA3Hash) putGetter := newTestHasherStore(NewMapChunkStore(), SHA3Hash)
expectedError := fmt.Errorf("Broken reader") expectedError := fmt.Errorf("Broken reader")
addr, _, err := TreeSplit(brokendata, int64(n), putGetter) addr, _, err := TreeSplit(context.TODO(), brokendata, int64(n), putGetter)
if err == nil || err.Error() != expectedError.Error() { if err == nil || err.Error() != expectedError.Error() {
tester.t.Fatalf("Not receiving the correct error! Expected %v, received %v", expectedError, err) tester.t.Fatalf("Not receiving the correct error! Expected %v, received %v", expectedError, err)
} }
@ -104,20 +105,24 @@ func testRandomData(usePyramid bool, hash string, n int, tester *chunkerTester)
putGetter := newTestHasherStore(NewMapChunkStore(), hash) putGetter := newTestHasherStore(NewMapChunkStore(), hash)
var addr Address var addr Address
var wait func() var wait func(context.Context) error
var err error var err error
ctx := context.TODO()
if usePyramid { if usePyramid {
addr, wait, err = PyramidSplit(data, putGetter, putGetter) addr, wait, err = PyramidSplit(ctx, data, putGetter, putGetter)
} else { } else {
addr, wait, err = TreeSplit(data, int64(n), putGetter) addr, wait, err = TreeSplit(ctx, data, int64(n), putGetter)
} }
if err != nil { if err != nil {
tester.t.Fatalf(err.Error()) tester.t.Fatalf(err.Error())
} }
tester.t.Logf(" Key = %v\n", addr) tester.t.Logf(" Key = %v\n", addr)
wait() err = wait(ctx)
if err != nil {
tester.t.Fatalf(err.Error())
}
reader := TreeJoin(addr, putGetter, 0) reader := TreeJoin(context.TODO(), addr, putGetter, 0)
output := make([]byte, n) output := make([]byte, n)
r, err := reader.Read(output) r, err := reader.Read(output)
if r != n || err != io.EOF { if r != n || err != io.EOF {
@ -200,11 +205,15 @@ func TestDataAppend(t *testing.T) {
chunkStore := NewMapChunkStore() chunkStore := NewMapChunkStore()
putGetter := newTestHasherStore(chunkStore, SHA3Hash) putGetter := newTestHasherStore(chunkStore, SHA3Hash)
addr, wait, err := PyramidSplit(data, putGetter, putGetter) ctx := context.TODO()
addr, wait, err := PyramidSplit(ctx, data, putGetter, putGetter)
if err != nil {
tester.t.Fatalf(err.Error())
}
err = wait(ctx)
if err != nil { if err != nil {
tester.t.Fatalf(err.Error()) tester.t.Fatalf(err.Error())
} }
wait()
//create a append data stream //create a append data stream
appendInput, found := tester.inputs[uint64(m)] appendInput, found := tester.inputs[uint64(m)]
@ -217,13 +226,16 @@ func TestDataAppend(t *testing.T) {
} }
putGetter = newTestHasherStore(chunkStore, SHA3Hash) putGetter = newTestHasherStore(chunkStore, SHA3Hash)
newAddr, wait, err := PyramidAppend(addr, appendData, putGetter, putGetter) newAddr, wait, err := PyramidAppend(ctx, addr, appendData, putGetter, putGetter)
if err != nil {
tester.t.Fatalf(err.Error())
}
err = wait(ctx)
if err != nil { if err != nil {
tester.t.Fatalf(err.Error()) tester.t.Fatalf(err.Error())
} }
wait()
reader := TreeJoin(newAddr, putGetter, 0) reader := TreeJoin(ctx, newAddr, putGetter, 0)
newOutput := make([]byte, n+m) newOutput := make([]byte, n+m)
r, err := reader.Read(newOutput) r, err := reader.Read(newOutput)
if r != (n + m) { if r != (n + m) {
@ -282,12 +294,16 @@ func benchmarkSplitJoin(n int, t *testing.B) {
data := testDataReader(n) data := testDataReader(n)
putGetter := newTestHasherStore(NewMapChunkStore(), SHA3Hash) putGetter := newTestHasherStore(NewMapChunkStore(), SHA3Hash)
key, wait, err := PyramidSplit(data, putGetter, putGetter) ctx := context.TODO()
key, wait, err := PyramidSplit(ctx, data, putGetter, putGetter)
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }
wait() err = wait(ctx)
reader := TreeJoin(key, putGetter, 0) if err != nil {
t.Fatalf(err.Error())
}
reader := TreeJoin(ctx, key, putGetter, 0)
benchReadAll(reader) benchReadAll(reader)
} }
} }
@ -298,7 +314,7 @@ func benchmarkSplitTreeSHA3(n int, t *testing.B) {
data := testDataReader(n) data := testDataReader(n)
putGetter := newTestHasherStore(&fakeChunkStore{}, SHA3Hash) putGetter := newTestHasherStore(&fakeChunkStore{}, SHA3Hash)
_, _, err := TreeSplit(data, int64(n), putGetter) _, _, err := TreeSplit(context.TODO(), data, int64(n), putGetter)
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }
@ -311,7 +327,7 @@ func benchmarkSplitTreeBMT(n int, t *testing.B) {
data := testDataReader(n) data := testDataReader(n)
putGetter := newTestHasherStore(&fakeChunkStore{}, BMTHash) putGetter := newTestHasherStore(&fakeChunkStore{}, BMTHash)
_, _, err := TreeSplit(data, int64(n), putGetter) _, _, err := TreeSplit(context.TODO(), data, int64(n), putGetter)
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }
@ -324,7 +340,7 @@ func benchmarkSplitPyramidSHA3(n int, t *testing.B) {
data := testDataReader(n) data := testDataReader(n)
putGetter := newTestHasherStore(&fakeChunkStore{}, SHA3Hash) putGetter := newTestHasherStore(&fakeChunkStore{}, SHA3Hash)
_, _, err := PyramidSplit(data, putGetter, putGetter) _, _, err := PyramidSplit(context.TODO(), data, putGetter, putGetter)
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }
@ -338,7 +354,7 @@ func benchmarkSplitPyramidBMT(n int, t *testing.B) {
data := testDataReader(n) data := testDataReader(n)
putGetter := newTestHasherStore(&fakeChunkStore{}, BMTHash) putGetter := newTestHasherStore(&fakeChunkStore{}, BMTHash)
_, _, err := PyramidSplit(data, putGetter, putGetter) _, _, err := PyramidSplit(context.TODO(), data, putGetter, putGetter)
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }
@ -354,18 +370,25 @@ func benchmarkSplitAppendPyramid(n, m int, t *testing.B) {
chunkStore := NewMapChunkStore() chunkStore := NewMapChunkStore()
putGetter := newTestHasherStore(chunkStore, SHA3Hash) putGetter := newTestHasherStore(chunkStore, SHA3Hash)
key, wait, err := PyramidSplit(data, putGetter, putGetter) ctx := context.TODO()
key, wait, err := PyramidSplit(ctx, data, putGetter, putGetter)
if err != nil {
t.Fatalf(err.Error())
}
err = wait(ctx)
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }
wait()
putGetter = newTestHasherStore(chunkStore, SHA3Hash) putGetter = newTestHasherStore(chunkStore, SHA3Hash)
_, wait, err = PyramidAppend(key, data1, putGetter, putGetter) _, wait, err = PyramidAppend(ctx, key, data1, putGetter, putGetter)
if err != nil {
t.Fatalf(err.Error())
}
err = wait(ctx)
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }
wait()
} }
} }

View file

@ -82,15 +82,15 @@ func NewFileStore(store ChunkStore, params *FileStoreParams) *FileStore {
func (f *FileStore) Retrieve(ctx context.Context, addr Address) (reader *LazyChunkReader, isEncrypted bool) { func (f *FileStore) Retrieve(ctx context.Context, addr Address) (reader *LazyChunkReader, isEncrypted bool) {
isEncrypted = len(addr) > f.hashFunc().Size() isEncrypted = len(addr) > f.hashFunc().Size()
getter := NewHasherStore(f.ChunkStore, f.hashFunc, isEncrypted) getter := NewHasherStore(f.ChunkStore, f.hashFunc, isEncrypted)
reader = TreeJoin(addr, getter, 0) reader = TreeJoin(ctx, addr, getter, 0)
return return
} }
// 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 (f *FileStore) Store(ctx context.Context, data io.Reader, size int64, toEncrypt bool) (addr Address, wait func(), err error) { func (f *FileStore) Store(ctx context.Context, data io.Reader, size int64, toEncrypt bool) (addr Address, wait func(context.Context) error, err error) {
putter := NewHasherStore(f.ChunkStore, f.hashFunc, toEncrypt) putter := NewHasherStore(f.ChunkStore, f.hashFunc, toEncrypt)
return PyramidSplit(data, putter, putter) return PyramidSplit(ctx, data, putter, putter)
} }
func (f *FileStore) HashSize() int { func (f *FileStore) HashSize() int {

View file

@ -50,11 +50,15 @@ func testFileStoreRandom(toEncrypt bool, t *testing.T) {
defer os.RemoveAll("/tmp/bzz") defer os.RemoveAll("/tmp/bzz")
reader, slice := generateRandomData(testDataSize) reader, slice := generateRandomData(testDataSize)
key, wait, err := fileStore.Store(context.TODO(), reader, testDataSize, toEncrypt) ctx := context.TODO()
key, wait, err := fileStore.Store(ctx, reader, testDataSize, toEncrypt)
if err != nil { if err != nil {
t.Errorf("Store error: %v", err) t.Errorf("Store error: %v", err)
} }
wait() err = wait(ctx)
if err != nil {
t.Fatalf("Store waitt error: %v", err.Error())
}
resultReader, isEncrypted := fileStore.Retrieve(context.TODO(), key) resultReader, isEncrypted := fileStore.Retrieve(context.TODO(), key)
if isEncrypted != toEncrypt { if isEncrypted != toEncrypt {
t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted) t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted)
@ -111,11 +115,15 @@ func testFileStoreCapacity(toEncrypt bool, t *testing.T) {
} }
fileStore := NewFileStore(localStore, NewFileStoreParams()) fileStore := NewFileStore(localStore, NewFileStoreParams())
reader, slice := generateRandomData(testDataSize) reader, slice := generateRandomData(testDataSize)
key, wait, err := fileStore.Store(context.TODO(), reader, testDataSize, toEncrypt) ctx := context.TODO()
key, wait, err := fileStore.Store(ctx, reader, testDataSize, toEncrypt)
if err != nil {
t.Errorf("Store error: %v", err)
}
err = wait(ctx)
if err != nil { if err != nil {
t.Errorf("Store error: %v", err) t.Errorf("Store error: %v", err)
} }
wait()
resultReader, isEncrypted := fileStore.Retrieve(context.TODO(), key) resultReader, isEncrypted := fileStore.Retrieve(context.TODO(), key)
if isEncrypted != toEncrypt { if isEncrypted != toEncrypt {
t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted) t.Fatalf("isEncrypted expected %v got %v", toEncrypt, isEncrypted)

View file

@ -17,6 +17,7 @@
package storage package storage
import ( import (
"context"
"fmt" "fmt"
"sync" "sync"
@ -126,9 +127,10 @@ func (h *hasherStore) Close() {
// Wait returns when // Wait returns when
// 1) the Close() function has been called and // 1) the Close() function has been called and
// 2) all the chunks which has been Put has been stored // 2) all the chunks which has been Put has been stored
func (h *hasherStore) Wait() { func (h *hasherStore) Wait(ctx context.Context) error {
<-h.closed <-h.closed
h.wg.Wait() h.wg.Wait()
return nil
} }
func (h *hasherStore) createHash(chunkData ChunkData) Address { func (h *hasherStore) createHash(chunkData ChunkData) Address {

View file

@ -18,6 +18,7 @@ package storage
import ( import (
"bytes" "bytes"
"context"
"testing" "testing"
"github.com/ethereum/go-ethereum/swarm/storage/encryption" "github.com/ethereum/go-ethereum/swarm/storage/encryption"
@ -60,7 +61,10 @@ func TestHasherStore(t *testing.T) {
hasherStore.Close() hasherStore.Close()
// Wait until chunks are really stored // Wait until chunks are really stored
hasherStore.Wait() err = hasherStore.Wait(context.TODO())
if err != nil {
t.Fatalf("Expected no error got \"%v\"", err)
}
// Get the first chunk // Get the first chunk
retrievedChunkData1, err := hasherStore.Get(key1) retrievedChunkData1, err := hasherStore.Get(key1)

View file

@ -17,6 +17,7 @@
package storage package storage
import ( import (
"context"
"encoding/binary" "encoding/binary"
"errors" "errors"
"io" "io"
@ -99,12 +100,12 @@ func NewPyramidSplitterParams(addr Address, reader io.Reader, putter Putter, get
When splitting, data is given as a SectionReader, and the key is a hashSize long byte slice (Key), the root hash of the entire content will fill this once processing finishes. When splitting, data is given as a SectionReader, and the key is a hashSize long byte slice (Key), the root hash of the entire content will fill this once processing finishes.
New chunks to store are store using the putter which the caller provides. New chunks to store are store using the putter which the caller provides.
*/ */
func PyramidSplit(reader io.Reader, putter Putter, getter Getter) (Address, func(), error) { func PyramidSplit(ctx context.Context, reader io.Reader, putter Putter, getter Getter) (Address, func(context.Context) error, error) {
return NewPyramidSplitter(NewPyramidSplitterParams(nil, reader, putter, getter, DefaultChunkSize)).Split() return NewPyramidSplitter(NewPyramidSplitterParams(nil, reader, putter, getter, DefaultChunkSize)).Split(ctx)
} }
func PyramidAppend(addr Address, reader io.Reader, putter Putter, getter Getter) (Address, func(), error) { func PyramidAppend(ctx context.Context, addr Address, reader io.Reader, putter Putter, getter Getter) (Address, func(context.Context) error, error) {
return NewPyramidSplitter(NewPyramidSplitterParams(addr, reader, putter, getter, DefaultChunkSize)).Append() return NewPyramidSplitter(NewPyramidSplitterParams(addr, reader, putter, getter, DefaultChunkSize)).Append(ctx)
} }
// Entry to create a tree node // Entry to create a tree node
@ -203,7 +204,7 @@ func (pc *PyramidChunker) decrementWorkerCount() {
pc.workerCount -= 1 pc.workerCount -= 1
} }
func (pc *PyramidChunker) Split() (k Address, wait func(), err error) { func (pc *PyramidChunker) Split(ctx context.Context) (k Address, wait func(context.Context) error, err error) {
log.Debug("pyramid.chunker: Split()") log.Debug("pyramid.chunker: Split()")
pc.wg.Add(1) pc.wg.Add(1)
@ -235,7 +236,7 @@ func (pc *PyramidChunker) Split() (k Address, wait func(), err error) {
} }
func (pc *PyramidChunker) Append() (k Address, wait func(), err error) { func (pc *PyramidChunker) Append(ctx context.Context) (k Address, wait func(context.Context) error, err error) {
log.Debug("pyramid.chunker: Append()") log.Debug("pyramid.chunker: Append()")
// Load the right most unfinished tree chunks in every level // Load the right most unfinished tree chunks in every level
pc.loadTree() pc.loadTree()

View file

@ -18,6 +18,7 @@ package storage
import ( import (
"bytes" "bytes"
"context"
"crypto" "crypto"
"crypto/rand" "crypto/rand"
"encoding/binary" "encoding/binary"
@ -303,7 +304,7 @@ type Putter interface {
// Close is to indicate that no more chunk data will be Put on this Putter // Close is to indicate that no more chunk data will be Put on this Putter
Close() Close()
// Wait returns if all data has been store and the Close() was called. // Wait returns if all data has been store and the Close() was called.
Wait() Wait(context.Context) error
} }
// Getter is an interface to retrieve a chunk's data by its reference // Getter is an interface to retrieve a chunk's data by its reference

View file

@ -348,12 +348,16 @@ func testLocalStoreAndRetrieve(t *testing.T, swarm *Swarm, n int, randomData boo
} }
dataPut := string(slice) dataPut := string(slice)
k, wait, err := swarm.api.Store(context.TODO(), strings.NewReader(dataPut), int64(len(dataPut)), false) ctx := context.TODO()
k, wait, err := swarm.api.Store(ctx, strings.NewReader(dataPut), int64(len(dataPut)), false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if wait != nil { if wait != nil {
wait() err = wait(ctx)
if err != nil {
t.Fatal(err)
}
} }
r, _ := swarm.api.Retrieve(context.TODO(), k) r, _ := swarm.api.Retrieve(context.TODO(), k)