Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 55 additions & 3 deletions internal/gcscache/gcscache.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,46 @@

var ctx = context.Background()

// objectHandle interface wraps the methods we use from storage.ObjectHandle
type objectHandle interface {
NewReader(ctx context.Context) (io.ReadCloser, error)
NewWriter(ctx context.Context) io.WriteCloser
Delete(ctx context.Context) error
}

// bucketHandle interface wraps the methods we use from storage.BucketHandle
type bucketHandle interface {
Object(name string) objectHandle
}

// gcsObjectHandle wraps storage.ObjectHandle to implement our interface
type gcsObjectHandle struct {
*storage.ObjectHandle
}

func (o *gcsObjectHandle) NewReader(ctx context.Context) (io.ReadCloser, error) {
return o.ObjectHandle.NewReader(ctx)

Check warning on line 40 in internal/gcscache/gcscache.go

View check run for this annotation

Codecov / codecov/patch

internal/gcscache/gcscache.go#L39-L40

Added lines #L39 - L40 were not covered by tests
}

func (o *gcsObjectHandle) NewWriter(ctx context.Context) io.WriteCloser {
return o.ObjectHandle.NewWriter(ctx)

Check warning on line 44 in internal/gcscache/gcscache.go

View check run for this annotation

Codecov / codecov/patch

internal/gcscache/gcscache.go#L43-L44

Added lines #L43 - L44 were not covered by tests
}

func (o *gcsObjectHandle) Delete(ctx context.Context) error {
return o.ObjectHandle.Delete(ctx)

Check warning on line 48 in internal/gcscache/gcscache.go

View check run for this annotation

Codecov / codecov/patch

internal/gcscache/gcscache.go#L47-L48

Added lines #L47 - L48 were not covered by tests
}

// gcsBucketHandle wraps storage.BucketHandle to implement our interface
type gcsBucketHandle struct {
*storage.BucketHandle
}

func (b *gcsBucketHandle) Object(name string) objectHandle {
return &gcsObjectHandle{b.BucketHandle.Object(name)}

Check warning on line 57 in internal/gcscache/gcscache.go

View check run for this annotation

Codecov / codecov/patch

internal/gcscache/gcscache.go#L56-L57

Added lines #L56 - L57 were not covered by tests
}

type cache struct {
bucket *storage.BucketHandle
bucket bucketHandle
prefix string
}

Expand All @@ -40,6 +78,12 @@
return nil, false
}

// Treat empty objects as cache misses to prevent cache poisoning
// when objects are deleted by lifecycle rules
if len(value) == 0 {
return nil, false
}

return value, true
}

Expand All @@ -59,7 +103,7 @@
}
}

func (c *cache) object(key string) *storage.ObjectHandle {
func (c *cache) object(key string) objectHandle {
name := path.Join(c.prefix, keyToFilename(key))
return c.bucket.Object(name)
}
Expand All @@ -70,6 +114,14 @@
return hex.EncodeToString(h.Sum(nil))
}

// NewWithBucket constructs a cache using the provided bucket handle
func NewWithBucket(bucket bucketHandle, prefix string) *cache {
return &cache{
bucket: bucket,
prefix: prefix,
}
}

// New constructs a Cache storing files in the specified GCS bucket. If prefix
// is not empty, objects will be prefixed with that path. Credentials should
// be specified using one of the mechanisms supported for Application Default
Expand All @@ -82,6 +134,6 @@

return &cache{
prefix: prefix,
bucket: client.Bucket(bucket),
bucket: &gcsBucketHandle{client.Bucket(bucket)},

Check warning on line 137 in internal/gcscache/gcscache.go

View check run for this annotation

Codecov / codecov/patch

internal/gcscache/gcscache.go#L137

Added line #L137 was not covered by tests
}, nil
}
Loading
Loading