Skip to content

Commit

Permalink
Merge pull request #15 from xufeisofly/fix/cache
Browse files Browse the repository at this point in the history
fix: fix cache problem
  • Loading branch information
iFaceless authored Jun 3, 2020
2 parents 42565e2 + e7573f3 commit c899ab8
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 94 deletions.
58 changes: 39 additions & 19 deletions cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,50 @@ package portal
import (
"context"
"fmt"
"sync"

"github.com/bluele/gcache"
"golang.org/x/sync/singleflight"
)

type Cacher interface {
Set(ctx context.Context, key interface{}, value interface{}) error
Get(ctx context.Context, key interface{}) (interface{}, error)
}

type LRUCache struct {
c gcache.Cache
type ErrNil struct{}

func (e *ErrNil) Error() string {
return "portal cache key not found."
}

func NewLRUCache(size int) *LRUCache {
return &LRUCache{
c: gcache.New(size).LRU().Build(),
}
type MapCache struct {
c sync.Map
}

func newMapCache() *MapCache {
return &MapCache{}
}

var _ Cacher = (*LRUCache)(nil)
var _ Cacher = (*MapCache)(nil)

func (lru *LRUCache) Set(_ context.Context, key, value interface{}) error {
return lru.c.Set(key, value)
func (m *MapCache) Set(_ context.Context, key, value interface{}) error {
m.c.Store(key, value)
return nil
}

func (lru *LRUCache) Get(_ context.Context, key interface{}) (interface{}, error) {
return lru.c.Get(key)
func (m *MapCache) Get(_ context.Context, key interface{}) (interface{}, error) {
if v, ok := m.c.Load(key); ok {
return v, nil
}
return nil, &ErrNil{}
}

const (
cacheKeyTem = "%s#%s#%s"
defaultLRUSize = 8192
cacheKeyTem = "%s#%s#%s"
)

var (
DefaultCache = NewLRUCache(defaultLRUSize)
DefaultCache = newMapCache()
portalCache Cacher
isCacheDisabled = false
)
Expand Down Expand Up @@ -69,10 +77,22 @@ func defaultCacheID(cacheObj interface{}) string {
return fmt.Sprintf("%p", cacheObj)
}

func isCacheKeyValid(cacheKey *string) bool {
return portalCache != nil && cacheKey != nil
}

type cachable interface {
PortalDisableCache() bool
}

type cacheGroup struct {
cache Cacher
g *singleflight.Group
}

func newCacheGroup(cache Cacher) *cacheGroup {
return &cacheGroup{
cache: cache,
g: &singleflight.Group{},
}
}

func (cg *cacheGroup) valid() bool {
return portalCache != nil && cg.cache != nil
}
67 changes: 31 additions & 36 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ func (s *Student) Info() *studentInfo {
}

type ClassSchema struct {
Students []*StudentSchema `json:"students" portal:"nested;async"`
Students []*StudentSchema `json:"students" portal:"nested"`
Name string `json:"name" portal:"attr:Name"`
}

type StudentSchema struct {
FullName string `json:"full_name,omitempty" portal:"attr:FullName"`
ShortName string `json:"short_name,omitempty" portal:"meth:GetShortName"`
Age int `json:"age" portal:"attr:Info.Age"`
Height int `json:"height" portal:"attr:Info.Height"`
Age int `json:"age" portal:"attr:Info.Age;async"`
Height int `json:"height" portal:"attr:Info.Height;async"`
}

func (sch *StudentSchema) GetShortName(s *Student) string {
Expand Down Expand Up @@ -86,13 +86,6 @@ func TestDumpWithCache(t *testing.T) {
assert.Equal(t, 1, shortNameCounter)
assert.Equal(t, 1, fullNameCounter)
assert.Equal(t, 1, infoCounter)

err = Dump(&ss, &s)
assert.Nil(t, err)

assert.Equal(t, 1, shortNameCounter)
assert.Equal(t, 1, fullNameCounter)
assert.Equal(t, 1, infoCounter)
}

func TestDumpNestedWithCache(t *testing.T) {
Expand Down Expand Up @@ -121,71 +114,73 @@ func TestDumpNestedWithCache(t *testing.T) {
assert.Equal(t, 1, fullNameCounter)
assert.Equal(t, 1, infoCounter)
assert.Equal(t, 1, nameCounter)

err = Dump(&cc, c)
assert.Nil(t, err)

assert.Equal(t, 1, shortNameCounter)
assert.Equal(t, 1, fullNameCounter)
assert.Equal(t, 1, infoCounter)
assert.Equal(t, 1, nameCounter)
}

var weightCounter int
var metaCounter int

type Food struct {
ID int
}

func (f *Food) Weight() int {
weightCounter += 1
return 100
type meta struct {
Weight int
Size int
}

func (f *Food) Meta() meta {
metaCounter += 1
return meta{Weight: 10, Size: 20}
}

type FoodSchema struct {
Weight string `portal:"attr:Weight"`
Weight string `portal:"attr:Meta.Weight;async"`
Size string `portal:"attr:Meta.Size;async"`
}

func (s *FoodSchema) PortalDisableCache() bool {
return true
}

type FoodSchemaTwo struct {
Weight string `portal:"attr:Weight;disablecache"`
Weight string `portal:"attr:Meta.Weight;async;disablecache"`
Size string `portal:"attr:Meta.Size;async"`
}

type FoodSchemaThree struct {
Weight string `portal:"attr:Weight"`
Weight string `portal:"attr:Meta.Weight;async"`
Size string `portal:"attr:Meta.Size;async"`
}

func TestDumpWithCacheDisabled(t *testing.T) {
SetCache(DefaultCache)
defer SetCache(nil)
weightCounter = 0
metaCounter = 0

f := Food{
ID: 1,
}

var ff FoodSchema
Dump(&ff, &f)
assert.Equal(t, 1, weightCounter)

Dump(&ff, &f)
assert.Equal(t, 2, weightCounter)
assert.Equal(t, 2, metaCounter)
metaCounter = 0

var ff2 FoodSchemaTwo
Dump(&ff2, &f)
assert.Equal(t, 3, weightCounter)
assert.Equal(t, 2, metaCounter)
metaCounter = 0

var ff3 FoodSchemaThree
Dump(&ff3, &f)
assert.Equal(t, 4, weightCounter)
Dump(&ff3, &f)
assert.Equal(t, 4, weightCounter)
assert.Equal(t, 1, metaCounter)
metaCounter = 0

Dump(&ff3, &f, DisableCache())
assert.Equal(t, 5, weightCounter)
assert.Equal(t, 2, metaCounter)
metaCounter = 0

SetCache(nil)
Dump(&ff3, &f)
assert.Equal(t, 6, weightCounter)
assert.Equal(t, 2, metaCounter)
metaCounter = 0
}
6 changes: 3 additions & 3 deletions chell_benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ type Hogwarts struct {
}

func (h *Hogwarts) Addr() string {
time.Sleep(100 * time.Millisecond)
return "addr"
}

Expand All @@ -198,11 +197,13 @@ type HogwartsSchema struct {
type HouseSchema struct {
Name string `portal:"meth:GetMeta.Name;async"`
Color string `portal:"meth:GetMeta.Color;async"`
Desc string `portal:"meth:GetMeta.Desc;async"`
}

type Meta struct {
Name string
Color string
Desc string
}

func makeHouses(count int) (ret []*House) {
Expand All @@ -219,6 +220,7 @@ func (s *HouseSchema) GetMeta(m *House) Meta {
return Meta{
Name: "name",
Color: "red",
Desc: "desc",
}
}

Expand All @@ -235,7 +237,6 @@ func BenchmarkDumpManyWithCache(b *testing.B) {
for i := 0; i < b.N; i++ {
var schemas HogwartsSchema
_ = Dump(&schemas, hogwarts)
_ = Dump(&schemas, hogwarts)
}
}

Expand All @@ -251,6 +252,5 @@ func BenchmarkDumpManyWithoutCache(b *testing.B) {
for i := 0; i < b.N; i++ {
var schemas HogwartsSchema
_ = Dump(&schemas, hogwarts)
_ = Dump(&schemas, hogwarts)
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ module github.com/ifaceless/portal
go 1.13

require (
github.com/bluele/gcache v0.0.0-20190518031135-bc40bd653833
github.com/fatih/structs v1.1.0
github.com/kr/pretty v0.1.0 // indirect
github.com/panjf2000/ants/v2 v2.1.1
github.com/pkg/errors v0.8.1
github.com/sirupsen/logrus v1.4.2
github.com/spf13/cast v1.3.0
github.com/stretchr/testify v1.4.0
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
)
10 changes: 6 additions & 4 deletions schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type schema struct {
parent *schema

cacheDisabled bool
cacheGroup *cacheGroup
}

func newSchema(v interface{}, parent ...*schema) *schema {
Expand Down Expand Up @@ -65,6 +66,7 @@ func newSchema(v interface{}, parent ...*schema) *schema {
rawValue: rawValue,
fieldAliasMapTagName: "json",
cacheDisabled: cacheDisabled,
cacheGroup: newCacheGroup(newMapCache()),
}

if len(parent) > 0 {
Expand Down Expand Up @@ -162,21 +164,21 @@ func (s *schema) fieldValueFromSrc(ctx context.Context, field *schemaField, v in
ret, err = invokeMethodOfAnyType(ctx, s.rawValue, m, v)
} else {
cacheKey := genCacheKey(ctx, s.rawValue, v, m)
ret, err = invokeMethodOfAnyTypeWithCache(ctx, s.rawValue, m, cacheKey, v)
ret, err = invokeMethodOfAnyTypeWithCache(ctx, s.rawValue, m, s.cacheGroup, cacheKey, v)
}

if err != nil {
return nil, fmt.Errorf("failed to get value: %s", err)
}
if len(attrs) > 0 {
return nestedValue(ctx, ret, attrs, !disableCache)
return nestedValue(ctx, ret, attrs, nil, !disableCache)
}
return ret, nil
} else if field.hasChainingAttrs() {
disableCache := noCache || field.isCacheDisabled()
return nestedValue(ctx, v, field.chainingAttrs(), !disableCache)
return nestedValue(ctx, v, field.chainingAttrs(), s.cacheGroup, !disableCache)
} else {
return nestedValue(ctx, v, []string{field.Name()}, false)
return nestedValue(ctx, v, []string{field.Name()}, nil, false)
}

return
Expand Down
Loading

0 comments on commit c899ab8

Please sign in to comment.