github.com/zhyoulun/cilium@v1.6.12/pkg/eventqueue/eventqueue.go (about) 1 // Copyright 2019 Authors of Cilium 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 eventqueue 16 17 import ( 18 "fmt" 19 "reflect" 20 "sync" 21 "sync/atomic" 22 23 "github.com/cilium/cilium/pkg/lock" 24 "github.com/cilium/cilium/pkg/logging" 25 "github.com/cilium/cilium/pkg/logging/logfields" 26 "github.com/cilium/cilium/pkg/option" 27 "github.com/cilium/cilium/pkg/spanstat" 28 29 "github.com/sirupsen/logrus" 30 ) 31 32 var ( 33 log = logging.DefaultLogger.WithField(logfields.LogSubsys, "eventqueue") 34 ) 35 36 // EventQueue is a structure which is utilized to handle Events in a first-in, 37 // first-out order. An EventQueue may be closed, in which case all events which 38 // are queued up, but have not been processed yet, will be cancelled (i.e., not 39 // ran). It is guaranteed that no events will be scheduled onto an EventQueue 40 // after it has been closed; if any event is attempted to be scheduled onto an 41 // EventQueue after it has been closed, it will be cancelled immediately. For 42 // any event to be processed by the EventQueue, it must implement the 43 // `EventHandler` interface. This allows for different types of events to be 44 // processed by anything which chooses to utilize an `EventQueue`. 45 type EventQueue struct { 46 47 // This should always be a buffered channel. 48 events chan *Event 49 50 // close is closed once the EventQueue has been closed. 51 close chan struct{} 52 53 // drain is closed when the EventQueue is stopped. Any Event which is 54 // Enqueued after this channel is closed will be cancelled / not processed 55 // by the queue. If an Event has been Enqueued, but has not been processed 56 // before this channel is closed, it will be cancelled and not processed 57 // as well. 58 drain chan struct{} 59 60 // eventQueueOnce is used to ensure that the EventQueue business logic can 61 // only be ran once. 62 eventQueueOnce sync.Once 63 64 // closeOnce is used to ensure that the EventQueue can only be closed once. 65 closeOnce sync.Once 66 67 // name is used to differentiate this EventQueue from other EventQueues that 68 // are also running in logs 69 name string 70 71 eventsMu lock.RWMutex 72 } 73 74 // NewEventQueue returns an EventQueue with a capacity for only one event at 75 // a time. 76 func NewEventQueue() *EventQueue { 77 return NewEventQueueBuffered("", 1) 78 79 } 80 81 func (q *EventQueue) getLogger() *logrus.Entry { 82 return log.WithFields( 83 logrus.Fields{ 84 "name": q.name, 85 }) 86 } 87 88 // NewEventQueueBuffered returns an EventQueue with a capacity of, 89 // numBufferedEvents at a time, and all other needed fields initialized. 90 func NewEventQueueBuffered(name string, numBufferedEvents int) *EventQueue { 91 log.WithFields(logrus.Fields{ 92 "name": name, 93 "numBufferedEvents": numBufferedEvents, 94 }).Debug("creating new EventQueue") 95 return &EventQueue{ 96 name: name, 97 // Up to numBufferedEvents can be Enqueued until Enqueueing blocks. 98 events: make(chan *Event, numBufferedEvents), 99 close: make(chan struct{}), 100 drain: make(chan struct{}), 101 } 102 103 } 104 105 // Event is an event that can be enqueued onto an EventQueue. 106 type Event struct { 107 // Metadata is the information about the event which is sent 108 // by its queuer. Metadata must implement the EventHandler interface in 109 // order for the Event to be successfully processed by the EventQueue. 110 Metadata EventHandler 111 112 // eventResults is a channel on which the results of the event are sent. 113 // It is populated by the EventQueue itself, not by the queuer. This channel 114 // is closed if the event is cancelled. 115 eventResults chan interface{} 116 117 // cancelled signals that the given Event was not ran. This can happen 118 // if the EventQueue processing this Event was closed before the Event was 119 // Enqueued onto the Event queue, or if the Event was Enqueued onto an 120 // EventQueue, and the EventQueue on which the Event was scheduled was 121 // closed. 122 cancelled chan struct{} 123 124 // stats is a field which contains information about when this event is 125 // enqueued, dequeued, etc. 126 stats eventStatistics 127 128 // enqueued is an atomic boolean that specifies whether this event has 129 // been enqueued on an EventQueue. 130 enqueued int32 131 } 132 133 type eventStatistics struct { 134 135 // waitEnqueue shows how long a given event was waiting on the queue before 136 // it was actually processed. 137 waitEnqueue spanstat.SpanStat 138 139 // durationStat shows how long the actual processing of the event took. This 140 // is the time for how long Handle() takes for the event. 141 durationStat spanstat.SpanStat 142 143 // waitConsumeOffQueue shows how long it took for the event to be consumed 144 // plus the time it the event waited in the queue. 145 waitConsumeOffQueue spanstat.SpanStat 146 } 147 148 // NewEvent returns an Event with all fields initialized. 149 func NewEvent(meta EventHandler) *Event { 150 return &Event{ 151 Metadata: meta, 152 eventResults: make(chan interface{}, 1), 153 cancelled: make(chan struct{}), 154 stats: eventStatistics{}, 155 } 156 } 157 158 // WasCancelled returns whether the cancelled channel for the given Event has 159 // been closed or not. Cancellation occurs if the event was not processed yet 160 // by an EventQueue onto which this Event was Enqueued, and the queue is closed, 161 // or if the event was attempted to be scheduled onto an EventQueue which has 162 // already been closed. 163 func (ev *Event) WasCancelled() bool { 164 select { 165 case <-ev.cancelled: 166 return true 167 default: 168 return false 169 } 170 } 171 172 // Enqueue pushes the given event onto the EventQueue. If the queue has been 173 // stopped, the Event will not be enqueued, and its cancel channel will be 174 // closed, indicating that the Event was not ran. This function may block if 175 // the queue is at its capacity for events. If a single Event has Enqueue 176 // called on it multiple times asynchronously, there is no guarantee as to 177 // which one will return the channel which passes results back to the caller. 178 // It is up to the caller to check whether the returned channel is nil, as 179 // waiting to receive on such a channel will block forever. Returns an error 180 // if the Event has been previously enqueued, if the Event is nil, or the queue 181 // itself is not initialized properly. 182 func (q *EventQueue) Enqueue(ev *Event) (<-chan interface{}, error) { 183 if q.notSafeToAccess() || ev == nil { 184 return nil, fmt.Errorf("unable to Enqueue event") 185 } 186 187 // Multiple Enqueues can occur at the same time. Ensure that events channel 188 // is not closed while we are enqueueing events. 189 q.eventsMu.RLock() 190 defer q.eventsMu.RUnlock() 191 192 // Events can only be enqueued once. 193 if atomic.AddInt32(&ev.enqueued, 1) > 1 { 194 return nil, fmt.Errorf("unable to Enqueue event; event has already had Enqueue called on it") 195 } 196 197 select { 198 // The event should be drained from the queue (e.g., it should not be 199 // processed). 200 case <-q.drain: 201 // Closed eventResults channel signifies cancellation. 202 close(ev.cancelled) 203 close(ev.eventResults) 204 205 return ev.eventResults, nil 206 default: 207 // The events channel may be closed even if an event has been pushed 208 // onto the events channel, as events are consumed off of the events 209 // channel asynchronously! If the EventQueue is closed before this 210 // event is processed, then it will be cancelled. 211 212 ev.stats.waitEnqueue.Start() 213 ev.stats.waitConsumeOffQueue.Start() 214 q.events <- ev 215 ev.stats.waitEnqueue.End(true) 216 return ev.eventResults, nil 217 } 218 } 219 220 func (ev *Event) printStats(q *EventQueue) { 221 if option.Config.Debug { 222 q.getLogger().WithFields(logrus.Fields{ 223 "eventType": reflect.TypeOf(ev.Metadata).String(), 224 "eventHandlingDuration": ev.stats.durationStat.Total(), 225 "eventEnqueueWaitTime": ev.stats.waitEnqueue.Total(), 226 "eventConsumeOffQueueWaitTime": ev.stats.waitConsumeOffQueue.Total(), 227 }).Debug("EventQueue event processing statistics") 228 } 229 } 230 231 // Run consumes events that have been queued for this EventQueue. It 232 // is presumed that the eventQueue is a buffered channel with a length of one 233 // (i.e., only one event can be processed at a time). All business logic for 234 // handling queued events is contained within this function. The events in the 235 // queue must implement the EventHandler interface. If the event queue is 236 // closed, then all events which were queued up, but not processed, are 237 // cancelled; any event which is currently being processed will not be 238 // cancelled. 239 func (q *EventQueue) Run() { 240 241 if q.notSafeToAccess() { 242 return 243 } 244 245 go q.eventQueueOnce.Do(func() { 246 for ev := range q.events { 247 select { 248 case <-q.drain: 249 ev.stats.waitConsumeOffQueue.End(false) 250 close(ev.cancelled) 251 close(ev.eventResults) 252 ev.printStats(q) 253 default: 254 ev.stats.waitConsumeOffQueue.End(true) 255 ev.stats.durationStat.Start() 256 ev.Metadata.Handle(ev.eventResults) 257 // Always indicate success for now. 258 ev.stats.durationStat.End(true) 259 // Ensures that no more results can be sent as the event has 260 // already been processed. 261 ev.printStats(q) 262 close(ev.eventResults) 263 } 264 } 265 }) 266 } 267 268 func (q *EventQueue) notSafeToAccess() bool { 269 return q == nil || q.close == nil || q.drain == nil || q.events == nil 270 } 271 272 // Stop stops any further events from being processed by the EventQueue. Any 273 // event which is currently being processed by the EventQueue will continue to 274 // run. All other events waiting to be processed, and all events that may be 275 // enqueued will not be processed by the event queue; they will be cancelled. 276 // If the queue has already been stopped, this is a no-op. 277 func (q *EventQueue) Stop() { 278 if q.notSafeToAccess() { 279 return 280 } 281 282 q.closeOnce.Do(func() { 283 q.getLogger().Debug("stopping EventQueue") 284 // Any event that is sent to the queue at this point will be cancelled 285 // immediately in Enqueue(). 286 close(q.drain) 287 288 // Signal that the queue has been drained. 289 close(q.close) 290 291 q.eventsMu.Lock() 292 close(q.events) 293 q.eventsMu.Unlock() 294 }) 295 } 296 297 // WaitToBeDrained returns the channel which waits for the EventQueue to have been 298 // stopped. This allows for queuers to ensure that all events in the queue have 299 // been processed or cancelled. If the queue is nil, returns immediately. 300 func (q *EventQueue) WaitToBeDrained() { 301 if q == nil { 302 return 303 } 304 <-q.close 305 } 306 307 // EventHandler is an interface for allowing an EventQueue to handle events 308 // in a generic way. To be processed by the EventQueue, all event types must 309 // implement any function specified in this interface. 310 type EventHandler interface { 311 Handle(chan interface{}) 312 }