github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/beacon/light/request/scheduler.go (about) 1 // Copyright 2023 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package request 18 19 import ( 20 "sync" 21 22 "github.com/ethereum/go-ethereum/log" 23 ) 24 25 // Module represents a mechanism which is typically responsible for downloading 26 // and updating a passive data structure. It does not directly interact with the 27 // servers. It can start requests using the Requester interface, maintain its 28 // internal state by receiving and processing Events and update its target data 29 // structure based on the obtained data. 30 // It is the Scheduler's responsibility to feed events to the modules, call 31 // Process as long as there might be something to process and then generate request 32 // candidates using MakeRequest and start the best possible requests. 33 // Modules are called by Scheduler whenever a global trigger is fired. All events 34 // fire the trigger. Changing a target data structure also triggers a next 35 // processing round as it could make further actions possible either by the same 36 // or another Module. 37 type Module interface { 38 // Process is a non-blocking function responsible for starting requests, 39 // processing events and updating the target data structures(s) and the 40 // internal state of the module. Module state typically consists of information 41 // about pending requests and registered servers. 42 // Process is always called after an event is received or after a target data 43 // structure has been changed. 44 // 45 // Note: Process functions of different modules are never called concurrently; 46 // they are called by Scheduler in the same order of priority as they were 47 // registered in. 48 Process(Requester, []Event) 49 } 50 51 // Requester allows Modules to obtain the list of momentarily available servers, 52 // start new requests and report server failure when a response has been proven 53 // to be invalid in the processing phase. 54 // Note that all Requester functions should be safe to call from Module.Process. 55 type Requester interface { 56 CanSendTo() []Server 57 Send(Server, Request) ID 58 Fail(Server, string) 59 } 60 61 // Scheduler is a modular network data retrieval framework that coordinates multiple 62 // servers and retrieval mechanisms (modules). It implements a trigger mechanism 63 // that calls the Process function of registered modules whenever either the state 64 // of existing data structures or events coming from registered servers could 65 // allow new operations. 66 type Scheduler struct { 67 lock sync.Mutex 68 modules []Module // first has the highest priority 69 names map[Module]string 70 servers map[server]struct{} 71 targets map[targetData]uint64 72 73 requesterLock sync.RWMutex 74 serverOrder []server 75 pending map[ServerAndID]pendingRequest 76 77 // eventLock guards access to the events list. Note that eventLock can be 78 // locked either while lock is locked or unlocked but lock cannot be locked 79 // while eventLock is locked. 80 eventLock sync.Mutex 81 events []Event 82 stopCh chan chan struct{} 83 84 triggerCh chan struct{} // restarts waiting sync loop 85 // if trigger has already been fired then send to testWaitCh blocks until 86 // the triggered processing round is finished 87 testWaitCh chan struct{} 88 } 89 90 type ( 91 // Server identifies a server without allowing any direct interaction. 92 // Note: server interface is used by Scheduler and Tracker but not used by 93 // the modules that do not interact with them directly. 94 // In order to make module testing easier, Server interface is used in 95 // events and modules. 96 Server interface { 97 Name() string 98 } 99 Request any 100 Response any 101 ID uint64 102 ServerAndID struct { 103 Server Server 104 ID ID 105 } 106 ) 107 108 // targetData represents a registered target data structure that increases its 109 // ChangeCounter whenever it has been changed. 110 type targetData interface { 111 ChangeCounter() uint64 112 } 113 114 // pendingRequest keeps track of sent and not yet finalized requests and their 115 // sender modules. 116 type pendingRequest struct { 117 request Request 118 module Module 119 } 120 121 // NewScheduler creates a new Scheduler. 122 func NewScheduler() *Scheduler { 123 s := &Scheduler{ 124 servers: make(map[server]struct{}), 125 names: make(map[Module]string), 126 pending: make(map[ServerAndID]pendingRequest), 127 targets: make(map[targetData]uint64), 128 stopCh: make(chan chan struct{}), 129 // Note: testWaitCh should not have capacity in order to ensure 130 // that after a trigger happens testWaitCh will block until the resulting 131 // processing round has been finished 132 triggerCh: make(chan struct{}, 1), 133 testWaitCh: make(chan struct{}), 134 } 135 return s 136 } 137 138 // RegisterTarget registers a target data structure, ensuring that any changes 139 // made to it trigger a new round of Module.Process calls, giving a chance to 140 // modules to react to the changes. 141 func (s *Scheduler) RegisterTarget(t targetData) { 142 s.lock.Lock() 143 defer s.lock.Unlock() 144 145 s.targets[t] = 0 146 } 147 148 // RegisterModule registers a module. Should be called before starting the scheduler. 149 // In each processing round the order of module processing depends on the order of 150 // registration. 151 func (s *Scheduler) RegisterModule(m Module, name string) { 152 s.lock.Lock() 153 defer s.lock.Unlock() 154 155 s.modules = append(s.modules, m) 156 s.names[m] = name 157 } 158 159 // RegisterServer registers a new server. 160 func (s *Scheduler) RegisterServer(server server) { 161 s.lock.Lock() 162 defer s.lock.Unlock() 163 164 s.addEvent(Event{Type: EvRegistered, Server: server}) 165 server.subscribe(func(event Event) { 166 event.Server = server 167 s.addEvent(event) 168 }) 169 } 170 171 // UnregisterServer removes a registered server. 172 func (s *Scheduler) UnregisterServer(server server) { 173 s.lock.Lock() 174 defer s.lock.Unlock() 175 176 server.unsubscribe() 177 s.addEvent(Event{Type: EvUnregistered, Server: server}) 178 } 179 180 // Start starts the scheduler. It should be called after registering all modules 181 // and before registering any servers. 182 func (s *Scheduler) Start() { 183 go s.syncLoop() 184 } 185 186 // Stop stops the scheduler. 187 func (s *Scheduler) Stop() { 188 stop := make(chan struct{}) 189 s.stopCh <- stop 190 <-stop 191 s.lock.Lock() 192 for server := range s.servers { 193 server.unsubscribe() 194 } 195 s.servers = nil 196 s.lock.Unlock() 197 } 198 199 // syncLoop is the main event loop responsible for event/data processing and 200 // sending new requests. 201 // A round of processing starts whenever the global trigger is fired. Triggers 202 // fired during a processing round ensure that there is going to be a next round. 203 func (s *Scheduler) syncLoop() { 204 for { 205 s.lock.Lock() 206 s.processRound() 207 s.lock.Unlock() 208 loop: 209 for { 210 select { 211 case stop := <-s.stopCh: 212 close(stop) 213 return 214 case <-s.triggerCh: 215 break loop 216 case <-s.testWaitCh: 217 } 218 } 219 } 220 } 221 222 // targetChanged returns true if a registered target data structure has been 223 // changed since the last call to this function. 224 func (s *Scheduler) targetChanged() (changed bool) { 225 for target, counter := range s.targets { 226 if newCounter := target.ChangeCounter(); newCounter != counter { 227 s.targets[target] = newCounter 228 changed = true 229 } 230 } 231 return 232 } 233 234 // processRound runs an entire processing round. It calls the Process functions 235 // of all modules, passing all relevant events and repeating Process calls as 236 // long as any changes have been made to the registered target data structures. 237 // Once all events have been processed and a stable state has been achieved, 238 // requests are generated and sent if necessary and possible. 239 func (s *Scheduler) processRound() { 240 for { 241 log.Trace("Processing modules") 242 filteredEvents := s.filterEvents() 243 for _, module := range s.modules { 244 log.Trace("Processing module", "name", s.names[module], "events", len(filteredEvents[module])) 245 module.Process(requester{s, module}, filteredEvents[module]) 246 } 247 if !s.targetChanged() { 248 break 249 } 250 } 251 } 252 253 // Trigger starts a new processing round. If fired during processing, it ensures 254 // another full round of processing all modules. 255 func (s *Scheduler) Trigger() { 256 select { 257 case s.triggerCh <- struct{}{}: 258 default: 259 } 260 } 261 262 // addEvent adds an event to be processed in the next round. Note that it can be 263 // called regardless of the state of the lock mutex, making it safe for use in 264 // the server event callback. 265 func (s *Scheduler) addEvent(event Event) { 266 s.eventLock.Lock() 267 s.events = append(s.events, event) 268 s.eventLock.Unlock() 269 s.Trigger() 270 } 271 272 // filterEvent sorts each Event either as a request event or a server event, 273 // depending on its type. Request events are also sorted in a map based on the 274 // module that originally initiated the request. It also ensures that no events 275 // related to a server are returned before EvRegistered or after EvUnregistered. 276 // In case of an EvUnregistered server event it also closes all pending requests 277 // to the given server by adding a failed request event (EvFail), ensuring that 278 // all requests get finalized and thereby allowing the module logic to be safe 279 // and simple. 280 func (s *Scheduler) filterEvents() map[Module][]Event { 281 s.eventLock.Lock() 282 events := s.events 283 s.events = nil 284 s.eventLock.Unlock() 285 286 s.requesterLock.Lock() 287 defer s.requesterLock.Unlock() 288 289 filteredEvents := make(map[Module][]Event) 290 for _, event := range events { 291 server := event.Server.(server) 292 if _, ok := s.servers[server]; !ok && event.Type != EvRegistered { 293 continue // before EvRegister or after EvUnregister, discard 294 } 295 296 if event.IsRequestEvent() { 297 sid, _, _ := event.RequestInfo() 298 pending, ok := s.pending[sid] 299 if !ok { 300 continue // request already closed, ignore further events 301 } 302 if event.Type == EvResponse || event.Type == EvFail { 303 delete(s.pending, sid) // final event, close pending request 304 } 305 filteredEvents[pending.module] = append(filteredEvents[pending.module], event) 306 } else { 307 switch event.Type { 308 case EvRegistered: 309 s.servers[server] = struct{}{} 310 s.serverOrder = append(s.serverOrder, nil) 311 copy(s.serverOrder[1:], s.serverOrder[:len(s.serverOrder)-1]) 312 s.serverOrder[0] = server 313 case EvUnregistered: 314 s.closePending(event.Server, filteredEvents) 315 delete(s.servers, server) 316 for i, srv := range s.serverOrder { 317 if srv == server { 318 copy(s.serverOrder[i:len(s.serverOrder)-1], s.serverOrder[i+1:]) 319 s.serverOrder = s.serverOrder[:len(s.serverOrder)-1] 320 break 321 } 322 } 323 } 324 for _, module := range s.modules { 325 filteredEvents[module] = append(filteredEvents[module], event) 326 } 327 } 328 } 329 return filteredEvents 330 } 331 332 // closePending closes all pending requests to the given server and adds an EvFail 333 // event to properly finalize them 334 func (s *Scheduler) closePending(server Server, filteredEvents map[Module][]Event) { 335 for sid, pending := range s.pending { 336 if sid.Server == server { 337 filteredEvents[pending.module] = append(filteredEvents[pending.module], Event{ 338 Type: EvFail, 339 Server: server, 340 Data: RequestResponse{ 341 ID: sid.ID, 342 Request: pending.request, 343 }, 344 }) 345 delete(s.pending, sid) 346 } 347 } 348 } 349 350 // requester implements Requester. Note that while requester basically wraps 351 // Scheduler (with the added information of the currently processed Module), all 352 // functions are safe to call from Module.Process which is running while 353 // the Scheduler.lock mutex is held. 354 type requester struct { 355 *Scheduler 356 module Module 357 } 358 359 // CanSendTo returns the list of currently available servers. It also returns 360 // them in an order of least to most recently used, ensuring a round-robin usage 361 // of suitable servers if the module always chooses the first suitable one. 362 func (s requester) CanSendTo() []Server { 363 s.requesterLock.RLock() 364 defer s.requesterLock.RUnlock() 365 366 list := make([]Server, 0, len(s.serverOrder)) 367 for _, server := range s.serverOrder { 368 if server.canRequestNow() { 369 list = append(list, server) 370 } 371 } 372 return list 373 } 374 375 // Send sends a request and adds an entry to Scheduler.pending map, ensuring that 376 // related request events will be delivered to the sender Module. 377 func (s requester) Send(srv Server, req Request) ID { 378 s.requesterLock.Lock() 379 defer s.requesterLock.Unlock() 380 381 server := srv.(server) 382 id := server.sendRequest(req) 383 sid := ServerAndID{Server: srv, ID: id} 384 s.pending[sid] = pendingRequest{request: req, module: s.module} 385 for i, ss := range s.serverOrder { 386 if ss == server { 387 copy(s.serverOrder[i:len(s.serverOrder)-1], s.serverOrder[i+1:]) 388 s.serverOrder[len(s.serverOrder)-1] = server 389 return id 390 } 391 } 392 log.Error("Target server not found in ordered list of registered servers") 393 return id 394 } 395 396 // Fail should be called when a server delivers invalid or useless information. 397 // Calling Fail disables the given server for a period that is initially short 398 // but is exponentially growing if it happens frequently. This results in a 399 // somewhat fault tolerant operation that avoids hammering servers with requests 400 // that they cannot serve but still gives them a chance periodically. 401 func (s requester) Fail(srv Server, desc string) { 402 srv.(server).fail(desc) 403 }