budget.go RawHistoryFolder
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3package domain
4
5import "fmt"
6
7// ValidateCommitObjects checks a request before any repository I/O. max is the
8// caller's commit-count limit.
9func ValidateCommitObjects(ids []ObjectID, max int) error {
10 if len(ids) > max {
11 return fmt.Errorf("%w: %d commit objects asked, at most %d", ErrInvalid, len(ids), max)
12 }
13 for _, id := range ids {
14 if id.IsZero() {
15 return fmt.Errorf("%w: empty commit id", ErrInvalidObjectID)
16 }
17 }
18 return nil
19}
20
21// CommitObjectBudget bounds a batch of raw commits. Its zero value is ready to
22// use. Admission is a preview; Charge records only successfully read content.
23type CommitObjectBudget struct {
24 total int64
25 seen map[ObjectID]bool
26}
27
28func (b *CommitObjectBudget) Seen(id ObjectID) bool { return b.seen[id] }
29
30func (b *CommitObjectBudget) Admit(id ObjectID, commit bool, size int64) (take, stop bool) {
31 if b.Seen(id) || !commit || size < 0 || size > MaxCommitObjectBytes {
32 return false, false
33 }
34 if size > MaxCommitObjectsBytes-b.total {
35 return false, true
36 }
37 return true, false
38}
39
40func (b *CommitObjectBudget) Charge(id ObjectID, size int64) {
41 if b.seen == nil {
42 b.seen = make(map[ObjectID]bool)
43 }
44 b.seen[id] = true
45 b.total += size
46}
47
48// DiffBudget owns file selection and retained hunk accounting. Truncated files
49// consume no budget; streaming readers may use a copy while attempting a file.
50type DiffBudget struct {
51 limits DiffLimits
52 linesLeft, bytesLeft int
53}
54
55func NewDiffBudget(limits DiffLimits) DiffBudget {
56 return DiffBudget{limits: limits, linesLeft: limits.MaxTotalLines, bytesLeft: limits.MaxTotalBytes}
57}
58
59func (b DiffBudget) Window(files int) (kept, from, to int, truncated bool) {
60 kept = files
61 if b.limits.MaxFiles > 0 && kept > b.limits.MaxFiles {
62 kept = b.limits.MaxFiles
63 truncated = true
64 }
65 from, to = max(b.limits.From, 0), kept
66 if b.limits.To > 0 {
67 to = min(b.limits.To, kept)
68 }
69 return
70}
71
72func (b DiffBudget) ChangedLines(binary bool, n int) bool { return !binary && n > 0 }
73
74func (b DiffBudget) WantsHunks(binary bool, n int) bool {
75 return b.ChangedLines(binary, n) && n <= b.limits.MaxFileLines && n <= b.linesLeft && b.bytesLeft > 0
76}
77
78func (b DiffBudget) FileLines() int { return min(b.limits.MaxFileLines, b.linesLeft) }
79
80// ChargeLine accounts for one decoded hunk line and reports whether it fits.
81func (b *DiffBudget) ChargeLine(bytes int) bool {
82 b.linesLeft--
83 b.bytesLeft -= bytes
84 return b.linesLeft >= 0 && b.bytesLeft >= 0
85}