Attribute reader shutdown failures to checks that read content
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Performance Implementation Remediation
|
||||
|
||||
**Status:** Remediation in progress; R1 complete.
|
||||
**Status:** Remediation in progress; R1–R2 complete.
|
||||
|
||||
**Review baseline:** df064bd, reviewed on 2026-10-09 against the
|
||||
[performance target](performance.md) and
|
||||
@@ -90,6 +90,12 @@ tracking remains internal implementation bookkeeping.
|
||||
later selected check that has no applicable files. Verify the earlier reader
|
||||
user receives the cleanup cause and the child exit error remains discoverable.
|
||||
|
||||
**Completion:** Complete. Internal blob-read bookkeeping now identifies the last
|
||||
check that actually used the reader. The extended close-failure fixture preserves
|
||||
Go-format attribution when Markdown has no files, including the child exit code
|
||||
and stderr. The regression failed before the fix and passes afterward; validation
|
||||
race tests and compiled public API and dependency checks passed.
|
||||
|
||||
## R3: Qualify Output Allocation Measurements By Their Workload
|
||||
|
||||
**Priority:** Low.
|
||||
|
||||
@@ -19,6 +19,7 @@ type CandidateTree struct {
|
||||
byPath map[string]int
|
||||
directories map[string]struct{}
|
||||
blobReader *git.BlobReader
|
||||
blobReads uint64
|
||||
symlinkTargets map[string]string
|
||||
closed bool
|
||||
closeErr error
|
||||
@@ -113,6 +114,7 @@ func (tree *CandidateTree) readBlob(ctx context.Context, entry git.TreeEntry) ([
|
||||
}
|
||||
tree.blobReader = git.NewBlobReader(operationContext, tree.repositoryDir)
|
||||
}
|
||||
tree.blobReads++
|
||||
contents, err := tree.blobReader.Read(ctx, entry.ObjectID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read committed path %q: %w", entry.Path, err)
|
||||
|
||||
@@ -28,17 +28,29 @@ done
|
||||
printf 'batch process failed during cleanup\n' >&2
|
||||
exit 23`)
|
||||
|
||||
err := Run(context.Background(), lifecycleRequest(repository, commit))
|
||||
var failure *Failure
|
||||
if !errors.As(err, &failure) || failure.Check != GoFormat {
|
||||
t.Fatalf("Run() error = %v, want cleanup failure attributed to GoFormat", err)
|
||||
}
|
||||
var exitErr *exec.ExitError
|
||||
if !errors.As(failure.Cause, &exitErr) || exitErr.ExitCode() != 23 {
|
||||
t.Fatalf("cleanup cause = %v, want Git child exit code 23", failure.Cause)
|
||||
}
|
||||
if !strings.Contains(failure.Cause.Error(), "batch process failed during cleanup") {
|
||||
t.Fatalf("cleanup cause = %v, want captured Git stderr", failure.Cause)
|
||||
for _, testCase := range []struct {
|
||||
name string
|
||||
markdown *MarkdownSettings
|
||||
}{
|
||||
{name: "formatting only"},
|
||||
{name: "later Markdown check without files", markdown: &MarkdownSettings{}},
|
||||
} {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
request := lifecycleRequest(repository, commit)
|
||||
request.Settings.Markdown = testCase.markdown
|
||||
err := Run(context.Background(), request)
|
||||
var failure *Failure
|
||||
if !errors.As(err, &failure) || failure.Check != GoFormat {
|
||||
t.Fatalf("Run() error = %v, want cleanup failure attributed to GoFormat", err)
|
||||
}
|
||||
var exitErr *exec.ExitError
|
||||
if !errors.As(failure.Cause, &exitErr) || exitErr.ExitCode() != 23 {
|
||||
t.Fatalf("cleanup cause = %v, want Git child exit code 23", failure.Cause)
|
||||
}
|
||||
if !strings.Contains(failure.Cause.Error(), "batch process failed during cleanup") {
|
||||
t.Fatalf("cleanup cause = %v, want captured Git stderr", failure.Cause)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -146,10 +146,13 @@ func Run(ctx context.Context, request Request) (result error) {
|
||||
}
|
||||
}()
|
||||
if request.Settings.GoFormat {
|
||||
lastContentCheck = GoFormat
|
||||
readsBefore := tree.blobReads
|
||||
if err := checkGoFormat(ctx, tree); err != nil {
|
||||
return err
|
||||
}
|
||||
if tree.blobReads != readsBefore {
|
||||
lastContentCheck = GoFormat
|
||||
}
|
||||
}
|
||||
if request.Settings.ModuleDistribution.WorkspaceFiles {
|
||||
if err := checkWorkspaceFiles(tree); err != nil {
|
||||
@@ -157,10 +160,13 @@ func Run(ctx context.Context, request Request) (result error) {
|
||||
}
|
||||
}
|
||||
if request.Settings.ModuleDistribution.LocalReplacements {
|
||||
lastContentCheck = LocalReplacements
|
||||
readsBefore := tree.blobReads
|
||||
if err := checkLocalReplacements(ctx, tree); err != nil {
|
||||
return err
|
||||
}
|
||||
if tree.blobReads != readsBefore {
|
||||
lastContentCheck = LocalReplacements
|
||||
}
|
||||
}
|
||||
if request.Settings.FileSize != nil {
|
||||
if err := checkFileSize(tree, request.Settings.FileSize); err != nil {
|
||||
@@ -168,10 +174,13 @@ func Run(ctx context.Context, request Request) (result error) {
|
||||
}
|
||||
}
|
||||
if request.Settings.Markdown != nil {
|
||||
lastContentCheck = MarkdownLinks
|
||||
readsBefore := tree.blobReads
|
||||
if err := checkMarkdownLinks(ctx, tree, request.Settings.Markdown.EnforceCheckoutBoundary, request.Output); err != nil {
|
||||
return err
|
||||
}
|
||||
if tree.blobReads != readsBefore {
|
||||
lastContentCheck = MarkdownLinks
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user