cmd/frontend: add a cache for vuln data
The vulndb.Client already supports caching; we just have to supply an
implementation.
The only implementation in golang.org/x/vulndb uses the filesystem, so
we can't use it on App Engine. Provide an in-memory implementation
instead.
For golang/go#48223
Change-Id: I0431921dcabfb5546350dff095ae6aa5668ad892
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/347969
Trust: Jonathan Amsterdam <jba@google.com>
Run-TryBot: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/cmd/frontend/main.go b/cmd/frontend/main.go
index 04bf2b5..2bd0679 100644
--- a/cmd/frontend/main.go
+++ b/cmd/frontend/main.go
@@ -105,7 +105,9 @@
}
rc := cmdconfig.ReportingClient(ctx, cfg)
- vc, err := vulndbc.NewClient([]string{cfg.VulnDB}, vulndbc.Options{})
+ vc, err := vulndbc.NewClient([]string{cfg.VulnDB}, vulndbc.Options{
+ HTTPCache: newVulndbCache(),
+ })
if err != nil {
log.Fatalf(ctx, "vulndbc.NewClient: %v", err)
}
diff --git a/cmd/frontend/vulndb_cache.go b/cmd/frontend/vulndb_cache.go
new file mode 100644
index 0000000..eec5d38
--- /dev/null
+++ b/cmd/frontend/vulndb_cache.go
@@ -0,0 +1,93 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "sync"
+ "time"
+
+ lru "github.com/hashicorp/golang-lru"
+ "golang.org/x/vulndb/osv"
+)
+
+// vulndbCache implements the golang.org/x/vulndb/client.Cache interface. It
+// stores in memory the index and a limited number of path entries for one DB.
+type vulndbCache struct {
+ mu sync.Mutex
+ dbName string // support only one DB
+ index osv.DBIndex
+ retrieved time.Time
+ entryCache *lru.Cache
+}
+
+func newVulndbCache() *vulndbCache {
+ const size = 100
+ ec, err := lru.New(size)
+ if err != nil {
+ // Can only happen if size is bad, and we control it.
+ panic(err)
+ }
+ return &vulndbCache{entryCache: ec}
+}
+
+// ReadIndex returns the index for dbName from the cache, or returns zero values
+// if it is not present.
+func (c *vulndbCache) ReadIndex(dbName string) (osv.DBIndex, time.Time, error) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ if err := c.checkDB(dbName); err != nil {
+ return nil, time.Time{}, err
+ }
+ return c.index, c.retrieved, nil
+}
+
+// WriteIndex puts the index and retrieved time into the cache.
+func (c *vulndbCache) WriteIndex(dbName string, index osv.DBIndex, retrieved time.Time) error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ if err := c.checkDB(dbName); err != nil {
+ return err
+ }
+ c.index = index
+ c.retrieved = retrieved
+ return nil
+}
+
+// ReadEntries returns the vulndb entries for path from the cache, or
+// nil if not prsent.
+func (c *vulndbCache) ReadEntries(dbName, path string) ([]*osv.Entry, error) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ if err := c.checkDB(dbName); err != nil {
+ return nil, err
+ }
+ if entries, ok := c.entryCache.Get(path); ok {
+ return entries.([]*osv.Entry), nil
+ }
+ return nil, nil
+}
+
+// WriteEntries puts the entries for path into the cache.
+func (c *vulndbCache) WriteEntries(dbName, path string, entries []*osv.Entry) error {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ if err := c.checkDB(dbName); err != nil {
+ return err
+ }
+ c.entryCache.Add(path, entries)
+ return nil
+}
+
+func (c *vulndbCache) checkDB(name string) error {
+ if c.dbName == "" {
+ c.dbName = name
+ return nil
+ }
+ if c.dbName != name {
+ return fmt.Errorf("vulndbCache: called with db name %q, expected %q", name, c.dbName)
+ }
+ return nil
+}