forked from cloudwego/netpoll
-
Notifications
You must be signed in to change notification settings - Fork 0
/
poll_manager.go
134 lines (116 loc) · 3.14 KB
/
poll_manager.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2022 CloudWeGo Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:build !windows
// +build !windows
package netpoll
import (
"fmt"
"io"
"log"
"os"
"runtime"
)
func setNumLoops(numLoops int) error {
return pollmanager.SetNumLoops(numLoops)
}
func setLoadBalance(lb LoadBalance) error {
return pollmanager.SetLoadBalance(lb)
}
func setLoggerOutput(w io.Writer) {
logger = log.New(w, "", log.LstdFlags)
}
// manage all pollers
var pollmanager *manager
var logger *log.Logger
func init() {
var loops = runtime.GOMAXPROCS(0)/20 + 1
pollmanager = &manager{}
pollmanager.SetLoadBalance(RoundRobin)
pollmanager.SetNumLoops(loops)
setLoggerOutput(os.Stderr)
}
// LoadBalance is used to do load balancing among multiple pollers.
// a single poller may not be optimal if the number of cores is large (40C+).
type manager struct {
NumLoops int
balance loadbalance // load balancing method
polls []Poll // all the polls
}
// SetNumLoops will return error when set numLoops < 1
func (m *manager) SetNumLoops(numLoops int) error {
if numLoops < 1 {
return fmt.Errorf("set invalid numLoops[%d]", numLoops)
}
if numLoops < m.NumLoops {
// if less than, close the redundant pollers
var polls = make([]Poll, numLoops)
for idx := 0; idx < m.NumLoops; idx++ {
if idx < numLoops {
polls[idx] = m.polls[idx]
} else {
if err := m.polls[idx].Close(); err != nil {
logger.Printf("NETPOLL: poller close failed: %v\n", err)
}
}
}
m.NumLoops = numLoops
m.polls = polls
m.balance.Rebalance(m.polls)
return nil
}
m.NumLoops = numLoops
return m.Run()
}
// SetLoadBalance set load balance.
func (m *manager) SetLoadBalance(lb LoadBalance) error {
if m.balance != nil && m.balance.LoadBalance() == lb {
return nil
}
m.balance = newLoadbalance(lb, m.polls)
return nil
}
// Close release all resources.
func (m *manager) Close() error {
for _, poll := range m.polls {
poll.Close()
}
m.NumLoops = 0
m.balance = nil
m.polls = nil
return nil
}
// Run all pollers.
func (m *manager) Run() error {
// new poll to fill delta.
for idx := len(m.polls); idx < m.NumLoops; idx++ {
var poll = openPoll()
m.polls = append(m.polls, poll)
go poll.Wait()
}
// LoadBalance must be set before calling Run, otherwise it will panic.
m.balance.Rebalance(m.polls)
return nil
}
// Reset pollers, this operation is very dangerous, please make sure to do this when calling !
func (m *manager) Reset() error {
for _, poll := range m.polls {
poll.Close()
}
m.polls = nil
return m.Run()
}
// Pick will select the poller for use each time based on the LoadBalance.
func (m *manager) Pick() Poll {
return m.balance.Pick()
}