From 0e5a5e1e540e51ce94f98a019c9a9635b12d4ed2 Mon Sep 17 00:00:00 2001 From: Robert Graeff Date: Wed, 12 Jun 2024 15:29:44 +0200 Subject: [PATCH] Remove cache (run-int-tests) --- pkg/components/cache/cache.go | 262 ---------------- pkg/components/cache/filesystem.go | 489 ----------------------------- pkg/components/cache/inmemory.go | 49 --- pkg/components/cache/metrics.go | 107 ------- pkg/components/cache/types.go | 175 ----------- pkg/metrics/metrics.go | 6 - 6 files changed, 1088 deletions(-) delete mode 100644 pkg/components/cache/cache.go delete mode 100644 pkg/components/cache/filesystem.go delete mode 100644 pkg/components/cache/inmemory.go delete mode 100644 pkg/components/cache/metrics.go delete mode 100644 pkg/components/cache/types.go diff --git a/pkg/components/cache/cache.go b/pkg/components/cache/cache.go deleted file mode 100644 index 15b146210..000000000 --- a/pkg/components/cache/cache.go +++ /dev/null @@ -1,262 +0,0 @@ -// SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors. -// -// SPDX-License-Identifier: Apache-2.0 - -package cache - -import ( - "errors" - "fmt" - "io" - "os" - "sync" - - "github.com/go-logr/logr" - "github.com/mandelsoft/vfs/pkg/memoryfs" - "github.com/mandelsoft/vfs/pkg/osfs" - "github.com/mandelsoft/vfs/pkg/projectionfs" - "github.com/mandelsoft/vfs/pkg/vfs" - ocispecv1 "github.com/opencontainers/image-spec/specs-go/v1" -) - -type layeredCache struct { - log logr.Logger - mux sync.RWMutex - - baseFs *FileSystem - overlayFs *FileSystem -} - -// NewCache creates a new cache with the given options. -// It uses by default a tmp fs -func NewCache(log logr.Logger, options ...Option) (*layeredCache, error) { - opts := &Options{} - opts = opts.ApplyOptions(options) - opts.ApplyDefaults() - - if err := initBasePath(opts); err != nil { - return nil, err - } - - base, err := projectionfs.New(osfs.New(), opts.BasePath) - if err != nil { - return nil, err - } - baseCFs, err := NewCacheFilesystem(log.WithName("baseCacheFS"), base, opts.BaseGCConfig) - if err != nil { - return nil, fmt.Errorf("unable to create base layer: %w", err) - } - var overlayCFs *FileSystem - if opts.InMemoryOverlay { - overlayCFs, err = NewCacheFilesystem(log.WithName("inMemoryCacheFS"), memoryfs.New(), opts.InMemoryGCConfig) - if err != nil { - return nil, fmt.Errorf("unable to create base layer: %w", err) - } - } - - //initialize metrics - baseCFs.WithMetrics( - CachedItems.WithLabelValues(opts.UID), - CacheDiskUsage.WithLabelValues(opts.UID), - CacheHitsDisk.WithLabelValues(opts.UID)) - if opts.InMemoryOverlay { - overlayCFs.WithMetrics(nil, - CacheMemoryUsage.WithLabelValues(opts.UID), - CacheHitsMemory.WithLabelValues(opts.UID)) - } - - return &layeredCache{ - log: log, - mux: sync.RWMutex{}, - baseFs: baseCFs, - overlayFs: overlayCFs, - }, nil -} - -func initBasePath(opts *Options) error { - if len(opts.BasePath) == 0 { - path, err := os.MkdirTemp(os.TempDir(), "ocicache") - if err != nil { - return err - } - opts.BasePath = path - } - info, err := os.Stat(opts.BasePath) - if err != nil { - if !os.IsNotExist(err) { - return err - } - if err := os.MkdirAll(opts.BasePath, os.ModePerm); err != nil { - return err - } - return nil - } - - if !info.IsDir() { - return errors.New("path has to be a directory") - } - return nil -} - -// Close implements the io.Closer interface that cleanups all resource used by the cache. -func (lc *layeredCache) Close() error { - if err := lc.baseFs.Close(); err != nil { - return err - } - if lc.overlayFs != nil { - if err := lc.overlayFs.Close(); err != nil { - return err - } - } - return nil -} - -func (lc *layeredCache) Get(desc ocispecv1.Descriptor) (io.ReadCloser, error) { - _, file, err := lc.get(Path(desc), desc) - if err != nil { - return nil, err - } - return file, nil -} - -func (lc *layeredCache) Add(desc ocispecv1.Descriptor, reader io.ReadCloser) error { - path := Path(desc) - lc.mux.Lock() - defer lc.mux.Unlock() - defer reader.Close() - - file, err := lc.baseFs.Create(path, desc.Size) - if err != nil { - return err - } - defer file.Close() - - _, err = io.Copy(file, reader) - return err -} - -func (lc *layeredCache) Info() (Info, error) { - return Info{ - Size: lc.baseFs.Size, - CurrentSize: lc.baseFs.CurrentSize(), - ItemsCount: int64(lc.baseFs.index.Len()), - }, nil -} - -func (lc *layeredCache) Prune() error { - return lc.baseFs.DeleteAll() -} - -func (lc *layeredCache) get(dgst string, desc ocispecv1.Descriptor) (os.FileInfo, vfs.File, error) { - lc.mux.RLock() - defer lc.mux.RUnlock() - - // first search in the overlayFs layer - if info, file, err := lc.getFromOverlay(dgst, desc); err == nil { - return info, file, nil - } - - info, err := lc.baseFs.Stat(dgst) - if err != nil { - if os.IsNotExist(err) { - return nil, nil, ErrNotFound - } - return nil, nil, err - } - verified, err := verifyBlob(lc.baseFs.FileSystem, info, dgst, desc) - if err != nil { - return nil, nil, fmt.Errorf("unable to verify blob: %w", err) - } - if !verified { - // remove invalid blob from cache - if err := lc.baseFs.Remove(dgst); err != nil { - lc.log.V(7).Info("unable to remove invalid blob", "digest", dgst, "err", err.Error()) - } - return info, nil, ErrNotFound - } - file, err := lc.baseFs.OpenFile(dgst, os.O_RDONLY, os.ModePerm) - if err != nil { - return nil, nil, err - } - - // copy file to in memory cache - if lc.overlayFs != nil { - overlayFile, err := lc.overlayFs.Create(dgst, info.Size()) - if err != nil { - // do not return an error here as we are only unable to write to better cache - lc.log.V(5).Info(err.Error()) - return info, file, nil - } - defer overlayFile.Close() - if _, err := io.Copy(overlayFile, file); err != nil { - // do not return an error here as we are only unable to write to better cache - lc.log.V(5).Info(err.Error()) - - // The file handle is at the end as the data was copied by io.Copy. - // Therefore the file handle is reset so that the caller can also read the data. - if _, err := file.Seek(0, io.SeekStart); err != nil { - return nil, nil, fmt.Errorf("unable to reset the file handle: %w", err) - } - return info, file, nil - } - - // The file handle is at the end as the data was copied by io.Copy. - // Therefore the file handle is reset so that the caller can also read the data. - if _, err := file.Seek(0, io.SeekStart); err != nil { - return nil, nil, fmt.Errorf("unable to reset the file handle: %w", err) - } - } - return info, file, nil -} - -func (lc *layeredCache) getFromOverlay(dgst string, desc ocispecv1.Descriptor) (os.FileInfo, vfs.File, error) { - if lc.overlayFs == nil { - return nil, nil, ErrNotFound - } - info, err := lc.overlayFs.Stat(dgst) - if err != nil { - lc.log.V(7).Info("not found in overlay cache", "digest", dgst, "err", err.Error()) - return nil, nil, ErrNotFound - } - - verified, err := verifyBlob(lc.overlayFs.FileSystem, info, dgst, desc) - if err != nil { - return nil, nil, fmt.Errorf("unable to verify blob: %w", err) - } - if !verified { - // remove invalid blob from cache - if err := lc.overlayFs.Remove(dgst); err != nil { - lc.log.V(7).Info("unable to remove invalid blob", "digest", dgst, "err", err.Error()) - } - return info, nil, ErrNotFound - } - file, err := lc.overlayFs.OpenFile(dgst, os.O_RDONLY, os.ModePerm) - if err != nil { - return nil, nil, err - } - return info, file, err -} - -// verifyBlob validates the digest of a blob -func verifyBlob(fs vfs.FileSystem, info os.FileInfo, dgst string, desc ocispecv1.Descriptor) (bool, error) { - if info.Size() != desc.Size { - // do a simple check by checking the blob size - return false, nil - } - - file, err := fs.OpenFile(dgst, os.O_RDONLY, os.ModePerm) - if err != nil { - return false, err - } - defer file.Close() - - verifier := desc.Digest.Verifier() - if _, err := io.Copy(verifier, file); err != nil { - return false, err - } - return verifier.Verified(), nil -} - -func Path(desc ocispecv1.Descriptor) string { - return desc.Digest.Encoded() -} diff --git a/pkg/components/cache/filesystem.go b/pkg/components/cache/filesystem.go deleted file mode 100644 index c6bf78f08..000000000 --- a/pkg/components/cache/filesystem.go +++ /dev/null @@ -1,489 +0,0 @@ -// SPDX-FileCopyrightText: 2021 SAP SE or an SAP affiliate company and Gardener contributors. -// -// SPDX-License-Identifier: Apache-2.0 - -package cache - -import ( - "fmt" - "io" - "math" - "os" - "sort" - "sync" - "time" - - "github.com/go-logr/logr" - "github.com/mandelsoft/vfs/pkg/vfs" - "github.com/prometheus/client_golang/prometheus" - "k8s.io/apimachinery/pkg/api/resource" -) - -// GCHighThreshold defines the default percent of disk usage which triggers files garbage collection. -const GCHighThreshold float64 = 0.85 - -// GCLowThreshold defines the default percent of disk usage to which files garbage collection attempts to free. -const GCLowThreshold float64 = 0.80 - -// ResetInterval defines the default interval when the hit reset should run. -const ResetInterval time.Duration = 1 * time.Hour - -// PreservedHitsProportion defines the default percent of hits that should be preserved. -const PreservedHitsProportion = 0.5 - -// GarbageCollectionConfiguration contains all options for the cache garbage collection. -type GarbageCollectionConfiguration struct { - // Size is the size of the filesystem. - // If the value is 0 there is no limit and no garbage collection will happen. - // See the kubernetes quantity docs for detailed description of the format - // https://github.com/kubernetes/apimachinery/blob/master/pkg/api/resource/quantity.go - Size string - // GCHighThreshold defines the percent of disk usage which triggers files garbage collection. - GCHighThreshold float64 - // GCLowThreshold defines the percent of disk usage to which files garbage collection attempts to free. - GCLowThreshold float64 - // ResetInterval defines the interval when the hit reset should run. - ResetInterval time.Duration - // PreservedHitsProportion defines the percent of hits that should be preserved. - PreservedHitsProportion float64 -} - -// FileSystem is a internal representation of FileSystem with a optional max size -// and a garbage collection. -type FileSystem struct { - log logr.Logger - mux sync.Mutex - - // Configuration - vfs.FileSystem - // Size is the size of the filesystem in bytes. - // If the value is 0 there is no limit and no garbage collection will happen. - Size int64 - // GCHighThreshold defines the percent of disk usage which triggers files garbage collection. - GCHighThreshold float64 - // GCLowThreshold defines the percent of disk usage to which files garbage collection attempts to free. - GCLowThreshold float64 - // ResetInterval defines the interval when the hit reset should run. - ResetInterval time.Duration - // PreservedHitsProportion defines the percent of hits that should be preserved. - PreservedHitsProportion float64 - - index Index - // currentSize is the current size of the filesystem. - currentSize int64 - resetStopChan chan struct{} - - // optional metrics - itemsCountMetric prometheus.Gauge - diskUsageMetric prometheus.Gauge - hitsCountMetric prometheus.Counter -} - -// ApplyOptions parses and applies the options to the filesystem. -// It also applies defaults -func (o GarbageCollectionConfiguration) ApplyOptions(fs *FileSystem) error { - if len(o.Size) == 0 { - // no garbage collection configured ignore all other values - return nil - } - quantity, err := resource.ParseQuantity(o.Size) - if err != nil { - return fmt.Errorf("unable to parse size %q: %w", o.Size, err) - } - sizeInBytes, ok := quantity.AsInt64() - if ok { - fs.Size = sizeInBytes - } - - if o.GCHighThreshold == 0 { - o.GCHighThreshold = GCHighThreshold - } - fs.GCHighThreshold = o.GCHighThreshold - - if o.GCLowThreshold == 0 { - o.GCLowThreshold = GCLowThreshold - } - fs.GCLowThreshold = o.GCLowThreshold - - if o.ResetInterval == 0 { - o.ResetInterval = ResetInterval - } - fs.ResetInterval = o.ResetInterval - - if o.PreservedHitsProportion == 0 { - o.PreservedHitsProportion = PreservedHitsProportion - } - fs.PreservedHitsProportion = o.PreservedHitsProportion - - return nil -} - -// Merge merges 2 gc configurations whereas the defined values are overwritten. -func (o GarbageCollectionConfiguration) Merge(cfg *GarbageCollectionConfiguration) { - if len(o.Size) != 0 { - cfg.Size = o.Size - } - if o.GCHighThreshold != 0 { - cfg.GCHighThreshold = o.GCHighThreshold - } - if o.GCLowThreshold != 0 { - cfg.GCLowThreshold = o.GCLowThreshold - } - if o.ResetInterval != 0 { - cfg.ResetInterval = o.ResetInterval - } - if o.PreservedHitsProportion != 0 { - cfg.PreservedHitsProportion = o.PreservedHitsProportion - } -} - -// NewCacheFilesystem creates a new FileSystem cache. -// It acts as a replacement for a vfs filesystem that restricts the size of the filesystem. -// The garbage collection is triggered when a file is created. -// When the filesystem is not used anymore fs.Close() should be called to gracefully free resources. -func NewCacheFilesystem(log logr.Logger, fs vfs.FileSystem, gcOpts GarbageCollectionConfiguration) (*FileSystem, error) { - cFs := &FileSystem{ - log: log, - FileSystem: fs, - index: NewIndex(), - } - if err := gcOpts.ApplyOptions(cFs); err != nil { - return nil, err - } - - // load all cached files from the filesystem - files, err := vfs.ReadDir(fs, "/") - if err != nil { - return nil, fmt.Errorf("unable to read current cached files: %w", err) - } - for _, file := range files { - cFs.currentSize = cFs.currentSize + file.Size() - cFs.index.Add(file.Name(), file.Size(), file.ModTime()) - } - - if cFs.Size != 0 { - // start hit reset counter - cFs.StartResetInterval() - } - - return cFs, nil -} - -// WithMetrics adds prometheus metrics to the filesystem -// that are set by the filesystem. -func (fs *FileSystem) WithMetrics(itemsCount, usage prometheus.Gauge, hits prometheus.Counter) { - fs.diskUsageMetric = usage - fs.hitsCountMetric = hits - fs.itemsCountMetric = itemsCount - - if fs.diskUsageMetric != nil { - fs.diskUsageMetric.Set(float64(fs.CurrentSize())) - } - if fs.itemsCountMetric != nil { - fs.itemsCountMetric.Set(float64(fs.index.Len())) - } -} - -// Close implements the io.Closer interface. -// It should be called when the cache is not used anymore. -func (fs *FileSystem) Close() error { - if fs.resetStopChan == nil { - return nil - } - fs.resetStopChan <- struct{}{} - return nil -} - -var _ io.Closer = &FileSystem{} - -// StartResetInterval starts the reset counter for the cache hits. -func (fs *FileSystem) StartResetInterval() { - interval := time.NewTicker(ResetInterval) - fs.resetStopChan = make(chan struct{}) - go func() { - for { - select { - case <-interval.C: - fs.index.Reset() - case <-fs.resetStopChan: - interval.Stop() - return - } - } - }() -} - -func (fs *FileSystem) Create(path string, size int64) (vfs.File, error) { - fs.mux.Lock() - defer fs.mux.Unlock() - file, err := fs.FileSystem.Create(path) - if err != nil { - return nil, err - } - fs.setCurrentSize(fs.currentSize + size) - fs.index.Add(path, size, time.Now()) - if fs.itemsCountMetric != nil { - fs.itemsCountMetric.Inc() - } - go fs.RunGarbageCollection() - return file, err -} - -func (fs *FileSystem) OpenFile(name string, flags int, perm os.FileMode) (vfs.File, error) { - fs.index.Hit(name) - if fs.hitsCountMetric != nil { - fs.hitsCountMetric.Inc() - } - return fs.FileSystem.OpenFile(name, flags, perm) -} - -func (fs *FileSystem) Remove(name string) error { - if err := fs.FileSystem.Remove(name); err != nil { - return err - } - entry := fs.index.Get(name) - fs.setCurrentSize(fs.currentSize - entry.Size) - fs.index.Remove(name) - if fs.itemsCountMetric != nil { - fs.itemsCountMetric.Dec() - } - return nil -} - -// DeleteAll removes all files in the filesystem -func (fs *FileSystem) DeleteAll() error { - fs.mux.Lock() - defer fs.mux.Unlock() - files, err := vfs.ReadDir(fs.FileSystem, "/") - if err != nil { - return fmt.Errorf("unable to read current cached files: %w", err) - } - for _, file := range files { - if err := fs.Remove(file.Name()); err != nil { - return err - } - } - return nil -} - -// CurrentSize returns the current size of the filesystem -func (fs *FileSystem) CurrentSize() int64 { - return fs.currentSize -} - -// setCurrentSize sets the current size of the filesystem -func (fs *FileSystem) setCurrentSize(size int64) { - fs.currentSize = size - if fs.diskUsageMetric != nil { - fs.diskUsageMetric.Set(float64(size)) - } -} - -// usage returns the current disk usage of the filesystem -func (fs *FileSystem) usage() float64 { - return float64(fs.currentSize) / float64(fs.Size) -} - -// RunGarbageCollection runs the garbage collection of the filesystem. -// The gc only deletes items when the max size reached a certain threshold. -// If that threshold is reached the files are deleted with the following priority: -// - least hits -// - oldest -// - random -func (fs *FileSystem) RunGarbageCollection() { - // do not run gc if the size is infinite - if fs.Size == 0 { - return - } - // first check if we reached the threshold to start garbage collection - if usage := fs.usage(); usage < GCHighThreshold { - fs.log.V(10).Info(fmt.Sprintf("run gc with %v%% usage", usage)) - return - } - - // while the index is read and copied no write should happen - fs.mux.Lock() - index := fs.index.DeepCopy() - fs.mux.Unlock() - - // while the garbage collection is running read operations are blocked - // todo: improve to only block read operations on really deleted objects - fs.mux.Lock() - defer fs.mux.Unlock() - - // sort all files according to their deletion priority - items := index.PriorityList() - for fs.usage() > GCLowThreshold { - if len(items) == 0 { - return - } - item := items[0] - if err := fs.Remove(item.Name); err != nil { - fs.log.Error(err, "unable to delete file", "file", item.Name) - } - // remove currently garbage collected item - items = items[1:] - } -} - -type Index struct { - mut sync.RWMutex - entries map[string]IndexEntry -} - -// NewIndex creates a new index structure -func NewIndex() Index { - return Index{ - mut: sync.RWMutex{}, - entries: map[string]IndexEntry{}, - } -} - -type IndexEntry struct { - // Name is the name if the file. - Name string - // Size is the size of the file in bytes. - Size int64 - // Is the number of hits since the last gc - Hits int64 - // CreatedAt is the time when the file ha been created. - CreatedAt time.Time - // HitsSinceLastReset is the number hits since the last reset interval - HitsSinceLastReset int64 -} - -// Add adds a entry to the index. -func (i *Index) Add(name string, size int64, createdAt time.Time) { - i.entries[name] = IndexEntry{ - Name: name, - Size: size, - Hits: 0, - CreatedAt: createdAt, - HitsSinceLastReset: 0, - } -} - -// Len returns the number of items that are currently in the index. -func (i *Index) Len() int { - return len(i.entries) -} - -// Get return the index entry with the given name. -func (i *Index) Get(name string) IndexEntry { - i.mut.RLock() - defer i.mut.RUnlock() - return i.entries[name] -} - -// Remove removes the entry from the index. -func (i *Index) Remove(name string) { - i.mut.Lock() - defer i.mut.Unlock() - delete(i.entries, name) -} - -// Hit increases the hit count for the file. -func (i *Index) Hit(name string) { - i.mut.Lock() - defer i.mut.Unlock() - entry, ok := i.entries[name] - if !ok { - return - } - entry.Hits++ - entry.HitsSinceLastReset++ - i.entries[name] = entry -} - -// Reset resets the hit counter for all entries. -// The reset preserves 20% if the old hits. -func (i *Index) Reset() { - for name := range i.entries { - entry := i.Get(name) - - oldHits := entry.Hits - entry.HitsSinceLastReset - preservedHits := int64(float64(oldHits) * PreservedHitsProportion) - entry.Hits = preservedHits + entry.HitsSinceLastReset - - entry.HitsSinceLastReset = 0 - i.entries[name] = entry - } -} - -// DeepCopy creates a deep copy of the current index. -func (i *Index) DeepCopy() *Index { - index := &Index{ - entries: make(map[string]IndexEntry, len(i.entries)), - } - for key, value := range i.entries { - index.entries[key] = value - } - return index -} - -// PriorityList returns a entries of all entries -// sorted by their gc priority. -// The entry with the lowest priority is the first item. -func (i *Index) PriorityList() []IndexEntry { - p := priorityList{ - entries: make([]IndexEntry, 0), - } - for _, i := range i.entries { - entry := i - if entry.Hits > p.maxHits { - p.maxHits = entry.Hits - } - if p.minHits == 0 || entry.Hits < p.minHits { - p.minHits = entry.Hits - } - if p.newest.Before(entry.CreatedAt) { - p.newest = entry.CreatedAt - } - if p.oldest.IsZero() || entry.CreatedAt.Before(p.oldest) { - p.oldest = entry.CreatedAt - } - p.entries = append(p.entries, entry) - } - sort.Sort(p) - return p.entries -} - -// priorityList is a helper type that implements the sort.Sort function. -// the entries are sorted by their priority. -// The priority is calculated using the entries hits and creation date. -type priorityList struct { - minHits, maxHits int64 - oldest, newest time.Time - entries []IndexEntry -} - -var _ sort.Interface = priorityList{} - -func (i priorityList) Len() int { return len(i.entries) } - -func (i priorityList) Less(a, b int) bool { - eA, eB := i.entries[a], i.entries[b] - - // calculate the entries hits value - // based on the min and max values - priorityA := CalculatePriority(eA, i.minHits, i.maxHits, i.oldest, i.newest) - priorityB := CalculatePriority(eB, i.minHits, i.maxHits, i.oldest, i.newest) - return priorityA < priorityB -} - -// CalculatePriority calculates the gc priority of a index entry. -// A lower priority means that is more likely to be deleted. -func CalculatePriority(entry IndexEntry, minHits, maxHits int64, oldest, newest time.Time) float64 { - hitsVal := float64(entry.Hits-minHits) / float64(maxHits-minHits) - if math.IsNaN(hitsVal) { - hitsVal = 0 - } - dateVal := float64(entry.CreatedAt.UnixNano()-oldest.UnixNano()) / float64(newest.UnixNano()-oldest.UnixNano()) - if math.IsNaN(dateVal) { - dateVal = 0 - } - - return (hitsVal * 0.6) + (dateVal * 0.4) -} - -func (i priorityList) Swap(a, b int) { i.entries[a], i.entries[b] = i.entries[b], i.entries[a] } diff --git a/pkg/components/cache/inmemory.go b/pkg/components/cache/inmemory.go deleted file mode 100644 index 14538d8d3..000000000 --- a/pkg/components/cache/inmemory.go +++ /dev/null @@ -1,49 +0,0 @@ -// SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors. -// -// SPDX-License-Identifier: Apache-2.0 - -package cache - -import ( - "bytes" - "fmt" - "io" - - ocispecv1 "github.com/opencontainers/image-spec/specs-go/v1" -) - -type inmemoryCache struct { - store map[string][]byte -} - -// NewInMemoryCache creates a new in memory cache. -func NewInMemoryCache() *inmemoryCache { - return &inmemoryCache{ - store: make(map[string][]byte), - } -} - -func (fs *inmemoryCache) Close() error { - return nil -} - -func (fs *inmemoryCache) Get(desc ocispecv1.Descriptor) (io.ReadCloser, error) { - data, ok := fs.store[desc.Digest.String()] - if !ok { - return nil, ErrNotFound - } - return io.NopCloser(bytes.NewBuffer(data)), nil -} - -func (fs *inmemoryCache) Add(desc ocispecv1.Descriptor, reader io.ReadCloser) error { - if _, ok := fs.store[desc.Digest.String()]; ok { - // already cached - return nil - } - var buf bytes.Buffer - if _, err := io.Copy(&buf, reader); err != nil { - return fmt.Errorf("unable to read data: %w", err) - } - fs.store[desc.Digest.String()] = buf.Bytes() - return nil -} diff --git a/pkg/components/cache/metrics.go b/pkg/components/cache/metrics.go deleted file mode 100644 index ffa8a3f42..000000000 --- a/pkg/components/cache/metrics.go +++ /dev/null @@ -1,107 +0,0 @@ -// SPDX-FileCopyrightText: 2021 SAP SE or an SAP affiliate company and Gardener contributors. -// -// SPDX-License-Identifier: Apache-2.0 - -package cache - -import ( - "github.com/prometheus/client_golang/prometheus" - - lsv1alpha1 "github.com/gardener/landscaper/apis/core/v1alpha1" -) - -const ( - storeSubsystemName = "blueprintCacheStore" - - ociClientNamespaceName = "ociclient" - cacheSubsystemName = "blueprintCache" -) - -var ( - // DiskUsage discloses disk used by the blueprint store - DiskUsage = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: lsv1alpha1.LandscaperMetricsNamespaceName, - Subsystem: storeSubsystemName, - Name: "disk_usage_bytes", - Help: "Bytes on disk currently used by blueprint store instance.", - }, - ) - - // StoredItems discloses the number of items stored by the blueprint store. - StoredItems = prometheus.NewGauge( - prometheus.GaugeOpts{ - Namespace: lsv1alpha1.LandscaperMetricsNamespaceName, - Subsystem: storeSubsystemName, - Name: "items_total", - Help: "Total number of items currently stored by the blueprint store.", - }, - ) - - // CacheMemoryUsage discloses memory used by caches - CacheMemoryUsage = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Namespace: ociClientNamespaceName, - Subsystem: cacheSubsystemName, - Name: "memory_usage_bytes", - Help: "Bytes in memory currently used by cache instance.", - }, - []string{"id"}, - ) - - // CacheDiskUsage discloses disk used by caches - CacheDiskUsage = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Namespace: ociClientNamespaceName, - Subsystem: cacheSubsystemName, - Name: "disk_usage_bytes", - Help: "Bytes on disk currently used by cache instance.", - }, - []string{"id"}, - ) - - // CachedItems discloses the number of items stored by caches - CachedItems = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Namespace: ociClientNamespaceName, - Subsystem: cacheSubsystemName, - Name: "items_total", - Help: "Total number of items currently cached by instance.", - }, - []string{"id"}, - ) - - // CacheHitsDisk discloses the number of hits for items cached on disk - CacheHitsDisk = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Namespace: ociClientNamespaceName, - Subsystem: cacheSubsystemName, - Name: "disk_hits_total", - Help: "Total number of hits for items cached on disk by an instance.", - }, - []string{"id"}, - ) - - // CacheHitsMemory discloses the number of hits for items cached in memory - CacheHitsMemory = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Namespace: ociClientNamespaceName, - Subsystem: cacheSubsystemName, - Name: "memory_hits_total", - Help: "Total number of hits for items cached in memory by an instance.", - }, - []string{"id"}, - ) -) - -// RegisterStoreMetrics allows to register blueprint store metrics with a given prometheus registerer -func RegisterStoreMetrics(reg prometheus.Registerer) { - reg.MustRegister(DiskUsage) - reg.MustRegister(StoredItems) - - reg.MustRegister(CacheHitsDisk) - reg.MustRegister(CacheHitsMemory) - reg.MustRegister(CachedItems) - reg.MustRegister(CacheDiskUsage) - reg.MustRegister(CacheMemoryUsage) -} diff --git a/pkg/components/cache/types.go b/pkg/components/cache/types.go deleted file mode 100644 index 04952386e..000000000 --- a/pkg/components/cache/types.go +++ /dev/null @@ -1,175 +0,0 @@ -// SPDX-FileCopyrightText: 2020 SAP SE or an SAP affiliate company and Gardener contributors. -// -// SPDX-License-Identifier: Apache-2.0 - -package cache - -import ( - "errors" - "io" - - ocispecv1 "github.com/opencontainers/image-spec/specs-go/v1" - - "github.com/google/uuid" -) - -var ( - // ErrNotFound is a error that indicates that the file is not cached - ErrNotFound = errors.New("not cached") -) - -// CacheDirEnvName is the name of the environment variable that configures cache directory. -const CacheDirEnvName = "OCI_CACHE_DIR" - -// Cache is the interface for a oci cache -type Cache interface { - io.Closer - Get(desc ocispecv1.Descriptor) (io.ReadCloser, error) - Add(desc ocispecv1.Descriptor, reader io.ReadCloser) error -} - -// Info contains additional information about the cache -type Info struct { - // Size is the max size of the filesystem in bytes. - // If the value is 0 there is no limit and no garbage collection will happen. - // +optional - Size int64 `json:"size"` - // CurrentSize is the current size of the cache - CurrentSize int64 `json:"currentSize"` - // ItemsCount is the number of items that are currently managed by the cache. - ItemsCount int64 `json:"items"` -} - -// InfoInterface describes an interface that can be optionally exposed by a cache to give additional information. -type InfoInterface interface { - Info() (Info, error) -} - -// PruneInterface describes an interface that can be optionally exposed by a cache to manually prune the cache. -type PruneInterface interface { - Prune() error -} - -// InjectCache is a interface to inject a cache. -type InjectCache interface { - InjectCache(c Cache) error -} - -// InjectCacheInto injects a cache if the given object implements the InjectCache interface. -func InjectCacheInto(obj interface{}, cache Cache) error { - if cache == nil { - return nil - } - if injector, ok := obj.(InjectCache); ok { - return injector.InjectCache(cache) - } - return nil -} - -// Options contains all oci cache options to configure the oci cache. -type Options struct { - // InMemoryOverlay specifies if a overlayFs InMemory cache should be used - InMemoryOverlay bool - - // InMemoryGCConfig defines the garbage collection configuration for the in memory cache. - InMemoryGCConfig GarbageCollectionConfiguration - - // BasePath specifies the Base path for the os filepath. - // Will be defaulted to a temp filepath if not specified - BasePath string - - // BaseGCConfig defines the garbage collection configuration for the in base cache. - BaseGCConfig GarbageCollectionConfiguration - - // UID is the identity of a cache, if not specified a UID will be generated - UID string -} - -// Option is the interface to specify different cache options -type Option interface { - ApplyOption(options *Options) -} - -// ApplyOptions applies the given entries options on these options, -// and then returns itself (for convenient chaining). -func (o *Options) ApplyOptions(opts []Option) *Options { - for _, opt := range opts { - opt.ApplyOption(o) - } - return o -} - -// ApplyDefaults sets defaults for the options. -func (o *Options) ApplyDefaults() { - if o.InMemoryOverlay && len(o.InMemoryGCConfig.Size) == 0 { - o.InMemoryGCConfig.Size = "200Mi" - } - - if len(o.UID) == 0 { - o.UID = uuid.New().String() - } -} - -// WithInMemoryOverlay is the options to specify the usage of a in memory overlayFs -type WithInMemoryOverlay bool - -func (w WithInMemoryOverlay) ApplyOption(options *Options) { - options.InMemoryOverlay = bool(w) -} - -// WithBasePath is the options to specify a base path -type WithBasePath string - -func (p WithBasePath) ApplyOption(options *Options) { - options.BasePath = string(p) -} - -// WithInMemoryOverlaySize sets the max size of the overly file system. -// See the kubernetes quantity docs for detailed description of the format -// https://github.com/kubernetes/apimachinery/blob/master/pkg/api/resource/quantity.go -type WithInMemoryOverlaySize string - -func (p WithInMemoryOverlaySize) ApplyOption(options *Options) { - options.InMemoryGCConfig.Size = string(p) -} - -// WithBaseSize sets the max size of the base file system. -// See the kubernetes quantity docs for detailed description of the format -// https://github.com/kubernetes/apimachinery/blob/master/pkg/api/resource/quantity.go -type WithBaseSize string - -func (p WithBaseSize) ApplyOption(options *Options) { - options.BaseGCConfig.Size = string(p) -} - -// WithGCConfig overwrites the garbage collection settings for all caches. -type WithGCConfig GarbageCollectionConfiguration - -func (p WithGCConfig) ApplyOption(options *Options) { - cfg := GarbageCollectionConfiguration(p) - cfg.Merge(&options.BaseGCConfig) - cfg.Merge(&options.InMemoryGCConfig) -} - -// WithBaseGCConfig overwrites the base garbage collection settings. -type WithBaseGCConfig GarbageCollectionConfiguration - -func (p WithBaseGCConfig) ApplyOption(options *Options) { - cfg := GarbageCollectionConfiguration(p) - cfg.Merge(&options.BaseGCConfig) -} - -// WithBaseGCConfig overwrites the in memory garbage collection settings. -type WithInMemoryGCConfig GarbageCollectionConfiguration - -func (p WithInMemoryGCConfig) ApplyOption(options *Options) { - cfg := GarbageCollectionConfiguration(p) - cfg.Merge(&options.InMemoryGCConfig) -} - -// WithUID is the option to give a cache an identity -type WithUID string - -func (p WithUID) ApplyOption(options *Options) { - options.UID = string(p) -} diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index e7c331e23..12936db44 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -7,10 +7,6 @@ package metrics import ( componentcliMetrics "github.com/gardener/component-cli/ociclient/metrics" "github.com/prometheus/client_golang/prometheus" - - "github.com/gardener/landscaper/pkg/components/cache" - - "github.com/gardener/landscaper/pkg/landscaper/blueprints" ) /* @@ -20,7 +16,5 @@ import ( // RegisterMetrics allows to register all landscaper exposed metrics func RegisterMetrics(reg prometheus.Registerer) { - cache.RegisterStoreMetrics(reg) - blueprints.RegisterStoreMetrics(reg) componentcliMetrics.RegisterCacheMetrics(reg) }