opencontainers / opencontainers/cgroups
Add parsing of memory.events max into Failcnt for cgroup v2
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 29
- Forks
- 32
- PR merge metrics
- No merged PRs in 30d
Description
In cgroup v2, memory.failcnt is unavailable; memory.events provides the max failures count.
This patch updates getMemoryDataV2 to read the 'max' field from memory.events and populate MemoryData.Failcnt.
Includes TestStatMemoryPodCgroupFailcnt to cover both presence and absence of memory.events.
diff --git a/fs2/memory.go b/fs2/memory.go
index 7613307..47891ef 100644
--- a/fs2/memory.go
+++ b/fs2/memory.go
@@ -170,6 +170,13 @@ func getMemoryDataV2(path, name string) (cgroups.MemoryData, error) {
}
memoryData.MaxUsage = value
+ // Read failcnt (max events) from memory.events for cgroup v2
+ if failcnt, err := fscommon.GetValueByKey(path, "memory.events", "max"); err == nil {
+ memoryData.Failcnt = failcnt
+ } else if !os.IsNotExist(err) {
+ return cgroups.MemoryData{}, err
+ }
+
return memoryData, nil
}
diff --git a/fs2/memory_test.go b/fs2/memory_test.go
index e46dbe6..1a7c6c9 100644
--- a/fs2/memory_test.go
+++ b/fs2/memory_test.go
@@ -125,6 +125,62 @@ func TestStatMemoryPodCgroup(t *testing.T) {
}
}
+// Test that memory.events max field is parsed into Failcnt for cgroup v2
+func TestStatMemoryPodCgroupFailcnt(t *testing.T) {
+ // Use a fake cgroupfs.
+ cgroups.TestMode = true
+ fakeCgroupDir := t.TempDir()
+
+ // Prepare minimal cgroup v2 files.
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.stat"), []byte(exampleMemoryStatData), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.current"), []byte("1"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.max"), []byte("2"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.peak"), []byte("3"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ // Write memory.events with max field
+ events := "other_event 5\nmax 42\nsome_event 7\n"
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.events"), []byte(events), 0o644); err != nil {
+ t.Fatal(err)
+ }
+
+ gotStats := cgroups.NewStats()
+ if err := statMemory(fakeCgroupDir, gotStats); err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if got := gotStats.MemoryStats.Usage.Failcnt; got != 42 {
+ t.Errorf("expected Failcnt 42, got %d", got)
+ }
+
+ // Missing memory.events should not error and Failcnt remains zero
+ fakeCgroupDir = t.TempDir()
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.stat"), []byte(exampleMemoryStatData), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.current"), []byte("10"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.max"), []byte("20"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.WriteFile(filepath.Join(fakeCgroupDir, "memory.peak"), []byte("30"), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ gotStats = cgroups.NewStats()
+ if err := statMemory(fakeCgroupDir, gotStats); err != nil {
+ t.Fatalf("unexpected error when memory.events missing: %v", err)
+ }
+ if got := gotStats.MemoryStats.Usage.Failcnt; got != 0 {
+ t.Errorf("expected Failcnt 0 when memory.events missing, got %d", got)
+ }
+}
+
func TestRootStatsFromMeminfo(t *testing.T) {
stats := &cgroups.Stats{
MemoryStats: cgroups.MemoryStats{
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in fs2/memory.go at getMemoryDataV2 and review the existing memory.current, memory.max, and memory.peak parsing. Then inspect fs2/memory_test.go, especially TestStatMemoryPodCgroup and the proposed TestStatMemoryPodCgroupFailcnt. Done means the memory.events max value populates Failcnt, while a missing memory.events file remains valid and leaves Failcnt at zero.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- operating-systems
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100