diff --git a/cache/cache.go b/cache/cache.go index 5dc27951b..25ac9d16d 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -228,20 +228,7 @@ func (dc *directoryCache) Get(key string, opts ...Option) (Reader, error) { opt = o(opt) } - // 1. Try to get from hardlink first - if dc.hlManager != nil { - if linkPath, exists := dc.hlManager.GetLink(key); exists { - if r, err := os.Open(linkPath); err == nil { - return &reader{ - ReaderAt: r, - closeFunc: r.Close, - }, nil - } - // If failed to open, continue with normal flow - } - } - - // 2. Try to get from memory cache + // Try to get from memory cache if !dc.direct && !opt.direct { if b, done, ok := dc.cache.Get(key); ok { return &reader{ @@ -265,13 +252,21 @@ func (dc *directoryCache) Get(key string, opts ...Option) (Reader, error) { } } - // 3. Read from disk - file, err := os.Open(dc.cachePath(key)) + // Try to get from hardlink first + filepath := CachePath(dc.directory, key) + if dc.hlManager != nil { + if linkPath, exists := dc.hlManager.GetLink(key); exists { + filepath = linkPath + } + } + + // Read from disk + file, err := os.Open(filepath) if err != nil { return nil, fmt.Errorf("failed to open blob file for %q: %w", key, err) } - // 4. If in direct mode, don't cache file descriptor + // If in direct mode, don't cache file descriptor if dc.direct || opt.direct { return &reader{ ReaderAt: file, @@ -284,7 +279,7 @@ func (dc *directoryCache) Get(key string, opts ...Option) (Reader, error) { }, nil } - // 5. Cache file descriptor + // Cache file descriptor return &reader{ ReaderAt: file, closeFunc: func() error { @@ -323,7 +318,7 @@ func (dc *directoryCache) Add(key string, opts ...Option) (Writer, error) { } // Create temporary file - w, err := dc.wipFile(key) + w, err := WipFile(dc.wipDirectory, key) if err != nil { return nil, err } @@ -337,7 +332,7 @@ func (dc *directoryCache) Add(key string, opts ...Option) (Writer, error) { } // Commit file - targetPath := dc.cachePath(key) + targetPath := CachePath(dc.directory, key) if err := os.MkdirAll(filepath.Dir(targetPath), 0700); err != nil { return fmt.Errorf("failed to create cache directory: %w", err) } @@ -393,14 +388,6 @@ func (dc *directoryCache) isClosed() bool { return closed } -func (dc *directoryCache) cachePath(key string) string { - return filepath.Join(dc.directory, key[:2], key) -} - -func (dc *directoryCache) wipFile(key string) (*os.File, error) { - return os.CreateTemp(dc.wipDirectory, key+"-*") -} - func NewMemoryCache() BlobCache { return &MemoryCache{ Membuf: map[string]*bytes.Buffer{}, @@ -491,7 +478,7 @@ func (dc *directoryCache) CreateHardlink(key string) error { return nil } log.L.Debugf("Creating hardlink for key %q", key) - return dc.hlManager.CreateLink(key, dc.cachePath(key)) + return dc.hlManager.CreateLink(key, CachePath(dc.directory, key)) } func (dc *directoryCache) HasHardlink(key string) bool { diff --git a/cache/hardlink.go b/cache/hardlink.go index 95d488b22..4fbb45d13 100644 --- a/cache/hardlink.go +++ b/cache/hardlink.go @@ -130,14 +130,13 @@ func (hm *HardlinkManager) CreateLink(key string, sourcePath string) error { } // Create hardlink in hardlinks directory - linkPath := filepath.Join(hm.hlDir, key[:2], key) + linkPath := CachePath(hm.hlDir, key) if err := os.MkdirAll(filepath.Dir(linkPath), 0700); err != nil { return fmt.Errorf("failed to create link dir: %w", err) } // Create temporary link path - tmpLinkPath := linkPath + ".tmp" - + tmpLinkPath := CachePath(hm.hlDir, key+".wip") // Remove temporary link if it exists os.Remove(tmpLinkPath) diff --git a/cache/utils.go b/cache/utils.go new file mode 100644 index 000000000..d022d1522 --- /dev/null +++ b/cache/utils.go @@ -0,0 +1,36 @@ +/* + Copyright The containerd Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cache + +import ( + "fmt" + "os" + "path/filepath" +) + +// WipFile creates a temporary file in the given directory with the given key pattern +func WipFile(wipDirectory string, key string) (*os.File, error) { + if err := os.MkdirAll(wipDirectory, 0700); err != nil { + return nil, fmt.Errorf("failed to create wip directory: %w", err) + } + return os.CreateTemp(wipDirectory, key+"-*") +} + +// CachePath returns the path for a cache entry with the given key +func CachePath(directory string, key string) string { + return filepath.Join(directory, key[:2], key) +}