[perf] Add an interface for an LRU cache.
Also includes an implementation using golang-lru.
Change-Id: Iafc2e0eb11b486f3e4006f75b9135eae5f00385c
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/305598
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Commit-Queue: Joe Gregorio <jcgregorio@google.com>
diff --git a/perf/go/cache/cache.go b/perf/go/cache/cache.go
new file mode 100644
index 0000000..d7e71b8
--- /dev/null
+++ b/perf/go/cache/cache.go
@@ -0,0 +1,15 @@
+// Package cache defines an interface for an LRU cache.
+package cache
+
+// Cache in an interface for an LRU cache.
+type Cache interface {
+ // Add adds a value to the cache.
+ Add(key string, value interface{})
+
+ // Get looks up a key's value from the cache, returning the value and true
+ // if found, otherwise the returned bool is false.
+ Get(key string) (interface{}, bool)
+
+ // Exists returns true if the key is found in the cache.
+ Exists(key string) bool
+}
diff --git a/perf/go/cache/local/local.go b/perf/go/cache/local/local.go
new file mode 100644
index 0000000..c44264d
--- /dev/null
+++ b/perf/go/cache/local/local.go
@@ -0,0 +1,42 @@
+// Package local implements cache.Cache with an in-memory cache.
+package local
+
+import (
+ lru "github.com/hashicorp/golang-lru"
+ "go.skia.org/infra/go/skerr"
+ "go.skia.org/infra/perf/go/cache"
+)
+
+// Cache implements the cache.Cache interface.
+type Cache struct {
+ cache *lru.Cache
+}
+
+// New returns a new in-memory cache of the given size.
+func New(size int) (*Cache, error) {
+ c, err := lru.New(size)
+ if err != nil {
+ return nil, skerr.Wrapf(err, "failed to create local cache of size: %d", size)
+ }
+ return &Cache{
+ cache: c,
+ }, nil
+}
+
+// Add implements the cache.Cache interface.
+func (c *Cache) Add(key string, value interface{}) {
+ _ = c.cache.Add(key, value)
+}
+
+// Get implements the cache.Cache interface.
+func (c *Cache) Get(key string) (interface{}, bool) {
+ return c.cache.Get(key)
+}
+
+// Exists implements the cache.Cache interface.
+func (c *Cache) Exists(key string) bool {
+ return c.cache.Contains(key)
+}
+
+// Confirm we implement the interface.
+var _ cache.Cache = (*Cache)(nil)
diff --git a/perf/go/cache/local/local_test.go b/perf/go/cache/local/local_test.go
new file mode 100644
index 0000000..39e8e8c
--- /dev/null
+++ b/perf/go/cache/local/local_test.go
@@ -0,0 +1,57 @@
+package local
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ "go.skia.org/infra/go/testutils/unittest"
+)
+
+func TestCache_New_Failure(t *testing.T) {
+ unittest.SmallTest(t)
+ _, err := New(-12)
+ require.Error(t, err)
+}
+
+func TestCache_Get_Success(t *testing.T) {
+ unittest.SmallTest(t)
+ c, err := New(12)
+ require.NoError(t, err)
+
+ c.Add("foo", "bar")
+ got, ok := c.Get("foo")
+ assert.True(t, ok)
+ assert.Equal(t, "bar", got.(string))
+
+ _, ok = c.Get("quux")
+ assert.False(t, ok)
+}
+
+func TestCache_Get_FalseOnMiss(t *testing.T) {
+ unittest.SmallTest(t)
+ c, err := New(12)
+ require.NoError(t, err)
+
+ _, ok := c.Get("quux")
+ assert.False(t, ok)
+}
+
+func TestCache_Exists_Success(t *testing.T) {
+ unittest.SmallTest(t)
+ c, err := New(12)
+ require.NoError(t, err)
+
+ c.Add("foo", "bar")
+ ok := c.Exists("foo")
+ assert.True(t, ok)
+}
+
+func TestCache_Exists_FalseOnMiss(t *testing.T) {
+ unittest.SmallTest(t)
+ c, err := New(12)
+ require.NoError(t, err)
+
+ ok := c.Exists("foo")
+ assert.False(t, ok)
+}