github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/les/flowcontrol/manager.go (about) 1 // Package flowcontrol implements a client side flow control mechanism 2 package flowcontrol 3 4 import ( 5 "sync" 6 "time" 7 8 "github.com/quickchainproject/quickchain/common/mclock" 9 ) 10 11 const rcConst = 1000000 12 13 type cmNode struct { 14 node *ClientNode 15 lastUpdate mclock.AbsTime 16 serving, recharging bool 17 rcWeight uint64 18 rcValue, rcDelta, startValue int64 19 finishRecharge mclock.AbsTime 20 } 21 22 func (node *cmNode) update(time mclock.AbsTime) { 23 dt := int64(time - node.lastUpdate) 24 node.rcValue += node.rcDelta * dt / rcConst 25 node.lastUpdate = time 26 if node.recharging && time >= node.finishRecharge { 27 node.recharging = false 28 node.rcDelta = 0 29 node.rcValue = 0 30 } 31 } 32 33 func (node *cmNode) set(serving bool, simReqCnt, sumWeight uint64) { 34 if node.serving && !serving { 35 node.recharging = true 36 sumWeight += node.rcWeight 37 } 38 node.serving = serving 39 if node.recharging && serving { 40 node.recharging = false 41 sumWeight -= node.rcWeight 42 } 43 44 node.rcDelta = 0 45 if serving { 46 node.rcDelta = int64(rcConst / simReqCnt) 47 } 48 if node.recharging { 49 node.rcDelta = -int64(node.node.cm.rcRecharge * node.rcWeight / sumWeight) 50 node.finishRecharge = node.lastUpdate + mclock.AbsTime(node.rcValue*rcConst/(-node.rcDelta)) 51 } 52 } 53 54 type ClientManager struct { 55 lock sync.Mutex 56 nodes map[*cmNode]struct{} 57 simReqCnt, sumWeight, rcSumValue uint64 58 maxSimReq, maxRcSum uint64 59 rcRecharge uint64 60 resumeQueue chan chan bool 61 time mclock.AbsTime 62 } 63 64 func NewClientManager(rcTarget, maxSimReq, maxRcSum uint64) *ClientManager { 65 cm := &ClientManager{ 66 nodes: make(map[*cmNode]struct{}), 67 resumeQueue: make(chan chan bool), 68 rcRecharge: rcConst * rcConst / (100*rcConst/rcTarget - rcConst), 69 maxSimReq: maxSimReq, 70 maxRcSum: maxRcSum, 71 } 72 go cm.queueProc() 73 return cm 74 } 75 76 func (self *ClientManager) Stop() { 77 self.lock.Lock() 78 defer self.lock.Unlock() 79 80 // signal any waiting accept routines to return false 81 self.nodes = make(map[*cmNode]struct{}) 82 close(self.resumeQueue) 83 } 84 85 func (self *ClientManager) addNode(cnode *ClientNode) *cmNode { 86 time := mclock.Now() 87 node := &cmNode{ 88 node: cnode, 89 lastUpdate: time, 90 finishRecharge: time, 91 rcWeight: 1, 92 } 93 self.lock.Lock() 94 defer self.lock.Unlock() 95 96 self.nodes[node] = struct{}{} 97 self.update(mclock.Now()) 98 return node 99 } 100 101 func (self *ClientManager) removeNode(node *cmNode) { 102 self.lock.Lock() 103 defer self.lock.Unlock() 104 105 time := mclock.Now() 106 self.stop(node, time) 107 delete(self.nodes, node) 108 self.update(time) 109 } 110 111 // recalc sumWeight 112 func (self *ClientManager) updateNodes(time mclock.AbsTime) (rce bool) { 113 var sumWeight, rcSum uint64 114 for node := range self.nodes { 115 rc := node.recharging 116 node.update(time) 117 if rc && !node.recharging { 118 rce = true 119 } 120 if node.recharging { 121 sumWeight += node.rcWeight 122 } 123 rcSum += uint64(node.rcValue) 124 } 125 self.sumWeight = sumWeight 126 self.rcSumValue = rcSum 127 return 128 } 129 130 func (self *ClientManager) update(time mclock.AbsTime) { 131 for { 132 firstTime := time 133 for node := range self.nodes { 134 if node.recharging && node.finishRecharge < firstTime { 135 firstTime = node.finishRecharge 136 } 137 } 138 if self.updateNodes(firstTime) { 139 for node := range self.nodes { 140 if node.recharging { 141 node.set(node.serving, self.simReqCnt, self.sumWeight) 142 } 143 } 144 } else { 145 self.time = time 146 return 147 } 148 } 149 } 150 151 func (self *ClientManager) canStartReq() bool { 152 return self.simReqCnt < self.maxSimReq && self.rcSumValue < self.maxRcSum 153 } 154 155 func (self *ClientManager) queueProc() { 156 for rc := range self.resumeQueue { 157 for { 158 time.Sleep(time.Millisecond * 10) 159 self.lock.Lock() 160 self.update(mclock.Now()) 161 cs := self.canStartReq() 162 self.lock.Unlock() 163 if cs { 164 break 165 } 166 } 167 close(rc) 168 } 169 } 170 171 func (self *ClientManager) accept(node *cmNode, time mclock.AbsTime) bool { 172 self.lock.Lock() 173 defer self.lock.Unlock() 174 175 self.update(time) 176 if !self.canStartReq() { 177 resume := make(chan bool) 178 self.lock.Unlock() 179 self.resumeQueue <- resume 180 <-resume 181 self.lock.Lock() 182 if _, ok := self.nodes[node]; !ok { 183 return false // reject if node has been removed or manager has been stopped 184 } 185 } 186 self.simReqCnt++ 187 node.set(true, self.simReqCnt, self.sumWeight) 188 node.startValue = node.rcValue 189 self.update(self.time) 190 return true 191 } 192 193 func (self *ClientManager) stop(node *cmNode, time mclock.AbsTime) { 194 if node.serving { 195 self.update(time) 196 self.simReqCnt-- 197 node.set(false, self.simReqCnt, self.sumWeight) 198 self.update(time) 199 } 200 } 201 202 func (self *ClientManager) processed(node *cmNode, time mclock.AbsTime) (rcValue, rcCost uint64) { 203 self.lock.Lock() 204 defer self.lock.Unlock() 205 206 self.stop(node, time) 207 return uint64(node.rcValue), uint64(node.rcValue - node.startValue) 208 }