From add89714670cffea184814158863d2210820cdf7 Mon Sep 17 00:00:00 2001 From: lash Date: Wed, 24 Jan 2018 02:44:50 +0100 Subject: [PATCH] swarm/api, swarm/storage: Fullstack contexts --- swarm/api/api.go | 19 +++++++++-------- swarm/api/http/server.go | 10 ++++----- swarm/storage/resource.go | 38 ++++++++++++++-------------------- swarm/storage/resource_test.go | 26 +++++++++++++---------- 4 files changed, 45 insertions(+), 48 deletions(-) diff --git a/swarm/api/api.go b/swarm/api/api.go index 5a222dddc9..572b150da2 100644 --- a/swarm/api/api.go +++ b/swarm/api/api.go @@ -17,6 +17,7 @@ package api import ( + "context" "fmt" "io" "net/http" @@ -365,21 +366,21 @@ func (self *Api) BuildDirectoryTree(mhash string, nameresolver bool) (key storag } // Look up mutable resource updates at specific periods and versions -func (self *Api) ResourceLookup(name string, period uint32, version uint32) (storage.Key, []byte, error) { +func (self *Api) ResourceLookup(ctx context.Context, name string, period uint32, version uint32) (storage.Key, []byte, error) { var err error if version != 0 { if period == 0 { - currentblocknumber, err := self.resource.GetBlock() + currentblocknumber, err := self.resource.GetBlock(ctx) if err != nil { return nil, nil, fmt.Errorf("Could not determine latest block: %v", err) } period = self.resource.BlockToPeriod(name, currentblocknumber) } - _, err = self.resource.LookupVersionByName(name, period, version, true) + _, err = self.resource.LookupVersionByName(ctx, name, period, version, true) } else if period != 0 { - _, err = self.resource.LookupHistoricalByName(name, period, true) + _, err = self.resource.LookupHistoricalByName(ctx, name, period, true) } else { - _, err = self.resource.LookupLatestByName(name, true) + _, err = self.resource.LookupLatestByName(ctx, name, true) } if err != nil { return nil, nil, err @@ -387,8 +388,8 @@ func (self *Api) ResourceLookup(name string, period uint32, version uint32) (sto return self.resource.GetContent(name) } -func (self *Api) ResourceCreate(name string, frequency uint64) (storage.Key, error) { - rsrc, err := self.resource.NewResource(name, frequency) +func (self *Api) ResourceCreate(ctx context.Context, name string, frequency uint64) (storage.Key, error) { + rsrc, err := self.resource.NewResource(ctx, name, frequency) if err != nil { return nil, err } @@ -396,8 +397,8 @@ func (self *Api) ResourceCreate(name string, frequency uint64) (storage.Key, err return storage.Key(h[:]), nil } -func (self *Api) ResourceUpdate(name string, data []byte) (storage.Key, uint32, uint32, error) { - key, err := self.resource.Update(name, data) +func (self *Api) ResourceUpdate(ctx context.Context, name string, data []byte) (storage.Key, uint32, uint32, error) { + key, err := self.resource.Update(ctx, name, data) period, _ := self.resource.GetLastPeriod(name) version, _ := self.resource.GetVersion(name) return key, period, version, err diff --git a/swarm/api/http/server.go b/swarm/api/http/server.go index db81d89c59..a71edfdd23 100644 --- a/swarm/api/http/server.go +++ b/swarm/api/http/server.go @@ -299,7 +299,7 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *Request) { s.BadRequest(w, r, fmt.Sprintf("Cannot parse frequency parameter: %v", err)) return } - key, err := s.api.ResourceCreate(r.uri.Addr, frequency) + key, err := s.api.ResourceCreate(r.Context(), r.uri.Addr, frequency) if err != nil { s.Error(w, r, fmt.Errorf("Resource creation failed: %v", err)) return @@ -312,7 +312,7 @@ func (s *Server) HandlePostResource(w http.ResponseWriter, r *Request) { s.Error(w, r, err) return } - _, _, _, err = s.api.ResourceUpdate(r.uri.Addr, data) + _, _, _, err = s.api.ResourceUpdate(r.Context(), r.uri.Addr, data) if err != nil { s.Error(w, r, fmt.Errorf("Update resource failed: %v", err)) return @@ -350,7 +350,7 @@ func (s *Server) handleGetResource(w http.ResponseWriter, r *Request, name strin log.Debug("handlegetdb", "name", name) switch len(params) { case 0: - updateKey, data, err = s.api.ResourceLookup(name, 0, 0) + updateKey, data, err = s.api.ResourceLookup(r.Context(), name, 0, 0) case 2: version, err = strconv.ParseUint(params[1], 10, 32) if err != nil { @@ -360,13 +360,13 @@ func (s *Server) handleGetResource(w http.ResponseWriter, r *Request, name strin if err != nil { break } - updateKey, data, err = s.api.ResourceLookup(name, uint32(period), uint32(version)) + updateKey, data, err = s.api.ResourceLookup(r.Context(), name, uint32(period), uint32(version)) case 1: period, err = strconv.ParseUint(params[0], 10, 32) if err != nil { break } - updateKey, data, err = s.api.ResourceLookup(name, uint32(period), uint32(version)) + updateKey, data, err = s.api.ResourceLookup(r.Context(), name, uint32(period), uint32(version)) default: s.BadRequest(w, r, "Invalid mutable resource request") return diff --git a/swarm/storage/resource.go b/swarm/storage/resource.go index 7bd437e924..81a7621a63 100644 --- a/swarm/storage/resource.go +++ b/swarm/storage/resource.go @@ -130,8 +130,6 @@ type ethApi interface { // TODO: Include modtime in chunk data + signature type ResourceHandler struct { ChunkStore - ctx context.Context // base for new contexts passed to storage layer and ethapi, to ensure teardown when Close() is called - cancelFunc func() validator ResourceValidator ethClient ethApi resources map[string]*resource @@ -158,15 +156,12 @@ func NewResourceHandler(datadir string, cloudStore CloudStore, ethClient ethApi, DbStore: dbStore, } - ctx, cancel := context.WithCancel(context.Background()) rh := &ResourceHandler{ ChunkStore: newResourceChunkStore(path, hashfunc, localStore, cloudStore), ethClient: ethClient, resources: make(map[string]*resource), validator: validator, storeTimeout: defaultStoreTimeout, - ctx: ctx, - cancelFunc: cancel, hashPool: sync.Pool{ New: func() interface{} { return MakeHashFunc(SHA3Hash)() @@ -241,7 +236,7 @@ func (self *ResourceHandler) chunkSize() int64 { // The signature data should match the hash of the idna-converted name by the validator's namehash function, NOT the raw name bytes. // // The start block of the resource update will be the actual current block height of the connected network. -func (self *ResourceHandler) NewResource(name string, frequency uint64) (*resource, error) { +func (self *ResourceHandler) NewResource(ctx context.Context, name string, frequency uint64) (*resource, error) { // frequency 0 is invalid if frequency == 0 { @@ -272,7 +267,7 @@ func (self *ResourceHandler) NewResource(name string, frequency uint64) (*resour } // get our blockheight at this time - currentblock, err := self.GetBlock() + currentblock, err := self.GetBlock(ctx) if err != nil { return nil, err } @@ -312,11 +307,11 @@ func (self *ResourceHandler) NewResource(name string, frequency uint64) (*resour // update root data was retrieved externally, it typically doesn't) // // -func (self *ResourceHandler) LookupVersionByName(name string, period uint32, version uint32, refresh bool) (*resource, error) { - return self.LookupVersion(self.nameHash(name), name, period, version, refresh) +func (self *ResourceHandler) LookupVersionByName(ctx context.Context, name string, period uint32, version uint32, refresh bool) (*resource, error) { + return self.LookupVersion(ctx, self.nameHash(name), name, period, version, refresh) } -func (self *ResourceHandler) LookupVersion(nameHash common.Hash, name string, period uint32, version uint32, refresh bool) (*resource, error) { +func (self *ResourceHandler) LookupVersion(ctx context.Context, nameHash common.Hash, name string, period uint32, version uint32, refresh bool) (*resource, error) { rsrc, err := self.loadResource(nameHash, name, refresh) if err != nil { return nil, err @@ -332,11 +327,11 @@ func (self *ResourceHandler) LookupVersion(nameHash common.Hash, name string, pe // and returned. // // See also (*ResourceHandler).LookupVersion -func (self *ResourceHandler) LookupHistoricalByName(name string, period uint32, refresh bool) (*resource, error) { - return self.LookupHistorical(self.nameHash(name), name, period, refresh) +func (self *ResourceHandler) LookupHistoricalByName(ctx context.Context, name string, period uint32, refresh bool) (*resource, error) { + return self.LookupHistorical(ctx, self.nameHash(name), name, period, refresh) } -func (self *ResourceHandler) LookupHistorical(nameHash common.Hash, name string, period uint32, refresh bool) (*resource, error) { +func (self *ResourceHandler) LookupHistorical(ctx context.Context, nameHash common.Hash, name string, period uint32, refresh bool) (*resource, error) { rsrc, err := self.loadResource(nameHash, name, refresh) if err != nil { return nil, err @@ -354,18 +349,18 @@ func (self *ResourceHandler) LookupHistorical(nameHash common.Hash, name string, // Version iteration is done as in (*ResourceHandler).LookupHistorical // // See also (*ResourceHandler).LookupHistorical -func (self *ResourceHandler) LookupLatestByName(name string, refresh bool) (*resource, error) { - return self.LookupLatest(self.nameHash(name), name, refresh) +func (self *ResourceHandler) LookupLatestByName(ctx context.Context, name string, refresh bool) (*resource, error) { + return self.LookupLatest(ctx, self.nameHash(name), name, refresh) } -func (self *ResourceHandler) LookupLatest(nameHash common.Hash, name string, refresh bool) (*resource, error) { +func (self *ResourceHandler) LookupLatest(ctx context.Context, nameHash common.Hash, name string, refresh bool) (*resource, error) { // get our blockheight at this time and the next block of the update period rsrc, err := self.loadResource(nameHash, name, refresh) if err != nil { return nil, err } - currentblock, err := self.GetBlock() + currentblock, err := self.GetBlock(ctx) if err != nil { return nil, err } @@ -532,7 +527,7 @@ func (self *ResourceHandler) parseUpdate(chunkdata []byte) (*Signature, uint32, // It is the caller's responsibility to make sure that this data is not stale. // // A resource update cannot span chunks, and thus has max length 4096 -func (self *ResourceHandler) Update(name string, data []byte) (Key, error) { +func (self *ResourceHandler) Update(ctx context.Context, name string, data []byte) (Key, error) { var signaturelength int if self.validator != nil { @@ -555,7 +550,7 @@ func (self *ResourceHandler) Update(name string, data []byte) (Key, error) { } // get our blockheight at this time and the next block of the update period - currentblock, err := self.GetBlock() + currentblock, err := self.GetBlock(ctx) if err != nil { return nil, err } @@ -620,13 +615,10 @@ func (self *ResourceHandler) Update(name string, data []byte) (Key, error) { // Closes the datastore. // Always call this at shutdown to avoid data corruption. func (self *ResourceHandler) Close() { - self.cancelFunc() self.ChunkStore.Close() } -func (self *ResourceHandler) GetBlock() (uint64, error) { - ctx, cancel := context.WithCancel(self.ctx) - defer cancel() +func (self *ResourceHandler) GetBlock(ctx context.Context) (uint64, error) { blockheader, err := self.ethClient.HeaderByNumber(ctx, nil) if err != nil { return 0, err diff --git a/swarm/storage/resource_test.go b/swarm/storage/resource_test.go index e84cdb7b93..376b8397ae 100644 --- a/swarm/storage/resource_test.go +++ b/swarm/storage/resource_test.go @@ -157,7 +157,9 @@ func TestResourceHandler(t *testing.T) { defer teardownTest() // create a new resource - _, err = rh.NewResource(safeName, resourceFrequency) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + _, err = rh.NewResource(ctx, safeName, resourceFrequency) if err != nil { t.Fatal(err) } @@ -183,7 +185,7 @@ func TestResourceHandler(t *testing.T) { resourcekey := make(map[string]Key) fwdBlocks(int(resourceFrequency/2), backend) data := []byte("blinky") - resourcekey["blinky"], err = rh.Update(safeName, data) + resourcekey["blinky"], err = rh.Update(ctx, safeName, data) if err != nil { t.Fatal(err) } @@ -191,7 +193,7 @@ func TestResourceHandler(t *testing.T) { // update on first period fwdBlocks(int(resourceFrequency/2), backend) data = []byte("pinky") - resourcekey["pinky"], err = rh.Update(safeName, data) + resourcekey["pinky"], err = rh.Update(ctx, safeName, data) if err != nil { t.Fatal(err) } @@ -199,7 +201,7 @@ func TestResourceHandler(t *testing.T) { // update on second period fwdBlocks(int(resourceFrequency), backend) data = []byte("inky") - resourcekey["inky"], err = rh.Update(safeName, data) + resourcekey["inky"], err = rh.Update(ctx, safeName, data) if err != nil { t.Fatal(err) } @@ -207,7 +209,7 @@ func TestResourceHandler(t *testing.T) { // update just after second period fwdBlocks(1, backend) data = []byte("clyde") - resourcekey["clyde"], err = rh.Update(safeName, data) + resourcekey["clyde"], err = rh.Update(ctx, safeName, data) if err != nil { t.Fatal(err) } @@ -219,7 +221,7 @@ func TestResourceHandler(t *testing.T) { fwdBlocks(int(resourceFrequency*2)-1, backend) rh2, err := NewResourceHandler(datadir, &testCloudStore{}, rh.ethClient, nil) - _, err = rh2.LookupLatestByName(safeName, true) + _, err = rh2.LookupLatestByName(ctx, safeName, true) if err != nil { t.Fatal(err) } @@ -237,7 +239,7 @@ func TestResourceHandler(t *testing.T) { log.Debug("Latest lookup", "period", rh2.resources[safeName].lastPeriod, "version", rh2.resources[safeName].version, "data", rh2.resources[safeName].data) // specific block, latest version - rsrc, err := rh2.LookupHistoricalByName(safeName, 3, true) + rsrc, err := rh2.LookupHistoricalByName(ctx, safeName, 3, true) if err != nil { t.Fatal(err) } @@ -248,7 +250,7 @@ func TestResourceHandler(t *testing.T) { log.Debug("Historical lookup", "period", rh2.resources[safeName].lastPeriod, "version", rh2.resources[safeName].version, "data", rh2.resources[safeName].data) // specific block, specific version - rsrc, err = rh2.LookupVersionByName(safeName, 3, 1, true) + rsrc, err = rh2.LookupVersionByName(ctx, safeName, 3, 1, true) if err != nil { t.Fatal(err) } @@ -293,14 +295,16 @@ func TestResourceENSOwner(t *testing.T) { defer teardownTest() // create new resource when we are owner = ok - _, err = rh.NewResource(safeName, resourceFrequency) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + _, err = rh.NewResource(ctx, safeName, resourceFrequency) if err != nil { t.Fatalf("Create resource fail: %v", err) } data := []byte("foo") // update resource when we are owner = ok - _, err = rh.Update(safeName, data) + _, err = rh.Update(ctx, safeName, data) if err != nil { t.Fatalf("Update resource fail: %v", err) } @@ -311,7 +315,7 @@ func TestResourceENSOwner(t *testing.T) { t.Fatal(err) } rh.validator.(*ENSValidator).signFunc = signertwo.signContent - _, err = rh.Update(safeName, data) + _, err = rh.Update(ctx, safeName, data) if err == nil { t.Fatalf("Expected resource update fail due to owner mismatch") }