Skip to content

Commit

Permalink
Remove pre render caching (#818)
Browse files Browse the repository at this point in the history
* Remove PreRenderCache and PreRenderCacheControl

* rename and clean cache related items

* rename pre rendered item and use proxy cached items

* rename http pwaResources to cachePWAResources
  • Loading branch information
maxence-charriere authored Mar 12, 2023
1 parent 3fc30b1 commit c0447b7
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 238 deletions.
76 changes: 12 additions & 64 deletions pkg/app/cache.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,10 @@
package app

import (
"context"
"sync"
"time"

"github.com/maxence-charriere/go-app/v9/pkg/cache"
)

// PreRenderCache is the interface that describes a cache that stores
// pre-rendered resources.
type PreRenderCache interface {
// Get returns the item at the given path.
Get(ctx context.Context, path string) (PreRenderedItem, bool)

// Set stored the item at the given path.
Set(ctx context.Context, i PreRenderedItem)
}

// PreRenderedItem represent an item that is stored in a PreRenderCache.
type PreRenderedItem struct {
type cacheItem struct {
// The request path.
Path string

Expand All @@ -29,69 +14,32 @@ type PreRenderedItem struct {
// The response content encoding.
ContentEncoding string

// The cache control.
CacheControl string

// The response body.
Body []byte
}

// Len return the body length.
func (r PreRenderedItem) Size() int {
return len(r.Body)
}

// NewPreRenderLRUCache creates an in memory LRU cache that stores items for the
// given duration. If provided, on eviction functions are called when item are
// evicted.
func NewPreRenderLRUCache(size int, itemTTL time.Duration, onEvict ...func(path string, i PreRenderedItem)) PreRenderCache {
return &preRenderLRUCache{
LRU: cache.LRU{
MaxSize: size,
ItemTTL: itemTTL,
OnEvict: func(path string, i cache.Item) {
item := i.(PreRenderedItem)
for _, fn := range onEvict {
fn(path, item)
}
},
},
}

}

type preRenderLRUCache struct {
cache.LRU
}

func (c *preRenderLRUCache) Get(ctx context.Context, path string) (PreRenderedItem, bool) {
i, ok := c.LRU.Get(ctx, path)
if !ok {
return PreRenderedItem{}, false
}
return i.(PreRenderedItem), true
func (i cacheItem) Len() int {
return len(i.Body)
}

func (c *preRenderLRUCache) Set(ctx context.Context, i PreRenderedItem) {
c.LRU.Set(ctx, i.Path, i)
}

type preRenderCache struct {
type memoryCache struct {
mu sync.RWMutex
items map[string]PreRenderedItem
items map[string]cacheItem
}

func newPreRenderCache(size int) *preRenderCache {
return &preRenderCache{
items: make(map[string]PreRenderedItem, size),
func newMemoryCache(size int) *memoryCache {
return &memoryCache{
items: make(map[string]cacheItem, size),
}
}
func (c *preRenderCache) Set(ctx context.Context, i PreRenderedItem) {

func (c *memoryCache) Set(i cacheItem) {
c.mu.Lock()
c.items[i.Path] = i
c.mu.Unlock()
}
func (c *preRenderCache) Get(ctx context.Context, path string) (PreRenderedItem, bool) {

func (c *memoryCache) Get(path string) (cacheItem, bool) {
c.mu.Lock()
i, ok := c.items[path]
c.mu.Unlock()
Expand Down
121 changes: 6 additions & 115 deletions pkg/app/cache_test.go
Original file line number Diff line number Diff line change
@@ -1,136 +1,27 @@
package app

import (
"context"
"testing"
"time"

"github.com/stretchr/testify/require"
)

func TestPreRenderLRUCache(t *testing.T) {
testPreRenderCache(t, NewPreRenderLRUCache(100, time.Second))
}

func TestPreRenderCache(t *testing.T) {
testPreRenderCache(t, newPreRenderCache(1))
}

func testPreRenderCache(t *testing.T, c PreRenderCache) {
ctx := context.TODO()
func TestMemoryCache(t *testing.T) {
c := newMemoryCache(5)

i := PreRenderedItem{
i := cacheItem{
Path: "/test",
ContentType: "text/html",
ContentEncoding: "gzip",
Body: []byte("test"),
}

ic, ok := c.Get(ctx, i.Path)
ic, ok := c.Get(i.Path)
require.Zero(t, ic)
require.False(t, ok)

c.Set(ctx, i)
ic, ok = c.Get(ctx, i.Path)
c.Set(i)
ic, ok = c.Get(i.Path)
require.True(t, ok)
require.Equal(t, i, ic)
}

func TestPreRenderLRUCacheExpire(t *testing.T) {
ctx := context.TODO()
evictCalled := false
onEvict := func(string, PreRenderedItem) { evictCalled = true }

c := NewPreRenderLRUCache(16, -time.Second, onEvict).(*preRenderLRUCache)

items := []PreRenderedItem{
{
Path: "/test1",
Body: []byte("test"),
},
{
Path: "/test2",
Body: []byte("test"),
},
{
Path: "/test3",
Body: []byte("test"),
},
{
Path: "/test4",
Body: []byte("test"),
},
}

for _, i := range items {
c.Set(ctx, i)
}
require.Equal(t, 4, c.Len())
require.Equal(t, 16, c.Size())

for _, i := range items {
ic, ok := c.Get(ctx, i.Path)
require.Zero(t, ic)
require.False(t, ok)
}
require.Equal(t, 4, c.Len())
require.Equal(t, 16, c.Size())

c.Set(ctx, PreRenderedItem{
Path: "/test5",
Body: []byte("test"),
})
require.Equal(t, 1, c.Len())
require.Equal(t, 4, c.Size())
require.False(t, evictCalled)
}

func TestPreRenderLRUCacheEvict(t *testing.T) {
ctx := context.TODO()

evictCount := 0
evictSize := 0
onEvict := func(path string, i PreRenderedItem) {
evictCount++
evictSize += i.Size()
}

c := NewPreRenderLRUCache(8, time.Second, onEvict).(*preRenderLRUCache)

items := []PreRenderedItem{
{
Path: "/test1",
Body: []byte("test"),
},
{
Path: "/test2",
Body: []byte("test"),
},
}

for _, i := range items {
c.Set(ctx, i)
}
require.Equal(t, 2, c.Len())
require.Equal(t, 8, c.Size())
require.Equal(t, 0, evictCount)
require.Equal(t, 0, evictSize)

c.Set(ctx, PreRenderedItem{
Path: "/test3",
Body: []byte("test"),
})
require.Equal(t, 2, c.Len())
require.Equal(t, 8, c.Size())
require.Equal(t, 1, evictCount)
require.Equal(t, 4, evictSize)

c.Set(ctx, PreRenderedItem{
Path: "/test4",
Body: []byte("testbig"),
})
require.Equal(t, 1, c.Len())
require.Equal(t, 7, c.Size())
require.Equal(t, 3, evictCount)
require.Equal(t, 12, evictSize)
}
Loading

0 comments on commit c0447b7

Please sign in to comment.