github.com/pingcap/tidb-lightning@v5.0.0-rc.0.20210428090220-84b649866577+incompatible/lightning/backend/local_unix.go (about) 1 // Copyright 2020 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 // +build !windows 15 16 package backend 17 18 import ( 19 "syscall" 20 21 "github.com/pingcap/errors" 22 "github.com/pingcap/failpoint" 23 "go.uber.org/zap" 24 25 "github.com/pingcap/tidb-lightning/lightning/log" 26 ) 27 28 const ( 29 // mininum max open files value 30 minRLimit = 1024 31 ) 32 33 func GetSystemRLimit() (uint64, error) { 34 var rLimit syscall.Rlimit 35 err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) 36 return rLimit.Cur, err 37 } 38 39 // VerifyRLimit checks whether the open-file limit is large enough. 40 // In Local-backend, we need to read and write a lot of L0 SST files, so we need 41 // to check system max open files limit. 42 func VerifyRLimit(estimateMaxFiles uint64) error { 43 if estimateMaxFiles < minRLimit { 44 estimateMaxFiles = minRLimit 45 } 46 var rLimit syscall.Rlimit 47 err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) 48 failpoint.Inject("GetRlimitValue", func(v failpoint.Value) { 49 limit := uint64(v.(int)) 50 rLimit.Cur = limit 51 rLimit.Max = limit 52 err = nil 53 }) 54 if err != nil { 55 return errors.Trace(err) 56 } 57 if rLimit.Cur >= estimateMaxFiles { 58 return nil 59 } 60 if rLimit.Max < estimateMaxFiles { 61 // If the process is not started by privileged user, this will fail. 62 rLimit.Max = estimateMaxFiles 63 } 64 prevLimit := rLimit.Cur 65 rLimit.Cur = estimateMaxFiles 66 failpoint.Inject("SetRlimitError", func(v failpoint.Value) { 67 if v.(bool) { 68 err = errors.New("Setrlimit Injected Error") 69 } 70 }) 71 if err == nil { 72 err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit) 73 } 74 if err != nil { 75 return errors.Annotatef(err, "the maximum number of open file descriptors is too small, got %d, expect greater or equal to %d", prevLimit, estimateMaxFiles) 76 } 77 78 // fetch the rlimit again to make sure our setting has taken effect 79 err = syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) 80 if err != nil { 81 return errors.Trace(err) 82 } 83 if rLimit.Cur < estimateMaxFiles { 84 helper := "Please manually execute `ulimit -n %d` to increase the open files limit." 85 return errors.Errorf("cannot update the maximum number of open file descriptors, expected: %d, got: %d. %s", 86 estimateMaxFiles, rLimit.Cur, helper) 87 } 88 89 log.L().Info("Set the maximum number of open file descriptors(rlimit)", 90 zap.Uint64("old", prevLimit), zap.Uint64("new", estimateMaxFiles)) 91 return nil 92 }