feat: persist cache effective upstream path

This commit is contained in:
2026-03-23 16:24:39 +08:00
parent 7c95ee0210
commit 9c85b9b097
3 changed files with 101 additions and 9 deletions

View File

@@ -2,6 +2,7 @@ package cache
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
@@ -49,6 +50,10 @@ type entryLock struct {
refs int
}
type entryMetadata struct {
EffectiveUpstreamPath string `json:"effective_upstream_path,omitempty"`
}
func (s *fileStore) Get(ctx context.Context, locator Locator) (*ReadResult, error) {
select {
case <-ctx.Done():
@@ -86,6 +91,12 @@ func (s *fileStore) Get(ctx context.Context, locator Locator) (*ReadResult, erro
SizeBytes: info.Size(),
ModTime: info.ModTime(),
}
if metadata, err := s.readMetadata(filePath); err == nil {
entry.EffectiveUpstreamPath = metadata.EffectiveUpstreamPath
} else if !errors.Is(err, fs.ErrNotExist) {
file.Close()
return nil, err
}
return &ReadResult{Entry: entry, Reader: file}, nil
}
@@ -133,12 +144,16 @@ func (s *fileStore) Put(ctx context.Context, locator Locator, body io.Reader, op
if err := os.Chtimes(filePath, modTime, modTime); err != nil {
return nil, err
}
if err := s.writeMetadata(filePath, opts.EffectiveUpstreamPath); err != nil {
return nil, err
}
entry := Entry{
Locator: locator,
FilePath: filePath,
SizeBytes: written,
ModTime: modTime,
Locator: locator,
FilePath: filePath,
SizeBytes: written,
ModTime: modTime,
EffectiveUpstreamPath: opts.EffectiveUpstreamPath,
}
return &entry, nil
}
@@ -157,6 +172,54 @@ func (s *fileStore) Remove(ctx context.Context, locator Locator) error {
if err := os.Remove(filePath); err != nil && !errors.Is(err, fs.ErrNotExist) {
return err
}
if err := os.Remove(metadataPath(filePath)); err != nil && !errors.Is(err, fs.ErrNotExist) {
return err
}
return nil
}
func (s *fileStore) readMetadata(filePath string) (entryMetadata, error) {
raw, err := os.ReadFile(metadataPath(filePath))
if err != nil {
return entryMetadata{}, err
}
var metadata entryMetadata
if err := json.Unmarshal(raw, &metadata); err != nil {
return entryMetadata{}, err
}
return metadata, nil
}
func (s *fileStore) writeMetadata(filePath string, effectiveUpstreamPath string) error {
metaFilePath := metadataPath(filePath)
if effectiveUpstreamPath == "" {
if err := os.Remove(metaFilePath); err != nil && !errors.Is(err, fs.ErrNotExist) {
return err
}
return nil
}
data, err := json.Marshal(entryMetadata{EffectiveUpstreamPath: effectiveUpstreamPath})
if err != nil {
return err
}
tempFile, err := os.CreateTemp(filepath.Dir(metaFilePath), ".cache-meta-*")
if err != nil {
return err
}
tempName := tempFile.Name()
if _, err := tempFile.Write(data); err != nil {
tempFile.Close()
_ = os.Remove(tempName)
return err
}
if err := tempFile.Close(); err != nil {
_ = os.Remove(tempName)
return err
}
if err := os.Rename(tempName, metaFilePath); err != nil {
_ = os.Remove(tempName)
return err
}
return nil
}
@@ -248,3 +311,7 @@ func copyWithContext(ctx context.Context, dst io.Writer, src io.Reader) (int64,
func locatorKey(locator Locator) string {
return locator.HubName + "::" + locator.Path
}
func metadataPath(filePath string) string {
return filePath + ".meta"
}

View File

@@ -26,7 +26,8 @@ type Store interface {
// PutOptions 控制写入过程中的可选属性。
type PutOptions struct {
ModTime time.Time
ModTime time.Time
EffectiveUpstreamPath string
}
// Locator 唯一定位一个缓存条目Hub + 相对路径),所有路径均为 URL 路径风格。
@@ -37,10 +38,11 @@ type Locator struct {
// Entry 表示一次缓存命中结果,包含绝对文件路径及文件信息。
type Entry struct {
Locator Locator `json:"locator"`
FilePath string `json:"file_path"`
SizeBytes int64 `json:"size_bytes"`
ModTime time.Time
Locator Locator `json:"locator"`
FilePath string `json:"file_path"`
SizeBytes int64 `json:"size_bytes"`
ModTime time.Time `json:"mod_time"`
EffectiveUpstreamPath string `json:"effective_upstream_path,omitempty"`
}
// ReadResult 组合 Entry 与正文 Reader便于代理层直接将 Body 流式返回。

View File

@@ -5,6 +5,7 @@ import (
"context"
"io"
"os"
"strings"
"testing"
"time"
)
@@ -62,6 +63,28 @@ func TestStoreRemove(t *testing.T) {
}
}
func TestStorePersistsEffectiveUpstreamPath(t *testing.T) {
store := newTestStore(t)
locator := Locator{HubName: "docker", Path: "/v2/coredns/manifests/v1.13.1"}
_, err := store.Put(context.Background(), locator, strings.NewReader("body"), PutOptions{
EffectiveUpstreamPath: "/v2/coredns/coredns/manifests/v1.13.1",
})
if err != nil {
t.Fatalf("put error: %v", err)
}
result, err := store.Get(context.Background(), locator)
if err != nil {
t.Fatalf("get error: %v", err)
}
defer result.Reader.Close()
if result.Entry.EffectiveUpstreamPath != "/v2/coredns/coredns/manifests/v1.13.1" {
t.Fatalf("unexpected effective upstream path: %q", result.Entry.EffectiveUpstreamPath)
}
}
func TestStoreIgnoresDirectories(t *testing.T) {
store := newTestStore(t)
locator := Locator{HubName: "ghcr", Path: "/v2"}