Harden chunk plan cache storage and reuse

This commit is contained in:
2026-07-18 00:49:50 +00:00
parent 6fc6ce0adb
commit 6d0a19c94c
7 changed files with 228 additions and 5 deletions

View File

@@ -17,7 +17,8 @@ import (
const SchemaVersion = pipeline.ChunkPlanSchemaVersion
type filesystemStore struct {
root string
root string
write func(string, []byte) error
}
func NewFilesystemStore(root string) (pipeline.ChunkPlanStore, error) {
@@ -28,7 +29,7 @@ func NewFilesystemStore(root string) (pipeline.ChunkPlanStore, error) {
if strings.ContainsRune(root, '\x00') {
return nil, fmt.Errorf("chunk plan root must not contain NUL")
}
return &filesystemStore{root: filepath.Clean(root)}, nil
return &filesystemStore{root: filepath.Clean(root), write: writeAtomic}, nil
}
func (s *filesystemStore) Load(sourceDigest string) (pipeline.ChunkPlanRecord, pipeline.ChunkPlanDecision, error) {
@@ -77,7 +78,11 @@ func (s *filesystemStore) Save(record pipeline.ChunkPlanRecord) error {
return fmt.Errorf("encode chunk plan record: %w", err)
}
data = append(data, '\n')
if err := writeAtomic(target, data); err != nil {
writer := s.write
if writer == nil {
writer = writeAtomic
}
if err := writer(target, data); err != nil {
return fmt.Errorf("write chunk plan: %w", err)
}
return nil
@@ -164,7 +169,16 @@ func invalidDecision(reason string) (pipeline.ChunkPlanRecord, pipeline.ChunkPla
return pipeline.ChunkPlanRecord{}, pipeline.ChunkPlanDecision{Status: pipeline.ChunkPlanInvalid, Reason: reason}, nil
}
type atomicWriteHooks struct {
BeforeCreateTemp func() error
BeforeRename func() error
}
func writeAtomic(target string, data []byte) error {
return writeAtomicWithHooks(target, data, atomicWriteHooks{})
}
func writeAtomicWithHooks(target string, data []byte, hooks atomicWriteHooks) error {
dir := filepath.Dir(target)
if err := os.MkdirAll(dir, 0o700); err != nil {
return err
@@ -173,6 +187,11 @@ func writeAtomic(target string, data []byte) error {
return err
}
if hooks.BeforeCreateTemp != nil {
if err := hooks.BeforeCreateTemp(); err != nil {
return err
}
}
temp, err := os.CreateTemp(dir, ".plan.json.tmp-*")
if err != nil {
return err
@@ -199,6 +218,11 @@ func writeAtomic(target string, data []byte) error {
if err := temp.Close(); err != nil {
return err
}
if hooks.BeforeRename != nil {
if err := hooks.BeforeRename(); err != nil {
return err
}
}
if err := os.Rename(tempPath, target); err != nil {
return err
}