github.com/pawelgaczynski/gain@v0.4.0-alpha.0.20230821120126-41f1e60a18da/worker.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 "syscall" 19 20 "github.com/pawelgaczynski/giouring" 21 "github.com/rs/zerolog" 22 "golang.org/x/sys/unix" 23 ) 24 25 type startSignal int 26 27 const ( 28 done startSignal = iota 29 ) 30 31 type worker interface { 32 loop(socket int) error 33 setIndex(index int) 34 index() int 35 shutdown() 36 ringFd() int 37 started() bool 38 close() 39 } 40 41 type workerStartListener func() 42 43 type workerConfig struct { 44 cpuAffinity bool 45 processPriority bool 46 maxSQEntries uint 47 maxCQEvents int 48 loggerLevel zerolog.Level 49 prettyLogger bool 50 } 51 52 type workerImpl struct { 53 *looper 54 *connCloser 55 *shutdowner 56 idx int 57 logger zerolog.Logger 58 startedChan chan startSignal 59 onCloseHandler func() 60 } 61 62 func (w *workerImpl) ringFd() int { 63 return w.looper.ring.RingFd() 64 } 65 66 func (w *workerImpl) setIndex(index int) { 67 w.idx = index 68 } 69 70 func (w *workerImpl) index() int { 71 return w.idx 72 } 73 74 func (w *workerImpl) processEvent(cqe *giouring.CompletionQueueEvent, 75 skipErrorChecker func(*giouring.CompletionQueueEvent) bool, 76 ) bool { 77 w.logDebug(). 78 Int32("Res", cqe.Res). 79 Uint64("req key", cqe.UserData & ^allFlagsMask). 80 Uint64("user data", cqe.UserData). 81 Str("req flag", flagToString(cqe.UserData)). 82 Msg("Process event") 83 84 switch { 85 case cqe.Res < 0: 86 if !skipErrorChecker(cqe) { 87 w.logError(nil). 88 Str("error", unix.ErrnoName(-syscall.Errno(cqe.Res))). 89 Str("req flag", flagToString(cqe.UserData)). 90 Uint64("req key", cqe.UserData & ^allFlagsMask). 91 Uint64("user data", cqe.UserData). 92 Msg("worker request returns error code") 93 } 94 95 return true 96 97 case cqe.UserData == 0: 98 w.logError(nil). 99 Msg("user data flag is missing") 100 101 return true 102 } 103 104 return false 105 } 106 107 func (w *workerImpl) logDebug() *zerolog.Event { 108 return w.logger.Debug().Int("worker index", w.index()).Int("ring fd", w.ringFd()) 109 } 110 111 func (w *workerImpl) logInfo() *zerolog.Event { 112 return w.logger.Info().Int("worker index", w.index()).Int("ring fd", w.ringFd()) 113 } 114 115 func (w *workerImpl) logWarn() *zerolog.Event { 116 return w.logger.Warn().Int("worker index", w.index()).Int("ring fd", w.ringFd()) 117 } 118 119 func (w *workerImpl) logError(err error) *zerolog.Event { 120 return w.logger.Error().Int("worker index", w.index()).Int("ring fd", w.ringFd()).Err(err) 121 } 122 123 func (w *workerImpl) close() { 124 if w.looper.ring != nil { 125 w.looper.ring.QueueExit() 126 } 127 } 128 129 func newWorkerImpl( 130 ring *giouring.Ring, config workerConfig, index int, logger zerolog.Logger, 131 ) *workerImpl { 132 return &workerImpl{ 133 logger: logger, 134 shutdowner: newShutdowner(), 135 connCloser: newConnCloser(ring, logger), 136 looper: newLooper(ring, config.cpuAffinity, config.processPriority, config.maxCQEvents), 137 startedChan: make(chan startSignal), 138 idx: index, 139 } 140 }