Add regulator to GCS

Signed-off-by: Huu Nguyen <whoshuu@gmail.com>
This commit is contained in:
Tony Holdstock-Brown
2016-12-06 15:50:39 -08:00
committed by Ryan Abrams
parent b424c3d870
commit f9187b2572
4 changed files with 114 additions and 40 deletions

View File

@@ -2,7 +2,10 @@ package base
import (
"context"
"fmt"
"io"
"reflect"
"strconv"
"sync"
storagedriver "github.com/docker/distribution/registry/storage/driver"
@@ -15,6 +18,46 @@ type regulator struct {
available uint64
}
// GetLimitFromParameter takes an interface type as decoded from the YAML
// configuration and returns a uint64 representing the maximum number of
// concurrent calls given a minimum limit and default.
//
// If the parameter supplied is of an invalid type this returns an error.
func GetLimitFromParameter(param interface{}, min, def uint64) (uint64, error) {
limit := def
switch v := param.(type) {
case string:
var err error
if limit, err = strconv.ParseUint(v, 0, 64); err != nil {
return limit, fmt.Errorf("parameter must be an integer, '%v' invalid", param)
}
case uint64:
limit = v
case int, int32, int64:
val := reflect.ValueOf(v).Convert(reflect.TypeOf(param)).Int()
// if param is negative casting to uint64 will wrap around and
// give you the hugest thread limit ever. Let's be sensible, here
if val > 0 {
limit = uint64(val)
} else {
limit = min
}
case uint, uint32:
limit = reflect.ValueOf(v).Convert(reflect.TypeOf(param)).Uint()
case nil:
// use the default
default:
return 0, fmt.Errorf("invalid value '%#v'", param)
}
if limit < min {
return min, nil
}
return limit, nil
}
// NewRegulator wraps the given driver and is used to regulate concurrent calls
// to the given storage driver to a maximum of the given limit. This is useful
// for storage drivers that would otherwise create an unbounded number of OS

View File

@@ -1,6 +1,7 @@
package base
import (
"fmt"
"sync"
"testing"
"time"
@@ -65,3 +66,33 @@ func TestRegulatorEnterExit(t *testing.T) {
}
}
}
func TestGetLimitFromParameter(t *testing.T) {
tests := []struct {
Input interface{}
Expected uint64
Min uint64
Default uint64
Err error
}{
{"foo", 0, 5, 5, fmt.Errorf("parameter must be an integer, 'foo' invalid")},
{"50", 50, 5, 5, nil},
{"5", 25, 25, 50, nil}, // lower than Min returns Min
{nil, 50, 25, 50, nil}, // nil returns default
{812, 812, 25, 50, nil},
}
for _, item := range tests {
t.Run(fmt.Sprint(item.Input), func(t *testing.T) {
actual, err := GetLimitFromParameter(item.Input, item.Min, item.Default)
if err != nil && item.Err != nil && err.Error() != item.Err.Error() {
t.Fatalf("GetLimitFromParameter error, expected %#v got %#v", item.Err, err)
}
if actual != item.Expected {
t.Fatalf("GetLimitFromParameter result error, expected %d got %d", item.Expected, actual)
}
})
}
}