Fence installation transaction durability (T-613)

This commit is contained in:
ila
2026-07-18 16:28:49 +08:00
parent 84befee70f
commit 20596a7de4
18 changed files with 697 additions and 64 deletions
+18 -6
View File
@@ -35,7 +35,8 @@ var (
// Extractor writes only payload/ contents from a pre-verified package ZIP.
type Extractor struct {
limits Limits
limits Limits
durability durabilityFence
}
type ExtractResult struct {
@@ -56,7 +57,7 @@ func NewExtractor(limits Limits) (Extractor, error) {
if err := limits.validate(); err != nil {
return Extractor{}, err
}
return Extractor{limits: limits}, nil
return Extractor{limits: limits, durability: defaultDurability()}, nil
}
// ExtractFile requires expectedPackageSize from the verified Catalog package.
@@ -88,6 +89,7 @@ func (extractor Extractor) extract(
if err := extractor.limits.validate(); err != nil {
return ExtractResult{}, err
}
fence := effectiveDurability(extractor.durability)
normalizedEntrypoint, err := normalizeEntrypoint(entrypoint)
if err != nil {
return ExtractResult{}, err
@@ -160,21 +162,21 @@ func (extractor Extractor) extract(
readLimit++
}
copied, copyErr := io.Copy(output, io.LimitReader(source, readLimit))
closeOutputErr := output.Close()
closeSourceErr := source.Close()
if copyErr != nil {
_ = output.Close()
return ExtractResult{}, fmt.Errorf("%w: read %s: %v", ErrArchiveCorrupt, entry.archivePath, copyErr)
}
if closeOutputErr != nil {
return ExtractResult{}, fmt.Errorf("close staging file: %w", closeOutputErr)
}
if closeSourceErr != nil {
_ = output.Close()
return ExtractResult{}, fmt.Errorf("%w: close %s: %v", ErrArchiveCorrupt, entry.archivePath, closeSourceErr)
}
if copied > remaining {
_ = output.Close()
return ExtractResult{}, ErrExpandedTooLarge
}
if uint64(copied) != entry.file.UncompressedSize64 {
_ = output.Close()
return ExtractResult{}, fmt.Errorf(
"%w: %s expanded to %d bytes, header declares %d",
ErrArchiveCorrupt,
@@ -183,9 +185,19 @@ func (extractor Extractor) extract(
entry.file.UncompressedSize64,
)
}
if err := syncFileWithFence(fence, output, "staging payload"); err != nil {
_ = output.Close()
return ExtractResult{}, err
}
if err := output.Close(); err != nil {
return ExtractResult{}, fmt.Errorf("close staging file: %w", err)
}
written += copied
result.Files++
}
if err := syncStagingTree(fence, destinationRoot); err != nil {
return ExtractResult{}, err
}
result.Bytes = written
result.EntrypointPath = entrypointPath