Skip to content

Commit 6d25447

Browse files
prd-foxjpmsam
authored andcommitted
Update file descriptor limits for macOS (#892)
* Introduces proper file handle limits for darwin based OSes (macOS/OSX) for working with Go 1.12
1 parent 882a303 commit 6d25447

File tree

9 files changed

+104
-21
lines changed

9 files changed

+104
-21
lines changed

cmd/utils/flags.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -882,10 +882,11 @@ func makeDatabaseHandles() int {
882882
if err != nil {
883883
Fatalf("Failed to retrieve file descriptor allowance: %v", err)
884884
}
885-
if err := fdlimit.Raise(uint64(limit)); err != nil {
885+
raised, err := fdlimit.Raise(uint64(limit))
886+
if err != nil {
886887
Fatalf("Failed to raise file descriptor allowance: %v", err)
887888
}
888-
return limit / 2 // Leave half for networking and other stuff
889+
return int(raised / 2) // Leave half for networking and other stuff
889890
}
890891

891892
// MakeAddress converts an account specified directly as a hex encoded string or

common/fdlimit/fdlimit_darwin.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Copyright 2019 The go-ethereum Authors
2+
// This file is part of the go-ethereum library.
3+
//
4+
// The go-ethereum library is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU Lesser General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// The go-ethereum library is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU Lesser General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU Lesser General Public License
15+
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
16+
17+
package fdlimit
18+
19+
import "syscall"
20+
21+
// hardlimit is the number of file descriptors allowed at max by the kernel.
22+
const hardlimit = 10240
23+
24+
// Raise tries to maximize the file descriptor allowance of this process
25+
// to the maximum hard-limit allowed by the OS.
26+
// Returns the size it was set to (may differ from the desired 'max')
27+
func Raise(max uint64) (uint64, error) {
28+
// Get the current limit
29+
var limit syscall.Rlimit
30+
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
31+
return 0, err
32+
}
33+
// Try to update the limit to the max allowance
34+
limit.Cur = limit.Max
35+
if limit.Cur > max {
36+
limit.Cur = max
37+
}
38+
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
39+
return 0, err
40+
}
41+
// MacOS can silently apply further caps, so retrieve the actually set limit
42+
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
43+
return 0, err
44+
}
45+
return limit.Cur, nil
46+
}
47+
48+
// Current retrieves the number of file descriptors allowed to be opened by this
49+
// process.
50+
func Current() (int, error) {
51+
var limit syscall.Rlimit
52+
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
53+
return 0, err
54+
}
55+
return int(limit.Cur), nil
56+
}
57+
58+
// Maximum retrieves the maximum number of file descriptors this process is
59+
// allowed to request for itself.
60+
func Maximum() (int, error) {
61+
// Retrieve the maximum allowed by dynamic OS limits
62+
var limit syscall.Rlimit
63+
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
64+
return 0, err
65+
}
66+
// Cap it to OPEN_MAX (10240) because macos is a special snowflake
67+
if limit.Max > hardlimit {
68+
limit.Max = hardlimit
69+
}
70+
return int(limit.Max), nil
71+
}

common/fdlimit/fdlimit_freebsd.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,24 @@ import "syscall"
2626

2727
// Raise tries to maximize the file descriptor allowance of this process
2828
// to the maximum hard-limit allowed by the OS.
29-
func Raise(max uint64) error {
29+
func Raise(max uint64) (uint64, error) {
3030
// Get the current limit
3131
var limit syscall.Rlimit
3232
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
33-
return err
33+
return 0, err
3434
}
3535
// Try to update the limit to the max allowance
3636
limit.Cur = limit.Max
3737
if limit.Cur > int64(max) {
3838
limit.Cur = int64(max)
3939
}
4040
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
41-
return err
41+
return 0, err
42+
}
43+
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
44+
return 0, err
4245
}
43-
return nil
46+
return uint64(limit.Cur), nil
4447
}
4548

4649
// Current retrieves the number of file descriptors allowed to be opened by this

common/fdlimit/fdlimit_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func TestFileDescriptorLimits(t *testing.T) {
3636
if limit, err := Current(); err != nil || limit <= 0 {
3737
t.Fatalf("failed to retrieve file descriptor limit (%d): %v", limit, err)
3838
}
39-
if err := Raise(uint64(target)); err != nil {
39+
if _, err := Raise(uint64(target)); err != nil {
4040
t.Fatalf("failed to raise file allowance")
4141
}
4242
if limit, err := Current(); err != nil || limit < target {

common/fdlimit/fdlimit_unix.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,34 @@
1414
// You should have received a copy of the GNU Lesser General Public License
1515
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
1616

17-
// +build linux darwin netbsd openbsd solaris
17+
// +build linux netbsd openbsd solaris
1818

1919
package fdlimit
2020

2121
import "syscall"
2222

2323
// Raise tries to maximize the file descriptor allowance of this process
2424
// to the maximum hard-limit allowed by the OS.
25-
func Raise(max uint64) error {
25+
// Returns the size it was set to (may differ from the desired 'max')
26+
func Raise(max uint64) (uint64, error) {
2627
// Get the current limit
2728
var limit syscall.Rlimit
2829
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
29-
return err
30+
return 0, err
3031
}
3132
// Try to update the limit to the max allowance
3233
limit.Cur = limit.Max
3334
if limit.Cur > max {
3435
limit.Cur = max
3536
}
3637
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
37-
return err
38+
return 0, err
39+
}
40+
// MacOS can silently apply further caps, so retrieve the actually set limit
41+
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil {
42+
return 0, err
3843
}
39-
return nil
44+
return limit.Cur, nil
4045
}
4146

4247
// Current retrieves the number of file descriptors allowed to be opened by this

common/fdlimit/fdlimit_windows.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,28 +16,31 @@
1616

1717
package fdlimit
1818

19-
import "errors"
19+
import "fmt"
20+
21+
// hardlimit is the number of file descriptors allowed at max by the kernel.
22+
const hardlimit = 16384
2023

2124
// Raise tries to maximize the file descriptor allowance of this process
2225
// to the maximum hard-limit allowed by the OS.
23-
func Raise(max uint64) error {
26+
func Raise(max uint64) (uint64, error) {
2427
// This method is NOP by design:
2528
// * Linux/Darwin counterparts need to manually increase per process limits
2629
// * On Windows Go uses the CreateFile API, which is limited to 16K files, non
2730
// changeable from within a running process
2831
// This way we can always "request" raising the limits, which will either have
2932
// or not have effect based on the platform we're running on.
30-
if max > 16384 {
31-
return errors.New("file descriptor limit (16384) reached")
33+
if max > hardlimit {
34+
return hardlimit, fmt.Errorf("file descriptor limit (%d) reached", hardlimit)
3235
}
33-
return nil
36+
return max, nil
3437
}
3538

3639
// Current retrieves the number of file descriptors allowed to be opened by this
3740
// process.
3841
func Current() (int, error) {
3942
// Please see Raise for the reason why we use hard coded 16K as the limit
40-
return 16384, nil
43+
return hardlimit, nil
4144
}
4245

4346
// Maximum retrieves the maximum number of file descriptors this process is

core/tx_pool_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ func validateEvents(events chan NewTxsEvent, count int) error {
139139
case ev := <-events:
140140
received = append(received, ev.Txs...)
141141
case <-time.After(time.Second):
142-
return fmt.Errorf("event #%d not fired", received)
142+
return fmt.Errorf("event #%d not fired", len(received))
143143
}
144144
}
145145
if len(received) > count {

crypto/bn256/cloudflare/main_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ func TestRandomG2Marshal(t *testing.T) {
1313
t.Error(err)
1414
continue
1515
}
16-
t.Logf("%d: %x\n", n, g2.Marshal())
16+
t.Logf("%v: %x\n", n, g2.Marshal())
1717
}
1818
}
1919

crypto/bn256/google/main_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ func TestRandomG2Marshal(t *testing.T) {
1313
t.Error(err)
1414
continue
1515
}
16-
t.Logf("%d: %x\n", n, g2.Marshal())
16+
t.Logf("%v: %x\n", n, g2.Marshal())
1717
}
1818
}
1919

0 commit comments

Comments
 (0)