1package physical
2
3import (
4	"strings"
5
6	"github.com/hashicorp/golang-lru"
7)
8
9const (
10	// DefaultCacheSize is used if no cache size is specified for NewCache
11	DefaultCacheSize = 32 * 1024
12)
13
14// Cache is used to wrap an underlying physical backend
15// and provide an LRU cache layer on top. Most of the reads done by
16// Vault are for policy objects so there is a large read reduction
17// by using a simple write-through cache.
18type Cache struct {
19	backend Backend
20	lru     *lru.TwoQueueCache
21}
22
23// NewCache returns a physical cache of the given size.
24// If no size is provided, the default size is used.
25func NewCache(b Backend, size int) *Cache {
26	if size <= 0 {
27		size = DefaultCacheSize
28	}
29	cache, _ := lru.New2Q(size)
30	c := &Cache{
31		backend: b,
32		lru:     cache,
33	}
34	return c
35}
36
37// Purge is used to clear the cache
38func (c *Cache) Purge() {
39	c.lru.Purge()
40}
41
42func (c *Cache) Put(entry *Entry) error {
43	err := c.backend.Put(entry)
44	c.lru.Add(entry.Key, entry)
45	return err
46}
47
48func (c *Cache) Get(key string) (*Entry, error) {
49	// Check the LRU first
50	if raw, ok := c.lru.Get(key); ok {
51		if raw == nil {
52			return nil, nil
53		} else {
54			return raw.(*Entry), nil
55		}
56	}
57
58	// Read from the underlying backend
59	ent, err := c.backend.Get(key)
60	if err != nil {
61		return nil, err
62	}
63
64	// Cache the result. We do NOT cache negative results
65	// for keys in the 'core/' prefix otherwise we risk certain
66	// race conditions upstream. The primary issue is with the HA mode,
67	// we could potentially negatively cache the leader entry and cause
68	// leader discovery to fail.
69	if ent != nil || !strings.HasPrefix(key, "core/") {
70		c.lru.Add(key, ent)
71	}
72	return ent, err
73}
74
75func (c *Cache) Delete(key string) error {
76	err := c.backend.Delete(key)
77	c.lru.Remove(key)
78	return err
79}
80
81func (c *Cache) List(prefix string) ([]string, error) {
82	// Always pass-through as this would be difficult to cache.
83	return c.backend.List(prefix)
84}
85