-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #48 from suborbital/connor/cache
Add cache to Ctx
- Loading branch information
Showing
7 changed files
with
207 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package hive | ||
|
||
import ( | ||
"sync" | ||
"time" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
// ErrCacheKeyNotFound is returned when a non-existent cache key is requested | ||
var ErrCacheKeyNotFound = errors.New("key not found") | ||
|
||
// Cache represents access to a persistent cache | ||
type Cache interface { | ||
Set(key string, val []byte, ttl int) error | ||
Get(key string) ([]byte, error) | ||
Delete(key string) error | ||
} | ||
|
||
// memoryCache is a "default" cache implementation for Hive | ||
type memoryCache struct { | ||
values map[string]*uniqueVal | ||
|
||
lock sync.RWMutex | ||
} | ||
|
||
// this is used to 1) allow pointers and 2) ensure checks for unique values are cheaper (pointer equality) | ||
type uniqueVal struct { | ||
val []byte | ||
} | ||
|
||
func newMemoryCache() *memoryCache { | ||
m := &memoryCache{ | ||
values: make(map[string]*uniqueVal), | ||
lock: sync.RWMutex{}, | ||
} | ||
|
||
return m | ||
} | ||
|
||
func (m *memoryCache) Set(key string, val []byte, ttl int) error { | ||
m.lock.Lock() | ||
defer m.lock.Unlock() | ||
|
||
uVal := &uniqueVal{ | ||
val: val, | ||
} | ||
|
||
m.values[key] = uVal | ||
|
||
if ttl > 0 { | ||
go func() { | ||
<-time.After(time.Second * time.Duration(ttl)) | ||
|
||
m.lock.Lock() | ||
defer m.lock.Unlock() | ||
|
||
currentVal := m.values[key] | ||
if currentVal == uVal { | ||
delete(m.values, key) | ||
} | ||
}() | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (m *memoryCache) Get(key string) ([]byte, error) { | ||
m.lock.RLock() | ||
defer m.lock.RUnlock() | ||
|
||
uVal, exists := m.values[key] | ||
if !exists { | ||
return nil, ErrCacheKeyNotFound | ||
} | ||
|
||
return uVal.val, nil | ||
} | ||
|
||
func (m *memoryCache) Delete(key string) error { | ||
m.lock.Lock() | ||
defer m.lock.Unlock() | ||
|
||
_, exists := m.values[key] | ||
if !exists { | ||
return nil | ||
} | ||
|
||
delete(m.values, key) | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package hive | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
|
||
"github.com/pkg/errors" | ||
) | ||
|
||
type setTester struct{} | ||
|
||
func (c *setTester) Run(job Job, ctx *Ctx) (interface{}, error) { | ||
data := job.Bytes() | ||
|
||
if err := ctx.Cache.Set("important", data, 1); err != nil { | ||
return nil, err | ||
} | ||
|
||
return nil, nil | ||
} | ||
|
||
// OnChange runs on worker changes | ||
func (c *setTester) OnChange(_ ChangeEvent) error { | ||
return nil | ||
} | ||
|
||
type getTester struct{} | ||
|
||
func (c *getTester) Run(job Job, ctx *Ctx) (interface{}, error) { | ||
key := job.String() | ||
|
||
val, err := ctx.Cache.Get(key) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return string(val), nil | ||
} | ||
|
||
// OnChange runs on worker changes | ||
func (c *getTester) OnChange(_ ChangeEvent) error { | ||
return nil | ||
} | ||
|
||
func TestCacheGetSet(t *testing.T) { | ||
h := New() | ||
h.Handle("set", &setTester{}) | ||
h.Handle("get", &getTester{}) | ||
|
||
_, err := h.Do(NewJob("set", "very important information")).Then() | ||
if err != nil { | ||
t.Error(errors.Wrap(err, "failed to set")) | ||
return | ||
} | ||
|
||
val, err := h.Do(NewJob("get", "important")).Then() | ||
if err != nil { | ||
t.Error(errors.Wrap(err, "get job failed")) | ||
return | ||
} | ||
|
||
if val.(string) != "very important information" { | ||
t.Error("result did not match expected 'very important information': ", val.(string)) | ||
} | ||
} | ||
|
||
func TestCacheGetSetWithTTL(t *testing.T) { | ||
h := New() | ||
h.Handle("set", &setTester{}) | ||
h.Handle("get", &getTester{}) | ||
|
||
_, err := h.Do(NewJob("set", "very important information")).Then() | ||
if err != nil { | ||
t.Error(errors.Wrap(err, "failed to set")) | ||
return | ||
} | ||
|
||
<-time.After(time.Second * 2) | ||
|
||
_, err = h.Do(NewJob("get", "important")).Then() | ||
if err == nil { | ||
t.Error("should have errored, did not") | ||
return | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters