Skip to content

Commit

Permalink
pkg/global: add the ability to call setrlimit(2) on startup
Browse files Browse the repository at this point in the history
Recent versions of Go changed the logic for setting RLIMIT_NOFILE as
part of child processes:

https://go-review.googlesource.com/c/go/+/476097

This might cause build actions to run into file descriptor limits. Let's
solve this by adding the ability to override resource limits in
bb_runner's configuration.
  • Loading branch information
EdSchouten committed Jan 8, 2024
1 parent e7766ce commit 1ba9ed4
Show file tree
Hide file tree
Showing 10 changed files with 428 additions and 149 deletions.
29 changes: 28 additions & 1 deletion pkg/global/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ go_library(
name = "global",
srcs = [
"apply_configuration.go",
"resource_limits_darwin.go",
"resource_limits_freebsd.go",
"resource_limits_linux.go",
"resource_limits_nonunix.go",
"resource_limits_unix.go",
"umask_nonunix.go",
"umask_unix.go",
],
Expand Down Expand Up @@ -36,5 +41,27 @@ go_library(
"@org_golang_google_grpc//:go_default_library",
"@org_golang_google_grpc//codes",
"@org_golang_google_grpc//status",
],
] + select({
"@io_bazel_rules_go//go/platform:android": [
"@org_golang_google_protobuf//types/known/wrapperspb",
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:darwin": [
"@org_golang_google_protobuf//types/known/wrapperspb",
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:freebsd": [
"@org_golang_google_protobuf//types/known/wrapperspb",
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:ios": [
"@org_golang_google_protobuf//types/known/wrapperspb",
"@org_golang_x_sys//unix",
],
"@io_bazel_rules_go//go/platform:linux": [
"@org_golang_google_protobuf//types/known/wrapperspb",
"@org_golang_x_sys//unix",
],
"//conditions:default": [],
}),
)
7 changes: 7 additions & 0 deletions pkg/global/apply_configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ func ApplyConfiguration(configuration *pb.Configuration) (*LifecycleState, bb_gr
}
}

// Set resource limits, if provided.
for name, resourceLimit := range configuration.GetSetResourceLimits() {
if err := setResourceLimit(name, resourceLimit); err != nil {
return nil, nil, util.StatusWrapf(err, "Failed to set resource limit %#v", name)
}
}

// Logging.
logPaths := configuration.GetLogPaths()
logWriters := append(make([]io.Writer, 0, len(logPaths)+1), os.Stderr)
Expand Down
23 changes: 23 additions & 0 deletions pkg/global/resource_limits_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//go:build darwin
// +build darwin

package global

import (
"golang.org/x/sys/unix"
)

var resourceLimitNames = map[string]int{
"AS": unix.RLIMIT_AS,
"CORE": unix.RLIMIT_CORE,
"CPU": unix.RLIMIT_CPU,
"DATA": unix.RLIMIT_DATA,
"FSIZE": unix.RLIMIT_FSIZE,
"MEMLOCK": unix.RLIMIT_MEMLOCK,
"NOFILE": unix.RLIMIT_NOFILE,
"NPROC": unix.RLIMIT_NPROC,
"RSS": unix.RLIMIT_RSS,
"STACK": unix.RLIMIT_STACK,
}

type resourceLimitValueType = uint64
23 changes: 23 additions & 0 deletions pkg/global/resource_limits_freebsd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//go:build freebsd
// +build freebsd

package global

import (
"golang.org/x/sys/unix"
)

var resourceLimitNames = map[string]int{
"AS": unix.RLIMIT_AS,
"CORE": unix.RLIMIT_CORE,
"CPU": unix.RLIMIT_CPU,
"DATA": unix.RLIMIT_DATA,
"FSIZE": unix.RLIMIT_FSIZE,
"MEMLOCK": unix.RLIMIT_MEMLOCK,
"NOFILE": unix.RLIMIT_NOFILE,
"NPROC": unix.RLIMIT_NPROC,
"RSS": unix.RLIMIT_RSS,
"STACK": unix.RLIMIT_STACK,
}

type resourceLimitValueType = int64
18 changes: 18 additions & 0 deletions pkg/global/resource_limits_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//go:build linux
// +build linux

package global

import (
"golang.org/x/sys/unix"
)

var resourceLimitNames = map[string]int{
"AS": unix.RLIMIT_AS,
"MEMLOCK": unix.RLIMIT_MEMLOCK,
"NOFILE": unix.RLIMIT_NOFILE,
"NPROC": unix.RLIMIT_NPROC,
"RSS": unix.RLIMIT_RSS,
}

type resourceLimitValueType = uint64
15 changes: 15 additions & 0 deletions pkg/global/resource_limits_nonunix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//go:build windows
// +build windows

package global

import (
"github.com/buildbarn/bb-storage/pkg/proto/configuration/global"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

func setResourceLimit(name string, resourceLimit *global.SetResourceLimitConfiguration) error {
return status.Error(codes.Unimplemented, "Resource limits cannot be adjusted on this operating system")
}
35 changes: 35 additions & 0 deletions pkg/global/resource_limits_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//go:build darwin || freebsd || linux
// +build darwin freebsd linux

package global

import (
"github.com/buildbarn/bb-storage/pkg/proto/configuration/global"

"golang.org/x/sys/unix"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/wrapperspb"
)

func convertResourceLimitValue(limit *wrapperspb.UInt64Value) resourceLimitValueType {
if limit == nil {
// No limit provided. Assume infinity.
return unix.RLIM_INFINITY
}
return resourceLimitValueType(limit.Value)
}

// setResourceLimit applies a single resource limit that is provided in
// the configuration file against the current process using
// setrlimit(2).
func setResourceLimit(name string, resourceLimit *global.SetResourceLimitConfiguration) error {
resource, ok := resourceLimitNames[name]
if !ok {
return status.Error(codes.InvalidArgument, "Resource name is not supported by this operating system")
}
return unix.Setrlimit(resource, &unix.Rlimit{
Cur: convertResourceLimitValue(resourceLimit.SoftLimit),
Max: convertResourceLimitValue(resourceLimit.HardLimit),
})
}
1 change: 1 addition & 0 deletions pkg/proto/configuration/global/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ proto_library(
"//pkg/proto/configuration/http:http_proto",
"@com_google_protobuf//:duration_proto",
"@com_google_protobuf//:empty_proto",
"@com_google_protobuf//:wrappers_proto",
"@io_opentelemetry_proto//:common_proto",
],
)
Expand Down
Loading

0 comments on commit 1ba9ed4

Please sign in to comment.