From 72099f2888ba5d69981992ba22edf4549eff2239 Mon Sep 17 00:00:00 2001 From: Jon Lee Date: Tue, 14 Jun 2022 16:29:08 +0800 Subject: [PATCH] feat: add increment/decrement in cache --- cache/memory_store.go | 73 +++++++++++++++++++++++++++++++++++++++++++ cache/redis_store.go | 35 +++++++++++++++++++++ cache/repository.go | 15 +++++++++ cache/store.go | 10 +++++- go.mod | 4 +-- go.sum | 12 +++---- 6 files changed, 140 insertions(+), 9 deletions(-) diff --git a/cache/memory_store.go b/cache/memory_store.go index 112ca12..ebf8457 100644 --- a/cache/memory_store.go +++ b/cache/memory_store.go @@ -85,6 +85,54 @@ func (s *MemoryStore) Put(key string, val interface{}, timeout time.Duration) er return nil } +// Increment the value of an item in the cache. +func (s *MemoryStore) Increment(key string, value ...int) (int, error) { + s.mu.RLock() + defer s.mu.RUnlock() + + var by = 1 + if len(value) > 0 { + by = value[0] + } + + exist, ok := s.items[s.prefix+key] + if !ok { + s.items[s.prefix+key] = item{ + Object: 1 + by, + } + } else { + by = exist.Object.(int) + by + exist.Object = by + s.items[s.prefix+key] = exist + } + + return by, nil +} + +// Decrement the value of an item in the cache. +func (s *MemoryStore) Decrement(key string, value ...int) (int, error) { + s.mu.RLock() + defer s.mu.RUnlock() + + var by = 1 + if len(value) > 0 { + by = value[0] + } + + exist, ok := s.items[s.prefix+key] + if !ok { + s.items[s.prefix+key] = item{ + Object: 0 - by, + } + } else { + by = exist.Object.(int) - by + exist.Object = by + s.items[s.prefix+key] = exist + } + + return by, nil +} + // Exist check cache's existence in memory. func (s *MemoryStore) Exist(key string) bool { s.mu.RLock() @@ -99,6 +147,31 @@ func (s *MemoryStore) Exist(key string) bool { return ok } +// Expire set value expire time. +func (s *MemoryStore) Expire(key string, timeout time.Duration) error { + var e int64 + if timeout > 0 { + e = time.Now().Add(timeout).UnixNano() + } + + s.mu.RLock() + defer s.mu.RUnlock() + + if !s.Exist(key) { + return errors.New("key not exist") + } + + item := s.items[s.prefix+key] + item.Expiration = e + s.items[s.prefix+key] = item + + if e > 0 { + s.DeleteExpired() + } + + return nil +} + // Forget Remove an item from the cache. func (s *MemoryStore) Forget(key string) error { delete(s.items, s.prefix+key) diff --git a/cache/redis_store.go b/cache/redis_store.go index 1110ae8..9e3d6cf 100644 --- a/cache/redis_store.go +++ b/cache/redis_store.go @@ -44,6 +44,32 @@ func (s *RedisStore) Put(key string, val interface{}, timeout time.Duration) err return err } +// Increment the value of an item in the cache. +func (s *RedisStore) Increment(key string, value ...int) (int, error) { + c := s.pool.Get() + defer c.Close() + + var by = 1 + if len(value) > 0 { + by = value[0] + } + + return redis.Int(c.Do("INCRBY", s.prefix+key, by)) +} + +// Decrement the value of an item in the cache. +func (s *RedisStore) Decrement(key string, value ...int) (int, error) { + c := s.pool.Get() + defer c.Close() + + var by = 1 + if len(value) > 0 { + by = value[0] + } + + return redis.Int(c.Do("DECRBY", s.prefix+key, by)) +} + // Exist check cache's existence in redis. func (s *RedisStore) Exist(key string) bool { c := s.pool.Get() @@ -55,6 +81,15 @@ func (s *RedisStore) Exist(key string) bool { return v } +// Expire set value expire time. +func (s *RedisStore) Expire(key string, timeout time.Duration) error { + c := s.pool.Get() + defer c.Close() + _, err := c.Do("EXPIRE", s.prefix+key, int64(timeout/time.Second)) + + return err +} + // Forget Remove an item from the cache. func (s *RedisStore) Forget(key string) error { c := s.pool.Get() diff --git a/cache/repository.go b/cache/repository.go index dabb9b1..30cf2fb 100644 --- a/cache/repository.go +++ b/cache/repository.go @@ -56,6 +56,21 @@ func (r *Repository) Add(key string, val interface{}, timeout time.Duration) err return r.store.Put(key, val, timeout) } +// Increment the value of an item in the cache. +func (r *Repository) Increment(key string, value ...int) (int, error) { + return r.store.Increment(key, value...) +} + +// Decrement the value of an item in the cache. +func (r *Repository) Decrement(key string, value ...int) (int, error) { + return r.store.Decrement(key, value...) +} + +// Expire set value expire time. +func (r *Repository) Expire(key string, timeout time.Duration) error { + return r.store.Expire(key, timeout) +} + // Remember Get an item from the cache, or store the default value. func (r *Repository) Remember(key string, val interface{}, timeout time.Duration, callback func() interface{}) error { err := r.Get(key, val) diff --git a/cache/store.go b/cache/store.go index 76d713a..f2795a8 100644 --- a/cache/store.go +++ b/cache/store.go @@ -11,9 +11,18 @@ type Store interface { // Put set cached value with key and expire time. Put(key string, val interface{}, timeout time.Duration) error + // Increment the value of an item in the cache. + Increment(key string, value ...int) (int, error) + + // Decrement the value of an item in the cache. + Decrement(key string, value ...int) (int, error) + // Exist check cache's existence in redis. Exist(key string) bool + // Expire set value expire time. + Expire(key string, timeout time.Duration) error + // Forget Remove an item from the cache. Forget(key string) error @@ -23,4 +32,3 @@ type Store interface { // TTL get the ttl of the key. TTL(key string) (int64, error) } - diff --git a/go.mod b/go.mod index dd790cd..e6e3961 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,6 @@ module github.com/forgoer/thinkgo go 1.14 require ( - github.com/gomodule/redigo v2.0.0+incompatible - github.com/stretchr/testify v1.5.1 + github.com/gomodule/redigo v1.8.8 + github.com/stretchr/testify v1.7.0 ) diff --git a/go.sum b/go.sum index 5ae6d18..bc94f23 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,13 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= -github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/gomodule/redigo v1.8.8 h1:f6cXq6RRfiyrOJEV7p3JhLDlmawGBVBBP1MggY8Mo4E= +github.com/gomodule/redigo v1.8.8/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=