hpcloud / tail

Go package for reading from continously updated files (tail -f)
MIT License
2.71k stars 503 forks source link

tailFile: leakybucket algo err #95

Open RuiHan2023 opened 8 years ago

RuiHan2023 commented 8 years ago

https://github.com/hpcloud/tail/blob/master/ratelimiter/leakybucket.go

newfill float64 = b.Fill + float64(amount) b.Fill -= float64(elapsed) / float64(b.LeakInterval) It is strange: add amount, dec time ?!

should be:


--- a/src/github.com/hpcloud/tail/ratelimiter/leakybucket.go
+++ b/src/github.com/hpcloud/tail/ratelimiter/leakybucket.go
@@ -30,7 +30,8 @@ func (b *LeakyBucket) updateFill() {
        if b.Fill > 0 {
                elapsed := now.Sub(b.Lastupdate)

-               b.Fill -= float64(elapsed) / float64(b.LeakInterval)
+               // fix bug: bucket algo err
+               b.Fill -= float64(b.Size) * float64(elapsed) / float64(b.LeakInterval)
                if b.Fill < 0 {
                        b.Fill = 0
                }
@@ -40,7 +41,6 @@ func (b *LeakyBucket) updateFill() {

 func (b *LeakyBucket) Pour(amount uint16) bool {
        b.updateFill()
-
        var newfill float64 = b.Fill + float64(amount)

        if newfill > float64(b.Size) {
@@ -54,7 +54,7 @@ func (b *LeakyBucket) Pour(amount uint16) bool {

 // The time at which this bucket will be completely drained
 func (b *LeakyBucket) DrainedAt() time.Time {
-       return b.Lastupdate.Add(time.Duration(b.Fill * float64(b.LeakInterval)))
+       return b.Lastupdate.Add(time.Duration(b.Fill / float64(b.Size) * float64(b.LeakInterval)))
 }

this leakybucket's rate: size/interval burst: size

please see: https://en.wikipedia.org/wiki/Leaky_bucket#Parameters

RuiHan2023 commented 8 years ago

Or, you can add a burst para, like this:

--- a/src/github.com/hpcloud/tail/ratelimiter/leakybucket.go
+++ b/src/github.com/hpcloud/tail/ratelimiter/leakybucket.go
@@ -7,6 +7,7 @@ import (

 type LeakyBucket struct {
        Size         uint16
+       Burst        uint16
        Fill         float64
        LeakInterval time.Duration // time.Duration for 1 unit of size to leak
        Lastupdate   time.Time
@@ -30,7 +31,8 @@ func (b *LeakyBucket) updateFill() {
        if b.Fill > 0 {
                elapsed := now.Sub(b.Lastupdate)

-               b.Fill -= float64(elapsed) / float64(b.LeakInterval)
+               // fix bug: bucket algo err
+               b.Fill -= float64(b.Size) * float64(elapsed) / float64(b.LeakInterval)
                if b.Fill < 0 {
                        b.Fill = 0
                }
@@ -40,10 +42,9 @@ func (b *LeakyBucket) updateFill() {

 func (b *LeakyBucket) Pour(amount uint16) bool {
        b.updateFill()
-
        var newfill float64 = b.Fill + float64(amount)

-       if newfill > float64(b.Size) {
+       if newfill > float64(b.Burst) {
                return false
        }

@@ -54,7 +55,7 @@ func (b *LeakyBucket) Pour(amount uint16) bool {

 // The time at which this bucket will be completely drained
 func (b *LeakyBucket) DrainedAt() time.Time {
-       return b.Lastupdate.Add(time.Duration(b.Fill * float64(b.LeakInterval)))
+       return b.Lastupdate.Add(time.Duration(b.Fill / float64(b.Size) * float64(b.LeakInterval)))
 }

When using leakybucket, you shoud config the "burst" para.

RuiHan2023 commented 8 years ago

I will commit to fix this.

kevinburke1 commented 5 years ago

Hi, any update here?

xgdgsc commented 4 years ago

How to use ratelimiter?