Add cache for mounts

This change adds a cache to the mounts type. This means that if called to get
a list of folders, for example, the result is reused instead of recalculated.
This also avoids duplicate logging.

Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
Evan Lezar 2022-04-05 09:35:27 +02:00
parent d970d0a627
commit 9c3c8e038a
4 changed files with 29 additions and 15 deletions

View File

@ -119,7 +119,7 @@ func newFromMountSpecs(logger *logrus.Logger, locators map[csv.MountSpecType]loo
// Mounts returns the discovered mounts for the csvDiscoverer. // Mounts returns the discovered mounts for the csvDiscoverer.
// Note that if the discoverer is for the device MountSpecType, the list of mounts is empty. // Note that if the discoverer is for the device MountSpecType, the list of mounts is empty.
func (d csvDiscoverer) Mounts() ([]Mount, error) { func (d *csvDiscoverer) Mounts() ([]Mount, error) {
if d.mountType == csv.MountSpecDev { if d.mountType == csv.MountSpecDev {
return d.None.Mounts() return d.None.Mounts()
} }
@ -129,7 +129,7 @@ func (d csvDiscoverer) Mounts() ([]Mount, error) {
// Devices returns the discovered devices for the csvDiscoverer. // Devices returns the discovered devices for the csvDiscoverer.
// Note that if the discoverer is not for the device MountSpecType, the list of devices is empty. // Note that if the discoverer is not for the device MountSpecType, the list of devices is empty.
func (d csvDiscoverer) Devices() ([]Device, error) { func (d *csvDiscoverer) Devices() ([]Device, error) {
if d.mountType != csv.MountSpecDev { if d.mountType != csv.MountSpecDev {
return d.None.Devices() return d.None.Devices()
} }

View File

@ -31,7 +31,7 @@ func TestCSVDiscoverer(t *testing.T) {
testCases := []struct { testCases := []struct {
description string description string
input csvDiscoverer input *csvDiscoverer
expectedMounts []Mount expectedMounts []Mount
expectedMountsError error expectedMountsError error
expectedDevicesError error expectedDevicesError error
@ -39,7 +39,7 @@ func TestCSVDiscoverer(t *testing.T) {
}{ }{
{ {
description: "dev mounts are empty", description: "dev mounts are empty",
input: csvDiscoverer{ input: &csvDiscoverer{
mounts: mounts{ mounts: mounts{
lookup: &lookup.LocatorMock{ lookup: &lookup.LocatorMock{
LocateFunc: func(string) ([]string, error) { LocateFunc: func(string) ([]string, error) {
@ -54,14 +54,14 @@ func TestCSVDiscoverer(t *testing.T) {
}, },
{ {
description: "dev devices returns error for nil lookup", description: "dev devices returns error for nil lookup",
input: csvDiscoverer{ input: &csvDiscoverer{
mountType: "dev", mountType: "dev",
}, },
expectedDevicesError: fmt.Errorf("no lookup defined"), expectedDevicesError: fmt.Errorf("no lookup defined"),
}, },
{ {
description: "lib devices are empty", description: "lib devices are empty",
input: csvDiscoverer{ input: &csvDiscoverer{
mounts: mounts{ mounts: mounts{
lookup: &lookup.LocatorMock{ lookup: &lookup.LocatorMock{
LocateFunc: func(string) ([]string, error) { LocateFunc: func(string) ([]string, error) {
@ -76,7 +76,7 @@ func TestCSVDiscoverer(t *testing.T) {
}, },
{ {
description: "lib mounts returns error for nil lookup", description: "lib mounts returns error for nil lookup",
input: csvDiscoverer{ input: &csvDiscoverer{
mountType: "lib", mountType: "lib",
}, },
expectedMountsError: fmt.Errorf("no lookup defined"), expectedMountsError: fmt.Errorf("no lookup defined"),

View File

@ -18,6 +18,7 @@ package discover
import ( import (
"fmt" "fmt"
"sync"
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -31,15 +32,25 @@ type mounts struct {
logger *logrus.Logger logger *logrus.Logger
lookup lookup.Locator lookup lookup.Locator
required []string required []string
sync.Mutex
cache []Mount
} }
var _ Discover = (*mounts)(nil) var _ Discover = (*mounts)(nil)
func (d mounts) Mounts() ([]Mount, error) { func (d *mounts) Mounts() ([]Mount, error) {
if d.lookup == nil { if d.lookup == nil {
return nil, fmt.Errorf("no lookup defined") return nil, fmt.Errorf("no lookup defined")
} }
if d.cache != nil {
d.logger.Debugf("returning cached mounts")
return d.cache, nil
}
d.Lock()
defer d.Unlock()
paths := make(map[string]bool) paths := make(map[string]bool)
for _, candidate := range d.required { for _, candidate := range d.required {
@ -68,5 +79,7 @@ func (d mounts) Mounts() ([]Mount, error) {
mounts = append(mounts, mount) mounts = append(mounts, mount)
} }
d.cache = mounts
return mounts, nil return mounts, nil
} }

View File

@ -41,16 +41,17 @@ func TestMounts(t *testing.T) {
description string description string
expectedError error expectedError error
expectedMounts []Mount expectedMounts []Mount
input mounts input *mounts
}{ }{
{ {
description: "nill lookup returns error", description: "nill lookup returns error",
expectedError: fmt.Errorf("no lookup defined"), expectedError: fmt.Errorf("no lookup defined"),
input: &mounts{},
}, },
{ {
description: "empty required returns no mounts", description: "empty required returns no mounts",
expectedError: nil, expectedError: nil,
input: mounts{ input: &mounts{
lookup: &lookup.LocatorMock{ lookup: &lookup.LocatorMock{
LocateFunc: func(string) ([]string, error) { LocateFunc: func(string) ([]string, error) {
return []string{"located"}, nil return []string{"located"}, nil
@ -61,7 +62,7 @@ func TestMounts(t *testing.T) {
{ {
description: "required returns located", description: "required returns located",
expectedError: nil, expectedError: nil,
input: mounts{ input: &mounts{
lookup: &lookup.LocatorMock{ lookup: &lookup.LocatorMock{
LocateFunc: func(string) ([]string, error) { LocateFunc: func(string) ([]string, error) {
return []string{"located"}, nil return []string{"located"}, nil
@ -74,7 +75,7 @@ func TestMounts(t *testing.T) {
{ {
description: "mounts removes located duplicates", description: "mounts removes located duplicates",
expectedError: nil, expectedError: nil,
input: mounts{ input: &mounts{
lookup: &lookup.LocatorMock{ lookup: &lookup.LocatorMock{
LocateFunc: func(string) ([]string, error) { LocateFunc: func(string) ([]string, error) {
return []string{"located"}, nil return []string{"located"}, nil
@ -86,7 +87,7 @@ func TestMounts(t *testing.T) {
}, },
{ {
description: "mounts skips located errors", description: "mounts skips located errors",
input: mounts{ input: &mounts{
lookup: &lookup.LocatorMock{ lookup: &lookup.LocatorMock{
LocateFunc: func(s string) ([]string, error) { LocateFunc: func(s string) ([]string, error) {
if s == "error" { if s == "error" {
@ -101,7 +102,7 @@ func TestMounts(t *testing.T) {
}, },
{ {
description: "mounts skips unlocated", description: "mounts skips unlocated",
input: mounts{ input: &mounts{
lookup: &lookup.LocatorMock{ lookup: &lookup.LocatorMock{
LocateFunc: func(s string) ([]string, error) { LocateFunc: func(s string) ([]string, error) {
if s == "empty" { if s == "empty" {
@ -116,7 +117,7 @@ func TestMounts(t *testing.T) {
}, },
{ {
description: "mounts skips unlocated", description: "mounts skips unlocated",
input: mounts{ input: &mounts{
lookup: &lookup.LocatorMock{ lookup: &lookup.LocatorMock{
LocateFunc: func(s string) ([]string, error) { LocateFunc: func(s string) ([]string, error) {
if s == "multiple" { if s == "multiple" {