github.com/aaa256/atlantis@v0.0.0-20210707112435-42ee889287a2/swarm/network/priorityqueue/priorityqueue.go (about) 1 // Copyright 2018 The go-athereum Authors 2 // This file is part of the go-athereum library. 3 // 4 // The go-athereum 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-athereum 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-athereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // package priority_queue implement a channel based priority queue 18 // over arbitrary types. It provides an 19 // an autopop loop applying a function to the items always respecting 20 // their priority. The structure is only quasi consistent ie., if a lower 21 // priority item is autopopped, it is guaranteed that there was a point 22 // when no higher priority item was present, ie. it is not guaranteed 23 // that there was any point where the lower priority item was present 24 // but the higher was not 25 26 package priorityqueue 27 28 import ( 29 "context" 30 "errors" 31 ) 32 33 var ( 34 errContention = errors.New("queue contention") 35 errBadPriority = errors.New("bad priority") 36 37 wakey = struct{}{} 38 ) 39 40 // PriorityQueue is the basic structure 41 type PriorityQueue struct { 42 queues []chan interface{} 43 wakeup chan struct{} 44 } 45 46 // New is the constructor for PriorityQueue 47 func New(n int, l int) *PriorityQueue { 48 var queues = make([]chan interface{}, n) 49 for i := range queues { 50 queues[i] = make(chan interface{}, l) 51 } 52 return &PriorityQueue{ 53 queues: queues, 54 wakeup: make(chan struct{}, 1), 55 } 56 } 57 58 // Run is a forever loop popping items from the queues 59 func (pq *PriorityQueue) Run(ctx context.Context, f func(interface{})) { 60 top := len(pq.queues) - 1 61 p := top 62 READ: 63 for { 64 q := pq.queues[p] 65 select { 66 case <-ctx.Done(): 67 return 68 case x := <-q: 69 f(x) 70 p = top 71 default: 72 if p > 0 { 73 p-- 74 continue READ 75 } 76 p = top 77 select { 78 case <-ctx.Done(): 79 return 80 case <-pq.wakeup: 81 } 82 } 83 } 84 } 85 86 // Push pushes an item to the appropriate queue specified in the priority argument 87 // if context is given it waits until either the item is pushed or the Context aborts 88 // otherwise returns errContention if the queue is full 89 func (pq *PriorityQueue) Push(ctx context.Context, x interface{}, p int) error { 90 if p < 0 || p >= len(pq.queues) { 91 return errBadPriority 92 } 93 if ctx == nil { 94 select { 95 case pq.queues[p] <- x: 96 default: 97 return errContention 98 } 99 } else { 100 select { 101 case pq.queues[p] <- x: 102 case <-ctx.Done(): 103 return ctx.Err() 104 } 105 } 106 select { 107 case pq.wakeup <- wakey: 108 default: 109 } 110 return nil 111 }