Skip to content

Commit

Permalink
feat: log level, removed mergo options for nicer optional params
Browse files Browse the repository at this point in the history
  • Loading branch information
23doors committed Jul 30, 2020
1 parent ae56702 commit 1ebb215
Show file tree
Hide file tree
Showing 31 changed files with 256 additions and 171 deletions.
50 changes: 33 additions & 17 deletions cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@ import (
"container/list"
"sync"
"time"

"github.com/imdario/mergo"
)

// Cache is an abstract raw struct used for LIFO-like LRU cache with ttl.
// As it provides no value access interface, it should be extended depending on what's needed.
// All exported methods should be thread-safe and use internal mutex.
// See LRUCache for example implementation.
type Cache struct {
options Options
cfg Config

// Maintain both valueMap and valuesList in sync.
// valueMap is used as a storage for key->list
Expand All @@ -29,18 +27,36 @@ type Cache struct {
deleteHandler DeleteHandler
}

// Options holds settable options for cache.
type Options struct {
// Config holds settable config for cache.
type Config struct {
TTL time.Duration
CleanupInterval time.Duration
Capacity int
}

var defaultOptions = &Options{
var DefaultConfig = Config{
TTL: 30 * time.Second,
CleanupInterval: 15 * time.Second,
}

func WithTTL(ttl time.Duration) func(*Config) {
return func(config *Config) {
config.TTL = ttl
}
}

func WithCleanupInterval(val time.Duration) func(*Config) {
return func(config *Config) {
config.CleanupInterval = val
}
}

func WithCapacity(c int) func(*Config) {
return func(config *Config) {
config.Capacity = c
}
}

// Item is used as a single element in cache.
type Item struct {
object interface{}
Expand Down Expand Up @@ -68,21 +84,21 @@ type DeleteHandler func(*valuesItem) *keyValue
type EvictionHandler func(string, interface{})

// Init initializes cache struct fields and starts janitor process.
func (c *Cache) Init(options *Options, deleteHandler DeleteHandler) {
func (c *Cache) Init(deleteHandler DeleteHandler, opts ...func(*Config)) {
c.mu.Lock()
defer c.mu.Unlock()

if c.janitor != nil {
panic("init on cache cannot be called twice")
}

if options != nil {
mergo.Merge(options, defaultOptions) // nolint - error not possible
} else {
options = defaultOptions
cfg := DefaultConfig

for _, opt := range opts {
opt(&cfg)
}

c.options = *options
c.cfg = cfg

if deleteHandler == nil {
deleteHandler = c.defaultDeleteHandler
Expand All @@ -92,16 +108,16 @@ func (c *Cache) Init(options *Options, deleteHandler DeleteHandler) {
c.valueMap = make(map[string]interface{})
c.valuesList = list.New()
c.janitor = &janitor{
interval: options.CleanupInterval,
interval: cfg.CleanupInterval,
stop: make(chan struct{}),
}

go c.janitor.Run(c)
}

// Options returns a copy of options struct.
func (c *Cache) Options() Options {
return c.options
func (c *Cache) Config() Config {
return c.cfg
}

// StopJanitor is meant to be called when cache is no longer needed to avoid leaking goroutine.
Expand Down Expand Up @@ -234,8 +250,8 @@ func (c *Cache) deleteValue(e *list.Element, now int64) (valueEvicted *keyValue)

func (c *Cache) checkLength() {
// If we are over the capacity, delete one closest to expiring.
if c.options.Capacity > 0 {
for c.valuesList.Len() > c.options.Capacity {
if c.cfg.Capacity > 0 {
for c.valuesList.Len() > c.cfg.Capacity {
c.deleteLRU()
}
}
Expand Down
10 changes: 5 additions & 5 deletions cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ func TestCache(t *testing.T) {
c := new(Cache)

Convey("Init sets default delete handler and starts janitor", func() {
c.Init(&Options{}, nil)
c.Init(nil)
So(c.janitor, ShouldNotBeNil)
So(c.deleteHandler, ShouldEqual, c.defaultDeleteHandler)

Convey("and cannot be called twice", func() {
So(func() { c.Init(&Options{}, nil) }, ShouldPanic)
So(func() { c.Init(nil) }, ShouldPanic)
})
Convey("delete returns false when delete handler returns nil", func() {
c.deleteHandler = func(item *valuesItem) *keyValue {
Expand All @@ -42,9 +42,9 @@ func TestCache(t *testing.T) {
})
})

Convey("Options returns a copy of options struct", func() {
So(c.Options(), ShouldNotEqual, c.options)
So(c.Options(), ShouldResemble, c.options)
Convey("Config returns a copy of config struct", func() {
So(c.Config(), ShouldNotEqual, c.cfg)
So(c.Config(), ShouldResemble, c.cfg)
})

})
Expand Down
29 changes: 6 additions & 23 deletions cache/lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,29 @@ package cache

import (
"time"

"github.com/imdario/mergo"
)

// LRUCache describes a struct for caching.
type LRUCache struct {
Cache
lruOptions LRUOptions
}

// LRUOptions holds settable options for cache.
type LRUOptions struct {
AutoRefresh bool
}

var defaultLRUOptions = &LRUOptions{
AutoRefresh: true,
autoRefresh bool
}

// NewLRUCache creates and initializes a new cache object.
// This one is based on LRU KV with TTL
func NewLRUCache(options *Options, lruOptions *LRUOptions) *LRUCache {
if lruOptions != nil {
mergo.Merge(lruOptions, defaultLRUOptions) // nolint - error not possible
} else {
lruOptions = defaultLRUOptions
}

func NewLRUCache(autoRefresh bool, opts ...func(*Config)) *LRUCache {
cache := LRUCache{
lruOptions: *lruOptions,
autoRefresh: autoRefresh,
}

cache.Cache.Init(options, cache.deleteHandler)
cache.Cache.Init(cache.deleteHandler, opts...)

return &cache
}

// Get returns an item at given key. It automatically extends the expiration if auto refresh is true. Returns the item or nil.
func (c *LRUCache) Get(key string) interface{} {
return c.get(key, c.lruOptions.AutoRefresh)
return c.get(key, c.autoRefresh)
}

func (c *LRUCache) get(key string, refresh bool) interface{} {
Expand Down Expand Up @@ -73,7 +56,7 @@ func (c *LRUCache) Refresh(key string) bool {

func (c *LRUCache) set(key string, val interface{}, ttl time.Duration) {
if ttl == 0 {
ttl = c.options.TTL
ttl = c.cfg.TTL
}

cItem := &Item{object: val, expiration: time.Now().Add(ttl).UnixNano(), ttl: ttl}
Expand Down
6 changes: 3 additions & 3 deletions cache/lru_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ type LRUSetCache struct {

// NewLRUSetCache creates and initializes a new cache object.
// This one is based on LRU K->List with TTL
func NewLRUSetCache(options *Options) *LRUSetCache {
func NewLRUSetCache(opts ...func(*Config)) *LRUSetCache {
cache := LRUSetCache{}
cache.Cache.Init(options, cache.deleteHandler)
cache.Cache.Init(cache.deleteHandler, opts...)

return &cache
}
Expand Down Expand Up @@ -77,7 +77,7 @@ func (c *LRUSetCache) Add(key string, val interface{}) bool {

func (c *LRUSetCache) AddTTL(key string, val interface{}, ttl time.Duration) bool {
if ttl == 0 {
ttl = c.options.TTL
ttl = c.cfg.TTL
}

c.mu.Lock()
Expand Down
4 changes: 3 additions & 1 deletion cache/lru_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import (

func TestLRUSetCache(t *testing.T) {
Convey("Given new LRU set", t, func() {
c := NewLRUSetCache(&Options{Capacity: 3, CleanupInterval: 1 * time.Millisecond})
c := NewLRUSetCache(
WithCapacity(3), WithCleanupInterval(1*time.Millisecond),
)

So(c.janitor, ShouldNotBeNil)
So(c.deleteHandler, ShouldEqual, c.deleteHandler)
Expand Down
6 changes: 3 additions & 3 deletions cache/lru_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (

func TestLRUCache(t *testing.T) {
Convey("Given new LRU cache with auto refresh", t, func() {
c := NewLRUCache(&Options{Capacity: 3, CleanupInterval: 1 * time.Millisecond}, &LRUOptions{})
c := NewLRUCache(true, WithCapacity(3), WithCleanupInterval(1*time.Millisecond))

So(c.janitor, ShouldNotBeNil)
So(c.deleteHandler, ShouldEqual, c.defaultDeleteHandler)
Expand Down Expand Up @@ -88,15 +88,15 @@ func TestLRUCache(t *testing.T) {
So(exp, ShouldBeLessThan, c.valueMap["key1"].(*Item).expiration)
})
Convey("Get with autorefresh disabled - doesn't refresh expiration time", func() {
c.lruOptions.AutoRefresh = false
c.autoRefresh = false
exp := c.valueMap["key1"].(*Item).expiration
So(c.valuesList.Back().Value.(*valuesItem).key, ShouldNotEqual, "key1")
c.Get("key1")
So(c.valuesList.Back().Value.(*valuesItem).key, ShouldNotEqual, "key1")
So(exp, ShouldEqual, c.valueMap["key1"].(*Item).expiration)
})
Convey("Refresh refreshes expiration time and moves element to back of LRU", func() {
c.lruOptions.AutoRefresh = false
c.autoRefresh = false
exp := c.valueMap["key1"].(*Item).expiration
So(c.valuesList.Back().Value.(*valuesItem).key, ShouldNotEqual, "key1")
c.Refresh("key1")
Expand Down
2 changes: 1 addition & 1 deletion celery/celery_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/mock"

"github.com/Syncano/pkg-go/celery/mocks"
"github.com/Syncano/pkg-go/v2/celery/mocks"
)

var err = errors.New("some error")
Expand Down
4 changes: 2 additions & 2 deletions database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"github.com/go-pg/pg/v9"
"go.uber.org/zap"

"github.com/Syncano/pkg-go/log"
"github.com/Syncano/pkg-go/util"
"github.com/Syncano/pkg-go/v2/log"
"github.com/Syncano/pkg-go/v2/util"
)

type key int
Expand Down
2 changes: 1 addition & 1 deletion database/manager/live_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package manager
import (
"github.com/go-pg/pg/v9/orm"

"github.com/Syncano/pkg-go/database"
"github.com/Syncano/pkg-go/v2/database"
)

// LiveManager defines a manager with live functionality.
Expand Down
2 changes: 1 addition & 1 deletion database/manager/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"github.com/go-pg/pg/v9"
"github.com/go-pg/pg/v9/orm"

"github.com/Syncano/pkg-go/database"
"github.com/Syncano/pkg-go/v2/database"
)

// Manager defines object manager.
Expand Down
2 changes: 1 addition & 1 deletion database/manager/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"github.com/go-pg/pg/v9"
"github.com/go-pg/pg/v9/orm"

"github.com/Syncano/pkg-go/util"
"github.com/Syncano/pkg-go/v2/util"
)

// Lock performs query with locking of rows for update.
Expand Down
4 changes: 2 additions & 2 deletions echo_middleware/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
"github.com/labstack/echo/v4"
"go.uber.org/zap"

"github.com/Syncano/pkg-go/log"
"github.com/Syncano/pkg-go/util"
"github.com/Syncano/pkg-go/v2/log"
"github.com/Syncano/pkg-go/v2/util"
)

const ContextRequestID = "req_id"
Expand Down
19 changes: 9 additions & 10 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
module github.com/Syncano/pkg-go
module github.com/Syncano/pkg-go/v2

go 1.14

require (
cloud.google.com/go/storage v1.10.0
github.com/TheZeroSlave/zapsentry v1.4.0
github.com/TheZeroSlave/zapsentry v1.4.1
github.com/alexandrevicenzi/unchained v1.3.0
github.com/aws/aws-sdk-go v1.33.3
github.com/aws/aws-sdk-go v1.33.15
github.com/cloudfoundry/gosigar v1.1.0
github.com/getsentry/sentry-go v0.6.1
github.com/getsentry/sentry-go v0.7.0
github.com/go-pg/pg/v9 v9.1.6
github.com/go-redis/cache/v7 v7.0.2
github.com/go-redis/redis/v7 v7.4.0
github.com/google/uuid v1.1.1 // indirect
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect
github.com/hashicorp/yamux v0.0.0-20200609203250-aecfd211c9ce
github.com/hnakamur/zap-ltsv v0.0.0-20170731143423-10a3dd1d839c
github.com/imdario/mergo v0.3.9
github.com/jackc/pgtype v1.4.0
github.com/jackc/pgx/v4 v4.7.1 // indirect
github.com/jackc/pgtype v1.4.2
github.com/jackc/pgx/v4 v4.8.1 // indirect
github.com/json-iterator/go v1.1.10
github.com/juju/ratelimit v1.0.1
github.com/labstack/echo/v4 v4.1.16
Expand All @@ -34,8 +33,8 @@ require (
github.com/vmihailenco/msgpack/v4 v4.3.12
go.opencensus.io v0.22.4
go.uber.org/zap v1.15.0
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
golang.org/x/tools v0.0.0-20200707134715-9e0a013e855f
google.golang.org/api v0.28.0
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7
google.golang.org/api v0.29.0
google.golang.org/grpc v1.30.0
)
Loading

0 comments on commit 1ebb215

Please sign in to comment.