Skip to content

Commit 0f14d87

Browse files
🤖 chore: abstract parent lookup pattern in cgroupv2 (#29)
This PR abstracts a repeating parent lookup pattern in cgroupv2 using a generic helper function. Relates to #28 (comment) ## Changes - **Added generic helper** - Handles parent cgroup lookups with customizable fallback behavior - **Applied to 5 methods**: - `cpuQuota()` - `cpuPeriod()` - `memoryMaxBytes()` - `memoryCurrentBytes()` - `memoryInactiveFileBytes()` --- 🤖 PR was written by Claude Sonnet 4.5 Thinking using [Coder Mux](https://github.com/coder/cmux) and reviewed by a human 👩
1 parent 7f9eb31 commit 0f14d87

File tree

1 file changed

+41
-60
lines changed

1 file changed

+41
-60
lines changed

cgroupv2.go

Lines changed: 41 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,25 @@ func newCgroupV2Statter(fs afero.Fs, path string, depth int) (*cgroupV2Statter,
6969
}, nil
7070
}
7171

72+
// getFromParentOrFallback attempts to get a value from the parent cgroup
73+
// when the current cgroup has no value set. If there is no parent, it
74+
// calls the fallback function to determine the return value.
75+
func getFromParentOrFallback[T any](
76+
s *cgroupV2Statter,
77+
getter func(*cgroupV2Statter) (T, error),
78+
fallback func() (T, error),
79+
) (T, error) {
80+
if s.parent != nil {
81+
result, err := getter(s.parent)
82+
if err != nil {
83+
var zero T
84+
return zero, xerrors.Errorf("read parent: %w", err)
85+
}
86+
return result, nil
87+
}
88+
return fallback()
89+
}
90+
7291
func (s cgroupV2Statter) cpuUsed() (used float64, err error) {
7392
cpuStatPath := filepath.Join(s.path, cgroupV2CPUStat)
7493

@@ -94,17 +113,10 @@ func (s cgroupV2Statter) cpuQuota() (float64, error) {
94113
}
95114

96115
// If the value is not a valid integer, assume it is the string
97-
// 'max' and that there is no limit set. In this scenario, we call
98-
// the parent to find its quota.
99-
if s.parent != nil {
100-
total, err := s.parent.cpuQuota()
101-
if err != nil {
102-
return 0, xerrors.Errorf("get parent cpu quota: %w", err)
103-
}
104-
return total, nil
105-
}
106-
107-
return -1, nil
116+
// 'max' and that there is no limit set. Try the parent or return -1.
117+
return getFromParentOrFallback(&s, (*cgroupV2Statter).cpuQuota, func() (float64, error) {
118+
return -1.0, nil
119+
})
108120
}
109121

110122
return float64(quotaUs), nil
@@ -120,18 +132,11 @@ func (s cgroupV2Statter) cpuPeriod() (float64, error) {
120132
}
121133

122134
// If the value is not a valid integer or the cpu.max file does
123-
// not exist, we call the parent to find its period. This can happen
124-
// in system-level cgroups like init.scope where cpu.max may not exist.
125-
if s.parent != nil {
126-
period, err := s.parent.cpuPeriod()
127-
if err != nil {
128-
return 0, xerrors.Errorf("get parent cpu period: %w", err)
129-
}
130-
return period, nil
131-
}
132-
133-
// No parent and no period found in the cgroup hierarchy.
134-
return cgroupV2DefaultPeriodUs, nil
135+
// not exist, try the parent or return the default period. This can
136+
// happen in system-level cgroups like init.scope where cpu.max may not exist.
137+
return getFromParentOrFallback(&s, (*cgroupV2Statter).cpuPeriod, func() (float64, error) {
138+
return cgroupV2DefaultPeriodUs, nil
139+
})
135140
}
136141

137142
return float64(periodUs), nil
@@ -161,19 +166,11 @@ func (s cgroupV2Statter) memoryMaxBytes() (*float64, error) {
161166
}
162167

163168
// If the value is not a valid integer _or_ the memory max file
164-
// does not exist, than we can assume that the limit is 'max'.
165-
// If the memory limit is max, and we have a parent, we shall call
166-
// the parent to find its maximum memory value.
167-
if s.parent != nil {
168-
result, err := s.parent.memoryMaxBytes()
169-
if err != nil {
170-
return nil, xerrors.Errorf("read parent memory max: %w", err)
171-
}
172-
return result, nil
173-
}
174-
175-
// We have no parent, and no max memory limit, so there is no memory limit.
176-
return nil, nil
169+
// does not exist, we can assume that the limit is 'max'.
170+
// Try the parent or return nil (no limit).
171+
return getFromParentOrFallback(&s, (*cgroupV2Statter).memoryMaxBytes, func() (*float64, error) {
172+
return nil, nil
173+
})
177174
}
178175

179176
return ptr.To(float64(maxUsageBytes)), nil
@@ -188,18 +185,10 @@ func (s cgroupV2Statter) memoryCurrentBytes() (int64, error) {
188185
return 0, xerrors.Errorf("read memory current: %w", err)
189186
}
190187

191-
// If the memory current file does not exist, and we have a parent,
192-
// we shall call the parent to find its current memory value.
193-
if s.parent != nil {
194-
result, err := s.parent.memoryCurrentBytes()
195-
if err != nil {
196-
return 0, xerrors.Errorf("read parent memory current: %w", err)
197-
}
198-
return result, nil
199-
}
200-
201-
// We have no parent, and no memory current file, so return the error.
202-
return 0, xerrors.Errorf("read memory current: %w", err)
188+
// If the memory current file does not exist, try the parent or return error.
189+
return getFromParentOrFallback(&s, (*cgroupV2Statter).memoryCurrentBytes, func() (int64, error) {
190+
return 0, xerrors.Errorf("read memory current: %w", err)
191+
})
203192
}
204193

205194
return currUsageBytes, nil
@@ -214,18 +203,10 @@ func (s cgroupV2Statter) memoryInactiveFileBytes() (int64, error) {
214203
return 0, xerrors.Errorf("read memory stat inactive_file: %w", err)
215204
}
216205

217-
// If the memory stat file does not exist, and we have a parent,
218-
// we shall call the parent to find its inactive_file value.
219-
if s.parent != nil {
220-
result, err := s.parent.memoryInactiveFileBytes()
221-
if err != nil {
222-
return 0, xerrors.Errorf("read parent memory stat inactive_file: %w", err)
223-
}
224-
return result, nil
225-
}
226-
227-
// We have no parent, and no memory stat file, so return the error.
228-
return 0, xerrors.Errorf("read memory stat inactive_file: %w", err)
206+
// If the memory stat file does not exist, try the parent or return error.
207+
return getFromParentOrFallback(&s, (*cgroupV2Statter).memoryInactiveFileBytes, func() (int64, error) {
208+
return 0, xerrors.Errorf("read memory stat inactive_file: %w", err)
209+
})
229210
}
230211

231212
return inactiveFileBytes, nil

0 commit comments

Comments
 (0)