diff --git a/lib/gobuild/gobuild.go b/lib/gobuild/gobuild.go index c024730..5592019 100644 --- a/lib/gobuild/gobuild.go +++ b/lib/gobuild/gobuild.go @@ -6,7 +6,6 @@ package gobuild import ( - "bytes" "context" "errors" "expvar" @@ -121,12 +120,13 @@ func (s *S3Cache) Get(ctx context.Context, actionID string) (outputID, diskPath return "", "", err } - object, err := s.S3Client.GetData(ctx, s.outputKey(outputID)) + object, size, err := s.S3Client.Get(ctx, s.outputKey(outputID)) if err != nil { // At this point we know the action exists, so if we can't read the // object report it as an error rather than a cache miss. return "", "", fmt.Errorf("[s3] read object %s: %w", outputID, err) } + defer object.Close() s.getFaultHit.Add(1) // Now we should have the body; poke it into the local cache. Preserve the @@ -134,8 +134,8 @@ func (s *S3Cache) Get(ctx context.Context, actionID string) (outputID, diskPath diskPath, err = s.Local.Put(ctx, gocache.Object{ ActionID: actionID, OutputID: outputID, - Size: int64(len(object)), - Body: bytes.NewReader(object), + Size: size, + Body: object, ModTime: mtime, }) return outputID, diskPath, err diff --git a/lib/modproxy/modproxy.go b/lib/modproxy/modproxy.go index 559bc57..889292c 100644 --- a/lib/modproxy/modproxy.go +++ b/lib/modproxy/modproxy.go @@ -158,7 +158,7 @@ func (c *S3Cacher) Get(ctx context.Context, name string) (_ io.ReadCloser, oerr } defer c.sema.Release(1) - obj, err := c.S3Client.Get(ctx, c.makeKey(hash)) + obj, _, err := c.S3Client.Get(ctx, c.makeKey(hash)) if errors.Is(err, fs.ErrNotExist) { c.getFaultMiss.Add(1) return nil, err diff --git a/lib/s3util/s3util.go b/lib/s3util/s3util.go index 4b724c5..84c602d 100644 --- a/lib/s3util/s3util.go +++ b/lib/s3util/s3util.go @@ -122,24 +122,24 @@ func (c *Client) Put(ctx context.Context, key string, data io.Reader) error { // close the reader when finished. // // If the key is not found, the resulting error satisfies [fs.ErrNotExist]. -func (c *Client) Get(ctx context.Context, key string) (io.ReadCloser, error) { +func (c *Client) Get(ctx context.Context, key string) (io.ReadCloser, int64, error) { rsp, err := c.Client.GetObject(ctx, &s3.GetObjectInput{ Bucket: &c.Bucket, Key: &key, }) if err != nil { if IsNotExist(err) { - return nil, fmt.Errorf("key %q: %w", key, fs.ErrNotExist) + return nil, -1, fmt.Errorf("key %q: %w", key, fs.ErrNotExist) } - return nil, err + return nil, -1, err } - return rsp.Body, nil + return rsp.Body, *rsp.ContentLength, nil } // GetData returns the contents of the specified key from S3. It is a shorthand // for calling Get followed by io.ReadAll on the result. func (c *Client) GetData(ctx context.Context, key string) ([]byte, error) { - rc, err := c.Get(ctx, key) + rc, _, err := c.Get(ctx, key) if err != nil { return nil, err }