Skip to content

Commit e364b6c

Browse files
authored
Merge branch 'master' into tvey/set-system-limits-on-program-start
2 parents c508301 + 61c5661 commit e364b6c

2 files changed

Lines changed: 185 additions & 0 deletions

File tree

pkg/limits/limits_posix.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//go:build linux || darwin || freebsd || openbsd
2+
3+
// Package limits includes POSIX-specific limit tuning to mirror xinetd-like defaults.
4+
// Separating platforms keeps platform quirks localized and easier to maintain.
5+
package limits
6+
7+
import (
8+
"fmt"
9+
"log"
10+
"syscall"
11+
)
12+
13+
func collectLimitRequests(logger *log.Logger) []limitRequest {
14+
desiredOpenFiles := uint64(100000)
15+
desiredProcesses := uint64(100000)
16+
17+
requests := []limitRequest{
18+
buildInfinityRequest("virtual memory (rlimit_as)", syscall.RLIMIT_AS),
19+
buildInfinityRequest("CPU time (rlimit_cpu)", syscall.RLIMIT_CPU),
20+
buildTargetRequest("open files (rlimit_files)", syscall.RLIMIT_NOFILE, desiredOpenFiles, logger),
21+
}
22+
23+
if procResource, ok := processLimitResource(); ok {
24+
requests = append(requests, buildTargetRequest("process count (rlimit_proc)", procResource, desiredProcesses, logger))
25+
} else {
26+
logger.Printf("Process limit resource is unavailable on this platform; skipping rlimit_proc")
27+
}
28+
29+
return requests
30+
}
31+
32+
func buildInfinityRequest(label string, resource int) limitRequest {
33+
return limitRequest{
34+
description: fmt.Sprintf("%s -> unlimited", label),
35+
apply: func() error {
36+
unlimited := ^uint64(0)
37+
38+
current := &syscall.Rlimit{}
39+
if err := syscall.Getrlimit(resource, current); err != nil {
40+
return fmt.Errorf("failed reading %s: %w", label, err)
41+
}
42+
43+
desired := &syscall.Rlimit{Cur: unlimited, Max: unlimited}
44+
if current.Cur == desired.Cur && current.Max == desired.Max {
45+
return nil
46+
}
47+
48+
if err := syscall.Setrlimit(resource, desired); err != nil {
49+
return fmt.Errorf("failed setting %s to unlimited: %w", label, err)
50+
}
51+
return nil
52+
},
53+
}
54+
}
55+
56+
func buildTargetRequest(label string, resource int, target uint64, logger *log.Logger) limitRequest {
57+
return limitRequest{
58+
description: fmt.Sprintf("%s -> %d", label, target),
59+
apply: func() error {
60+
current := &syscall.Rlimit{}
61+
if err := syscall.Getrlimit(resource, current); err != nil {
62+
return fmt.Errorf("failed reading %s: %w", label, err)
63+
}
64+
65+
desired := &syscall.Rlimit{Cur: target, Max: target}
66+
if current.Max > desired.Max {
67+
desired.Max = current.Max
68+
}
69+
if desired.Cur > desired.Max {
70+
desired.Cur = desired.Max
71+
}
72+
73+
if current.Cur >= desired.Cur && current.Max >= desired.Max {
74+
return nil
75+
}
76+
77+
if err := syscall.Setrlimit(resource, desired); err != nil {
78+
logger.Printf("Adjusting %s hit %v; trying best-effort with existing max", label, err)
79+
fallback := &syscall.Rlimit{Cur: desired.Cur, Max: current.Max}
80+
if fallback.Cur > fallback.Max {
81+
fallback.Cur = fallback.Max
82+
}
83+
if setErr := syscall.Setrlimit(resource, fallback); setErr != nil {
84+
return fmt.Errorf("failed setting %s even after fallback: %w", label, setErr)
85+
}
86+
}
87+
return nil
88+
},
89+
}
90+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//go:build darwin || freebsd
2+
// +build darwin freebsd
3+
4+
// Package limits includes POSIX-specific limit tuning to mirror xinetd-like defaults on BSD-derived systems.
5+
// Using a BSD-focused file keeps type handling compatible with the int64-based Rlimit definitions.
6+
package limits
7+
8+
import (
9+
"fmt"
10+
"log"
11+
"syscall"
12+
)
13+
14+
// collectLimitRequests assembles the desired RLIMIT adjustments for macOS and FreeBSD.
15+
// Keeping the list together documents which resources mirror the xinetd expectations.
16+
func collectLimitRequests(logger *log.Logger) []limitRequest {
17+
desiredOpenFiles := int64(100000)
18+
desiredProcesses := int64(100000)
19+
20+
requests := []limitRequest{
21+
buildInfinityRequest("virtual memory (rlimit_as)", syscall.RLIMIT_AS),
22+
buildInfinityRequest("CPU time (rlimit_cpu)", syscall.RLIMIT_CPU),
23+
buildTargetRequest("open files (rlimit_files)", syscall.RLIMIT_NOFILE, desiredOpenFiles, logger),
24+
}
25+
26+
if procResource, ok := processLimitResource(); ok {
27+
requests = append(requests, buildTargetRequest("process count (rlimit_proc)", procResource, desiredProcesses, logger))
28+
} else {
29+
logger.Printf("Process limit resource is unavailable on this platform; skipping rlimit_proc")
30+
}
31+
32+
return requests
33+
}
34+
35+
// buildInfinityRequest raises a resource to RLIM_INFINITY so workloads are not capped unexpectedly.
36+
// Using the constant directly avoids unsafe conversions when syscall uses int64 fields.
37+
func buildInfinityRequest(label string, resource int) limitRequest {
38+
return limitRequest{
39+
description: fmt.Sprintf("%s -> unlimited", label),
40+
apply: func() error {
41+
current := &syscall.Rlimit{}
42+
if err := syscall.Getrlimit(resource, current); err != nil {
43+
return fmt.Errorf("failed reading %s: %w", label, err)
44+
}
45+
46+
desired := &syscall.Rlimit{Cur: syscall.RLIM_INFINITY, Max: syscall.RLIM_INFINITY}
47+
if current.Cur == desired.Cur && current.Max == desired.Max {
48+
return nil
49+
}
50+
51+
if err := syscall.Setrlimit(resource, desired); err != nil {
52+
return fmt.Errorf("failed setting %s to unlimited: %w", label, err)
53+
}
54+
return nil
55+
},
56+
}
57+
}
58+
59+
// buildTargetRequest nudges a resource toward the requested level while honoring the hard ceiling.
60+
// When raising the hard limit is denied, the fallback keeps the process running with the best available values.
61+
func buildTargetRequest(label string, resource int, target int64, logger *log.Logger) limitRequest {
62+
return limitRequest{
63+
description: fmt.Sprintf("%s -> %d", label, target),
64+
apply: func() error {
65+
current := &syscall.Rlimit{}
66+
if err := syscall.Getrlimit(resource, current); err != nil {
67+
return fmt.Errorf("failed reading %s: %w", label, err)
68+
}
69+
70+
desired := &syscall.Rlimit{Cur: target, Max: target}
71+
if current.Max > desired.Max {
72+
desired.Max = current.Max
73+
}
74+
if desired.Cur > desired.Max {
75+
desired.Cur = desired.Max
76+
}
77+
78+
if current.Cur >= desired.Cur && current.Max >= desired.Max {
79+
return nil
80+
}
81+
82+
if err := syscall.Setrlimit(resource, desired); err != nil {
83+
logger.Printf("Adjusting %s hit %v; trying best-effort with existing max", label, err)
84+
fallback := &syscall.Rlimit{Cur: desired.Cur, Max: current.Max}
85+
if fallback.Cur > fallback.Max {
86+
fallback.Cur = fallback.Max
87+
}
88+
if setErr := syscall.Setrlimit(resource, fallback); setErr != nil {
89+
return fmt.Errorf("failed setting %s even after fallback: %w", label, setErr)
90+
}
91+
}
92+
return nil
93+
},
94+
}
95+
}

0 commit comments

Comments
 (0)