accounting: make --bwlimit set with the rc options/set take effect
Setting the bandwidth limit with options/set changed the option but never reached the token bucket, so it had no effect, whereas core/bwlimit worked. Apply the limit when the config is reloaded. Note that a bandwidth timetable set this way isn't scheduled - the limit for the current time is applied.
This commit is contained in:
1 parent
3cd41095b4
commit
48da73ad5a
3 files changed
+70
No files matched your search
@@ -35,9 +35,30 @@ type tokenBucket struct {
|
||||
curr buckets
|
||||
prev buckets
|
||||
toggledOff bool
|
||||
started bool
|
||||
currLimit fs.BwTimeSlot
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Apply --bwlimit when the config is reloaded, e.g. by the rc
|
||||
fs.BwLimitReload = TokenBucket.reload
|
||||
}
|
||||
|
||||
// reload applies a changed --bwlimit to the token bucket.
|
||||
//
|
||||
// This does nothing before the token bucket is started as
|
||||
// StartTokenBucket reads the limit itself.
|
||||
func (tb *tokenBucket) reload(ci *fs.ConfigInfo) error {
|
||||
limitNow := ci.BwLimit.LimitAt(time.Now())
|
||||
tb.mu.Lock()
|
||||
defer tb.mu.Unlock()
|
||||
if !tb.started || tb.currLimit.Bandwidth == limitNow.Bandwidth {
|
||||
return nil
|
||||
}
|
||||
tb._setBwLimit(limitNow.Bandwidth)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return true if limit is disabled
|
||||
//
|
||||
// Call with lock held
|
||||
@@ -111,6 +132,7 @@ func (tb *tokenBucket) StartTokenBucket(ctx context.Context) {
|
||||
tb.mu.Lock()
|
||||
defer tb.mu.Unlock()
|
||||
ci := fs.GetConfig(ctx)
|
||||
tb.started = true
|
||||
tb.currLimit = ci.BwLimit.LimitAt(time.Now())
|
||||
if tb.currLimit.Bandwidth.IsSet() {
|
||||
tb.curr = newTokenBucket(tb.currLimit.Bandwidth)
|
||||
|
||||
@@ -115,6 +115,46 @@ func TestRcBwLimit(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
// Check options/set applies a changed --bwlimit to the token bucket
|
||||
func TestBwLimitOptionsSet(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
ci := fs.GetConfig(ctx)
|
||||
oldBwLimit, oldStarted, oldCurr, oldCurrLimit := ci.BwLimit, TokenBucket.started, TokenBucket.curr, TokenBucket.currLimit
|
||||
defer func() {
|
||||
ci.BwLimit = oldBwLimit
|
||||
TokenBucket.started, TokenBucket.curr, TokenBucket.currLimit = oldStarted, oldCurr, oldCurrLimit
|
||||
}()
|
||||
|
||||
setBwLimit := func(rate string) {
|
||||
t.Helper()
|
||||
call := rc.Calls.Get("options/set")
|
||||
require.NotNil(t, call)
|
||||
_, err := call.Fn(ctx, rc.Params{"main": rc.Params{"BwLimit": rate}})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Nothing happens before the token bucket is started
|
||||
TokenBucket.started = false
|
||||
TokenBucket.curr = buckets{}
|
||||
setBwLimit("100k")
|
||||
assert.Nil(t, TokenBucket.curr[TokenBucketSlotAccounting])
|
||||
|
||||
// Once started the limit is applied
|
||||
TokenBucket.started = true
|
||||
TokenBucket.currLimit = fs.BwTimeSlot{}
|
||||
setBwLimit("200k")
|
||||
require.NotNil(t, TokenBucket.curr[TokenBucketSlotTransportTx])
|
||||
assert.Equal(t, rate.Limit(200*1024), TokenBucket.curr[TokenBucketSlotTransportTx].Limit())
|
||||
|
||||
// and changed again
|
||||
setBwLimit("300k")
|
||||
assert.Equal(t, rate.Limit(300*1024), TokenBucket.curr[TokenBucketSlotTransportTx].Limit())
|
||||
|
||||
// and turned off
|
||||
setBwLimit("off")
|
||||
assert.Nil(t, TokenBucket.curr[TokenBucketSlotTransportTx])
|
||||
}
|
||||
|
||||
// Check setting the limit records it and respects the SIGUSR2 toggle
|
||||
func TestSetBwLimitToggledOff(t *testing.T) {
|
||||
oldCurr, oldPrev, oldToggledOff, oldCurrLimit := TokenBucket.curr, TokenBucket.prev, TokenBucket.toggledOff, TokenBucket.currLimit
|
||||
|
||||
@@ -713,6 +713,10 @@ func init() {
|
||||
// be there but we can't move due to them being visible here in the rc.
|
||||
var LogReload = func(*ConfigInfo) error { return nil }
|
||||
|
||||
// BwLimitReload is written by fs/accounting to apply --bwlimit when
|
||||
// the config is reloaded, e.g. by the rc options/set.
|
||||
var BwLimitReload = func(*ConfigInfo) error { return nil }
|
||||
|
||||
// Reload assumes the config has been edited and does what is necessary to make it live
|
||||
func (ci *ConfigInfo) Reload(ctx context.Context) error {
|
||||
// Set -vv if --dump is in use
|
||||
@@ -765,6 +769,10 @@ func (ci *ConfigInfo) Reload(ctx context.Context) error {
|
||||
nonZero(&ci.Transfers)
|
||||
nonZero(&ci.Checkers)
|
||||
|
||||
if err := BwLimitReload(ci); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return LogReload(ci)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user