physical: Adding simple LRU write-through cache

This commit is contained in:
Armon Dadgar 2015-04-14 11:00:51 -07:00
parent c1bfd5ccdd
commit 30dcb99ba3
2 changed files with 123 additions and 0 deletions

75
physical/cache.go Normal file
View 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
View 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")
}
}