github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/swarm/network/priorityqueue/priorityqueue.go (about) 1 // Copyright 2018 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 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 "time" 32 33 "github.com/ethereum/go-ethereum/metrics" 34 ) 35 36 var ( 37 ErrContention = errors.New("contention") 38 39 errBadPriority = errors.New("bad priority") 40 41 wakey = struct{}{} 42 ) 43 44 // PriorityQueue is the basic structure 45 type PriorityQueue struct { 46 Queues []chan interface{} 47 wakeup chan struct{} 48 } 49 50 // New is the constructor for PriorityQueue 51 func New(n int, l int) *PriorityQueue { 52 var queues = make([]chan interface{}, n) 53 for i := range queues { 54 queues[i] = make(chan interface{}, l) 55 } 56 return &PriorityQueue{ 57 Queues: queues, 58 wakeup: make(chan struct{}, 1), 59 } 60 } 61 62 // Run is a forever loop popping items from the queues 63 func (pq *PriorityQueue) Run(ctx context.Context, f func(interface{})) { 64 top := len(pq.Queues) - 1 65 p := top 66 READ: 67 for { 68 q := pq.Queues[p] 69 select { 70 case <-ctx.Done(): 71 return 72 case x := <-q: 73 val := x.(struct { 74 v interface{} 75 t time.Time 76 }) 77 f(val.v) 78 metrics.GetOrRegisterResettingTimer("pq.run", nil).UpdateSince(val.t) 79 p = top 80 default: 81 if p > 0 { 82 p-- 83 continue READ 84 } 85 p = top 86 select { 87 case <-ctx.Done(): 88 return 89 case <-pq.wakeup: 90 } 91 } 92 } 93 } 94 95 // Push pushes an item to the appropriate queue specified in the priority argument 96 // if context is given it waits until either the item is pushed or the Context aborts 97 func (pq *PriorityQueue) Push(x interface{}, p int) error { 98 if p < 0 || p >= len(pq.Queues) { 99 return errBadPriority 100 } 101 val := struct { 102 v interface{} 103 t time.Time 104 }{ 105 x, 106 time.Now(), 107 } 108 select { 109 case pq.Queues[p] <- val: 110 default: 111 return ErrContention 112 } 113 select { 114 case pq.wakeup <- wakey: 115 default: 116 } 117 return nil 118 }