Skip to content

Commit

Permalink
feat: custom cache strategy (#42)
Browse files Browse the repository at this point in the history
  • Loading branch information
scorix authored Dec 4, 2024
1 parent 98699f6 commit 974ce8b
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 51 deletions.
52 changes: 4 additions & 48 deletions pkg/grib2/cache/boundary.go
Original file line number Diff line number Diff line change
@@ -1,53 +1,9 @@
package cache

import (
"context"
"strconv"

"golang.org/x/sync/singleflight"
)

type boundary struct {
minLat float32
maxLat float32
minLon float32
maxLon float32

cache Store
datasource GridDataSource
sfg singleflight.Group
}

func NewBoundary(minLat, maxLat, minLon, maxLon float32, datasource GridDataSource) GridCache {
return &boundary{
minLat: minLat,
maxLat: maxLat,
minLon: minLon,
maxLon: maxLon,
datasource: datasource,
cache: NewMapStore(),
func NewBoundary(minLat, maxLat, minLon, maxLon float32, datasource GridDataSource, cacheStore Store) GridCache {
inCache := func(lat, lon float32) bool {
return lat >= minLat && lat <= maxLat && lon >= minLon && lon <= maxLon
}
}

func (b *boundary) ReadGridAt(ctx context.Context, grid int, lat, lon float32) (float32, error) {
if lat < b.minLat || lat > b.maxLat || lon < b.minLon || lon > b.maxLon {
return b.datasource.ReadGridAt(ctx, grid)
}

v, err, _ := b.sfg.Do(strconv.Itoa(grid), func() (interface{}, error) {
vFromCache, ok := b.cache.Get(ctx, grid)
if !ok {
vFromSource, err := b.datasource.ReadGridAt(ctx, grid)
if err != nil {
return 0, err
}

b.cache.Set(ctx, grid, vFromSource)
vFromCache = vFromSource
}

return vFromCache, nil
})

return v.(float32), err
return NewCustom(inCache, datasource, cacheStore)
}
2 changes: 1 addition & 1 deletion pkg/grib2/cache/boundary_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (

func TestBoundary(t *testing.T) {
ds := &mockGridDataSource{gridValue: 100}
bc := cache.NewBoundary(0, 10, 0, 10, ds)
bc := cache.NewBoundary(0, 10, 0, 10, ds, cache.NewMapStore())

// first read should be from source
v, err := bc.ReadGridAt(context.TODO(), 1, 1, 1)
Expand Down
5 changes: 5 additions & 0 deletions pkg/grib2/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ type GridDataSource interface {

type GridCache interface {
ReadGridAt(ctx context.Context, grid int, lat, lon float32) (float32, error)
InCache(lat, lon float32) bool
}

type noCache struct {
Expand All @@ -21,3 +22,7 @@ func NewNoCache(datasource GridDataSource) GridCache {
func (n *noCache) ReadGridAt(ctx context.Context, grid int, lat, lon float32) (float32, error) {
return n.datasource.ReadGridAt(ctx, grid)
}

func (n *noCache) InCache(lat, lon float32) bool {
return false
}
47 changes: 47 additions & 0 deletions pkg/grib2/cache/custom.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package cache

import (
"context"
"strconv"

"golang.org/x/sync/singleflight"
)

type custom struct {
inCache func(lat, lon float32) bool

cache Store
datasource GridDataSource
sfg singleflight.Group
}

func NewCustom(inCache func(lat, lon float32) bool, datasource GridDataSource, cacheStore Store) GridCache {
return &custom{inCache: inCache, datasource: datasource, cache: cacheStore}
}

func (c *custom) InCache(lat, lon float32) bool {
return c.inCache(lat, lon)
}

func (c *custom) ReadGridAt(ctx context.Context, grid int, lat, lon float32) (float32, error) {
if !c.InCache(lat, lon) {
return c.datasource.ReadGridAt(ctx, grid)
}

v, err, _ := c.sfg.Do(strconv.Itoa(grid), func() (interface{}, error) {
vFromCache, ok := c.cache.Get(ctx, grid)
if !ok {
vFromSource, err := c.datasource.ReadGridAt(ctx, grid)
if err != nil {
return 0, err
}

c.cache.Set(ctx, grid, vFromSource)
vFromCache = vFromSource
}

return vFromCache, nil
})

return v.(float32), err
}
10 changes: 8 additions & 2 deletions pkg/grib2/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,15 @@ func NewSimplePackingMessageReaderFromMessage(r io.ReaderAt, m IndexedMessage, o

type SimplePackingMessageReaderOptions func(r *simplePackingMessageReader)

func WithBoundary(minLat, maxLat, minLon, maxLon float32) SimplePackingMessageReaderOptions {
func WithBoundaryCache(minLat, maxLat, minLon, maxLon float32) SimplePackingMessageReaderOptions {
return func(r *simplePackingMessageReader) {
r.cache = cache.NewBoundary(minLat, maxLat, minLon, maxLon, r.spr)
r.cache = cache.NewBoundary(minLat, maxLat, minLon, maxLon, r.spr, cache.NewMapStore())
}
}

func WithCustomCacheStrategy(inCache func(lat, lon float32) bool) SimplePackingMessageReaderOptions {
return func(r *simplePackingMessageReader) {
r.cache = cache.NewCustom(inCache, r.spr, cache.NewMapStore())
}
}

Expand Down

0 comments on commit 974ce8b

Please sign in to comment.