physical: Adding simple LRU write-through cache
This commit is contained in:
parent
c1bfd5ccdd
commit
30dcb99ba3
75
physical/cache.go
Normal file
75
physical/cache.go
Normal file
|
@ -0,0 +1,75 @@
|
|||
package physical
|
||||
|
||||
import "github.com/hashicorp/golang-lru"
|
||||
|
||||
const (
|
||||
// DefaultCacheSize is used if no cache size is specified
|
||||
// for NewPhysicalCache
|
||||
DefaultCacheSize = 32 * 1024
|
||||
)
|
||||
|
||||
// PhysicalCache is used to wrap an underlying physical backend
|
||||
// and provide an LRU cache layer on top. Most of the reads done by
|
||||
// Vault are for policy objects so there is a large read reduction
|
||||
// by using a simple write-through cache.
|
||||
type PhysicalCache struct {
|
||||
backend Backend
|
||||
lru *lru.Cache
|
||||
}
|
||||
|
||||
// NewPhysicalCache returns a physical cache of the given size.
|
||||
// If no size is provided, the default size is used.
|
||||
func NewPhysicalCache(b Backend, size int) *PhysicalCache {
|
||||
if size <= 0 {
|
||||
size = DefaultCacheSize
|
||||
}
|
||||
cache, _ := lru.New(size)
|
||||
c := &PhysicalCache{
|
||||
backend: b,
|
||||
lru: cache,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Purge is used to clear the cache
|
||||
func (c *PhysicalCache) Purge() {
|
||||
c.lru.Purge()
|
||||
}
|
||||
|
||||
func (c *PhysicalCache) Put(entry *Entry) error {
|
||||
err := c.backend.Put(entry)
|
||||
c.lru.Add(entry.Key, entry)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PhysicalCache) Get(key string) (*Entry, error) {
|
||||
// Check the LRU first
|
||||
if raw, ok := c.lru.Get(key); ok {
|
||||
if raw == nil {
|
||||
return nil, nil
|
||||
} else {
|
||||
return raw.(*Entry), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Read from the underlying backend
|
||||
ent, err := c.backend.Get(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Cache the result
|
||||
c.lru.Add(key, ent)
|
||||
return ent, err
|
||||
}
|
||||
|
||||
func (c *PhysicalCache) Delete(key string) error {
|
||||
err := c.backend.Delete(key)
|
||||
c.lru.Remove(key)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *PhysicalCache) List(prefix string) ([]string, error) {
|
||||
// Always pass-through as this would be difficult to cache.
|
||||
return c.backend.List(prefix)
|
||||
}
|
48
physical/cache_test.go
Normal file
48
physical/cache_test.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package physical
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
inm := NewInmem()
|
||||
cache := NewPhysicalCache(inm, 0)
|
||||
testBackend(t, cache)
|
||||
testBackend_ListPrefix(t, cache)
|
||||
}
|
||||
|
||||
func TestCache_Purge(t *testing.T) {
|
||||
inm := NewInmem()
|
||||
cache := NewPhysicalCache(inm, 0)
|
||||
|
||||
ent := &Entry{
|
||||
Key: "foo",
|
||||
Value: []byte("bar"),
|
||||
}
|
||||
err := cache.Put(ent)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Delete from under
|
||||
inm.Delete("foo")
|
||||
|
||||
// Read should work
|
||||
out, err := cache.Get("foo")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if out == nil {
|
||||
t.Fatalf("should have key")
|
||||
}
|
||||
|
||||
// Clear the cache
|
||||
cache.Purge()
|
||||
|
||||
// Read should fail
|
||||
out, err = cache.Get("foo")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if out != nil {
|
||||
t.Fatalf("should not have key")
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue