github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/ratelimiter/rwbucket.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package ratelimiter 7 8 import ( 9 "github.com/insolar/vanilla/atomickit" 10 ) 11 12 type RWRateQuota interface { 13 RateQuota 14 TakeWriteQuota(max int64) int64 15 TakeWriteQuotaNoWait(max int64) int64 16 WriteBucket() RateQuota 17 } 18 19 func NewRWBucket(bm *PeriodManager, read, write BucketConfig) *RWBucket { 20 read.Check() 21 write.Check() 22 23 return &RWBucket{RWSubBucket{ 24 stateR: BucketState{ 25 filledAmount: atomickit.NewUint32(read.RefillAmount), 26 bucketConfig: read, 27 }, 28 stateW: BucketState{ 29 filledAmount: atomickit.NewUint32(write.RefillAmount), 30 bucketConfig: write, 31 }, 32 refiller: PeriodRefiller{ 33 manager: bm, 34 periodCount: atomickit.NewUint64(bm.currentPeriod.Load()), 35 }}} 36 } 37 38 func NewRWChildBucket(parent ParentRWBucket, read, write BucketConfig) *RWChildBucket { 39 read.Check() 40 write.Check() 41 42 bm := parent.(periodBucket).GetManager() 43 return &RWChildBucket{RWChildSubBucket{ 44 stateR: BucketState{ 45 bucketConfig: read, 46 }, stateW: BucketState{ 47 bucketConfig: write, 48 }, refiller: PeriodRefiller{ 49 manager: bm, 50 periodCount: atomickit.NewUint64(bm.currentPeriod.Load()), 51 }, parent: parent}} 52 } 53 54 func NewRWChildBucketRatio(parent ParentRWBucket, refillRatio, maxRatio float32) *RWChildBucket { 55 cfgR, cfgW := parent.CopyRWConfig() 56 return NewRWChildBucket(parent, cfgR.Scale(refillRatio, maxRatio), cfgW.Scale(refillRatio, maxRatio)) 57 } 58 59 var _ ParentRWBucket = &RWBucket{} 60 var _ RWRateQuota = &RWBucket{} 61 var _ periodBucket = &RWBucket{} 62 63 type RWBucket struct { 64 s RWSubBucket 65 } 66 67 func (p *RWBucket) GetManager() *PeriodManager { 68 return p.s.refiller.manager 69 } 70 71 func (p *RWBucket) CopyRWConfig() (read, write BucketConfig) { 72 return p.s.stateR.config(), p.s.stateW.config() 73 } 74 75 func (p *RWBucket) TakeQuota(max int64) int64 { 76 return p.s.refiller.TakeQuota(max, &p.s.stateR, p.s.refillR) 77 } 78 79 func (p *RWBucket) TakeQuotaNoWait(max int64) int64 { 80 return p.s.refiller.TakeQuotaNoWait(max, &p.s.stateR, p.s.refillR) 81 } 82 83 func (p *RWBucket) TakeWriteQuota(max int64) int64 { 84 return p.s.refiller.TakeQuota(max, &p.s.stateW, p.s.refillW) 85 } 86 87 func (p *RWBucket) TakeWriteQuotaNoWait(max int64) int64 { 88 return p.s.refiller.TakeQuotaNoWait(max, &p.s.stateW, p.s.refillW) 89 } 90 91 func (p *RWBucket) TakeReadQuotaNoScale(max uint32) uint32 { 92 return p.s.stateR.TakeQuotaNoScale(max, p.s.refillR) 93 } 94 95 func (p *RWBucket) TakeWriteQuotaNoScale(max uint32) uint32 { 96 return p.s.stateW.TakeQuotaNoScale(max, p.s.refillW) 97 } 98 99 func (p *RWBucket) WriteBucket() RateQuota { 100 return &p.s 101 } 102 103 type RWSubBucket struct { 104 stateR BucketState 105 stateW BucketState 106 refiller PeriodRefiller 107 } 108 109 func (p *RWSubBucket) TakeQuota(max int64) int64 { 110 return p.refiller.TakeQuota(max, &p.stateW, p.refillW) 111 } 112 113 func (p *RWSubBucket) TakeQuotaNoWait(max int64) int64 { 114 return p.refiller.TakeQuotaNoWait(max, &p.stateW, p.refillW) 115 } 116 117 func (p *RWSubBucket) refillR(uint32) uint32 { 118 x := p.refiller.GetRefillCount() 119 p.stateW.ForceRefill(p.stateW.PeriodsToRefill(x)) 120 return p.stateR.PeriodsToRefill(x) 121 } 122 123 func (p *RWSubBucket) refillW(uint32) uint32 { 124 x := p.refiller.GetRefillCount() 125 p.stateR.ForceRefill(p.stateR.PeriodsToRefill(x)) 126 return p.stateW.PeriodsToRefill(x) 127 } 128 129 /**********************************************************/ 130 131 var _ ParentRWBucket = &RWChildBucket{} 132 var _ RWRateQuota = &RWChildBucket{} 133 var _ periodBucket = &RWChildBucket{} 134 135 type RWChildBucket struct { 136 s RWChildSubBucket 137 } 138 139 func (p *RWChildBucket) GetManager() *PeriodManager { 140 return p.s.refiller.manager 141 } 142 143 func (p *RWChildBucket) CopyRWConfig() (read, write BucketConfig) { 144 return p.s.stateR.config(), p.s.stateW.config() 145 } 146 147 func (p *RWChildBucket) TakeQuota(max int64) int64 { 148 return p.s.refiller.TakeQuota(max, &p.s.stateR, p.s.refillR) 149 } 150 151 func (p *RWChildBucket) TakeQuotaNoWait(max int64) int64 { 152 return p.s.refiller.TakeQuotaNoWait(max, &p.s.stateR, p.s.refillR) 153 } 154 155 func (p *RWChildBucket) TakeWriteQuota(max int64) int64 { 156 return p.s.refiller.TakeQuota(max, &p.s.stateW, p.s.refillW) 157 } 158 159 func (p *RWChildBucket) TakeWriteQuotaNoWait(max int64) int64 { 160 return p.s.refiller.TakeQuotaNoWait(max, &p.s.stateW, p.s.refillW) 161 } 162 163 func (p *RWChildBucket) TakeReadQuotaNoScale(max uint32) uint32 { 164 return p.s.stateR.TakeQuotaNoScale(max, p.s.refillR) 165 } 166 167 func (p *RWChildBucket) TakeWriteQuotaNoScale(max uint32) uint32 { 168 return p.s.stateW.TakeQuotaNoScale(max, p.s.refillW) 169 } 170 171 func (p *RWChildBucket) WriteBucket() RateQuota { 172 return &p.s 173 } 174 175 type ParentRWBucket interface { 176 TakeReadQuotaNoScale(max uint32) uint32 177 TakeWriteQuotaNoScale(max uint32) uint32 178 CopyRWConfig() (read, write BucketConfig) 179 } 180 181 type RWChildSubBucket struct { 182 stateR BucketState 183 stateW BucketState 184 refiller PeriodRefiller 185 186 quotaR RefillQuota 187 quotaW RefillQuota 188 parent ParentRWBucket 189 } 190 191 func (p *RWChildSubBucket) TakeQuota(max int64) int64 { 192 return p.refiller.TakeQuota(max, &p.stateW, p.refillW) 193 } 194 195 func (p *RWChildSubBucket) TakeQuotaNoWait(max int64) int64 { 196 return p.refiller.TakeQuotaNoWait(max, &p.stateW, p.refillW) 197 } 198 199 func (p *RWChildSubBucket) refillR(needed uint32) uint32 { 200 x := p.refiller.GetRefillCount() 201 p.stateW.ForceRefill(p.quotaW.Refill(needed, x, &p.stateW, p.parent.TakeWriteQuotaNoScale)) 202 return p.quotaR.Refill(needed, x, &p.stateR, p.parent.TakeReadQuotaNoScale) 203 } 204 205 func (p *RWChildSubBucket) refillW(needed uint32) uint32 { 206 x := p.refiller.GetRefillCount() 207 p.stateR.ForceRefill(p.quotaR.Refill(needed, x, &p.stateR, p.parent.TakeReadQuotaNoScale)) 208 return p.quotaW.Refill(needed, x, &p.stateW, p.parent.TakeWriteQuotaNoScale) 209 }