github.com/pawelgaczynski/gain@v0.4.0-alpha.0.20230821120126-41f1e60a18da/config.go (about) 1 // Copyright (c) 2023 Paweł Gaczyński 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package gain 16 17 import ( 18 "runtime" 19 "time" 20 21 "github.com/rs/zerolog" 22 ) 23 24 const ( 25 defaultPort = 8080 26 defaultMaxCQEvents = 16384 27 defaultMaxSQEntries = 16384 28 defaultRecvBufferSize = 4096 29 defaultSendBufferSize = 4096 30 ) 31 32 type Option[T any] func(*T) 33 34 type ConfigOption Option[Config] 35 36 type ServerArchitecture int 37 38 const ( 39 // Reactor design pattern has one input called Acceptor, 40 // which demultiplexes the handling of incoming connections to Consumer workers. 41 // The load balancing algorithm can be selected via configuration option. 42 Reactor ServerArchitecture = iota 43 // The Socket Sharding allow multiple workers to listen on the same address and port combination. 44 // In this case the kernel distributes incoming requests across all the sockets. 45 SocketSharding 46 ) 47 48 // Config is the configuration for the gain engine. 49 type Config struct { 50 // Architecture indicates one of the two available architectures: Reactor and SocketSharding. 51 // 52 // The Reactor design pattern has one input called Acceptor, 53 // which demultiplexes the handling of incoming connections to Consumer workers. 54 // The load balancing algorithm can be selected via configuration option. 55 // 56 // The Socket Sharding allows multiple workers to listen on the same address and port combination. 57 // In this case the kernel distributes incoming requests across all the sockets. 58 Architecture ServerArchitecture 59 // AsyncHandler indicates whether the engine should run the OnRead EventHandler method in a separate goroutines. 60 AsyncHandler bool 61 // GoroutinePool indicates use of pool of bounded goroutines for OnRead calls. 62 // Important: Valid only if AsyncHandler is true 63 GoroutinePool bool 64 // CPUAffinity determines whether each engine worker is locked to the one CPU. 65 CPUAffinity bool 66 // ProcessPriority sets the prority of the process to high (-19). Requires root privileges. 67 ProcessPriority bool 68 // Workers indicates the number of consumers or shard workers. The default is runtime.NumCPU(). 69 Workers int 70 // CBPFilter uses custom BPF filter to improve the performance of the Socket Sharding architecture. 71 CBPFilter bool 72 // LoadBalancing indicates the load-balancing algorithm to use when assigning a new connection. 73 // Important: valid only for Reactor architecture. 74 LoadBalancing LoadBalancing 75 // SocketRecvBufferSize sets the maximum socket receive buffer in bytes. 76 SocketRecvBufferSize int 77 // SocketSendBufferSize sets the maximum socket send buffer in bytes. 78 SocketSendBufferSize int 79 // TCPKeepAlive sets the TCP keep-alive for the socket. 80 TCPKeepAlive time.Duration 81 // LoggerLevel indicates the logging level. 82 LoggerLevel zerolog.Level 83 // PrettyLogger sets the pretty-printing zerolog mode. 84 // Important: it is inefficient so should be used only for debugging. 85 PrettyLogger bool 86 87 // ============================== 88 // io_uring related options 89 // ============================== 90 // MaxSQEntries sets the maximum number of SQEs that can be submitted in one batch. 91 // If the number of SQEs exceeds this value, the io_uring will return a SQE overflow error. 92 MaxSQEntries uint 93 // MaxCQEvents sets the maximum number of CQEs that can be retrieved in one batch. 94 MaxCQEvents uint 95 } 96 97 // WithArchitecture sets the architecture of gain engine. 98 func WithArchitecture(architecture ServerArchitecture) ConfigOption { 99 return func(c *Config) { 100 c.Architecture = architecture 101 } 102 } 103 104 // WithAsyncHandler sets the asynchronous mode for the OnRead callback. 105 func WithAsyncHandler(asyncHandler bool) ConfigOption { 106 return func(c *Config) { 107 c.AsyncHandler = asyncHandler 108 } 109 } 110 111 // WithGoroutinePool sets the goroutine pool for asynchronous handler. 112 func WithGoroutinePool(goroutinePool bool) ConfigOption { 113 return func(c *Config) { 114 c.GoroutinePool = goroutinePool 115 } 116 } 117 118 // WithCPUAffinity sets the CPU affinity option. 119 func WithCPUAffinity(cpuAffinity bool) ConfigOption { 120 return func(c *Config) { 121 c.CPUAffinity = cpuAffinity 122 } 123 } 124 125 // WithProcessPriority sets the high process priority. Note: requires root privileges. 126 func WithProcessPriority(processPriority bool) ConfigOption { 127 return func(c *Config) { 128 c.ProcessPriority = processPriority 129 } 130 } 131 132 // WithWorkers sets the number of workers. 133 func WithWorkers(workers int) ConfigOption { 134 return func(c *Config) { 135 c.Workers = workers 136 } 137 } 138 139 // WithCBPF sets the CBPF filter for the gain engine. 140 func WithCBPF(cbpf bool) ConfigOption { 141 return func(c *Config) { 142 c.CBPFilter = cbpf 143 } 144 } 145 146 // WithLoadBalancing sets the load balancing algorithm. 147 func WithLoadBalancing(loadBalancing LoadBalancing) ConfigOption { 148 return func(c *Config) { 149 c.LoadBalancing = loadBalancing 150 } 151 } 152 153 // WithSocketRecvBufferSize sets the maximum socket receive buffer in bytes. 154 func WithSocketRecvBufferSize(size int) ConfigOption { 155 return func(c *Config) { 156 c.SocketRecvBufferSize = size 157 } 158 } 159 160 // WithSocketSendBufferSize sets the maximum socket send buffer in bytes. 161 func WithSocketSendBufferSize(size int) ConfigOption { 162 return func(c *Config) { 163 c.SocketSendBufferSize = size 164 } 165 } 166 167 // WithTCPKeepAlive sets the TCP keep-alive for the socket. 168 func WithTCPKeepAlive(tcpKeepAlive time.Duration) ConfigOption { 169 return func(c *Config) { 170 c.TCPKeepAlive = tcpKeepAlive 171 } 172 } 173 174 // WithLoggerLevel sets the logging level. 175 func WithLoggerLevel(loggerLevel zerolog.Level) ConfigOption { 176 return func(c *Config) { 177 c.LoggerLevel = loggerLevel 178 } 179 } 180 181 // WithPrettyLogger sets the pretty-printing zerolog mode. 182 func WithPrettyLogger(prettyLogger bool) ConfigOption { 183 return func(c *Config) { 184 c.PrettyLogger = prettyLogger 185 } 186 } 187 188 // WithMaxSQEntries sets the maximum number of entries in the submission queue. 189 func WithMaxSQEntries(maxSQEntries uint) ConfigOption { 190 return func(c *Config) { 191 c.MaxSQEntries = maxSQEntries 192 } 193 } 194 195 // WithMaxCQEvents sets the maximum number of entries in the completion queue. 196 func WithMaxCQEvents(maxCQEvents uint) ConfigOption { 197 return func(c *Config) { 198 c.MaxCQEvents = maxCQEvents 199 } 200 } 201 202 func NewConfig(opts ...ConfigOption) Config { 203 config := Config{ 204 Architecture: Reactor, 205 AsyncHandler: false, 206 GoroutinePool: false, 207 CPUAffinity: false, 208 ProcessPriority: false, 209 LoggerLevel: zerolog.ErrorLevel, 210 PrettyLogger: false, 211 Workers: runtime.NumCPU(), 212 CBPFilter: false, 213 LoadBalancing: RoundRobin, 214 SocketRecvBufferSize: 0, 215 SocketSendBufferSize: 0, 216 TCPKeepAlive: 0, 217 MaxSQEntries: defaultMaxSQEntries, 218 MaxCQEvents: defaultMaxCQEvents, 219 } 220 for _, opt := range opts { 221 opt(&config) 222 } 223 224 return config 225 }