33c448f147
This commit refactors base.regulator into the 2.4 interfaces and adds a filesystem configuration option `maxthreads` to configure the regulator. By default `maxthreads` is set to 100. This means the FS driver is limited to 100 concurrent blocking file operations. Any subsequent operations will block in Go until previous filesystem operations complete. This ensures that the registry can never open thousands of simultaneous threads from os filesystem operations. Note that `maxthreads` can never be less than 25. Add test case covering parsable string maxthreads Signed-off-by: Tony Holdstock-Brown <tony@docker.com>
113 lines
2.5 KiB
Go
113 lines
2.5 KiB
Go
package filesystem
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"os"
|
|
"reflect"
|
|
"testing"
|
|
|
|
storagedriver "github.com/docker/distribution/registry/storage/driver"
|
|
"github.com/docker/distribution/registry/storage/driver/testsuites"
|
|
. "gopkg.in/check.v1"
|
|
)
|
|
|
|
// Hook up gocheck into the "go test" runner.
|
|
func Test(t *testing.T) { TestingT(t) }
|
|
|
|
func init() {
|
|
root, err := ioutil.TempDir("", "driver-")
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer os.Remove(root)
|
|
|
|
driver, err := FromParameters(map[string]interface{}{
|
|
"rootdirectory": root,
|
|
})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
testsuites.RegisterSuite(func() (storagedriver.StorageDriver, error) {
|
|
return driver, nil
|
|
}, testsuites.NeverSkip)
|
|
}
|
|
|
|
func TestFromParametersImpl(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
params map[string]interface{} // techincally the yaml can contain anything
|
|
expected DriverParameters
|
|
pass bool
|
|
}{
|
|
// check we use default threads and root dirs
|
|
{
|
|
params: map[string]interface{}{},
|
|
expected: DriverParameters{
|
|
RootDirectory: defaultRootDirectory,
|
|
MaxThreads: defaultMaxThreads,
|
|
},
|
|
pass: true,
|
|
},
|
|
// Testing initiation with a string maxThreads which can't be parsed
|
|
{
|
|
params: map[string]interface{}{
|
|
"maxthreads": "fail",
|
|
},
|
|
expected: DriverParameters{},
|
|
pass: false,
|
|
},
|
|
{
|
|
params: map[string]interface{}{
|
|
"maxthreads": "100",
|
|
},
|
|
expected: DriverParameters{
|
|
RootDirectory: defaultRootDirectory,
|
|
MaxThreads: uint64(100),
|
|
},
|
|
pass: true,
|
|
},
|
|
{
|
|
params: map[string]interface{}{
|
|
"maxthreads": 100,
|
|
},
|
|
expected: DriverParameters{
|
|
RootDirectory: defaultRootDirectory,
|
|
MaxThreads: uint64(100),
|
|
},
|
|
pass: true,
|
|
},
|
|
// check that we use minimum thread counts
|
|
{
|
|
params: map[string]interface{}{
|
|
"maxthreads": 1,
|
|
},
|
|
expected: DriverParameters{
|
|
RootDirectory: defaultRootDirectory,
|
|
MaxThreads: minThreads,
|
|
},
|
|
pass: true,
|
|
},
|
|
}
|
|
|
|
for _, item := range tests {
|
|
params, err := fromParametersImpl(item.params)
|
|
|
|
if !item.pass {
|
|
// We only need to assert that expected failures have an error
|
|
if err == nil {
|
|
t.Fatalf("expected error configuring filesystem driver with invalid param: %+v", item.params)
|
|
}
|
|
continue
|
|
}
|
|
|
|
if err != nil {
|
|
t.Fatalf("unexpected error creating filesystem driver: %s", err)
|
|
}
|
|
// Note that we get a pointer to params back
|
|
if !reflect.DeepEqual(*params, item.expected) {
|
|
t.Fatalf("unexpected params from filesystem driver. expected %+v, got %+v", item.expected, params)
|
|
}
|
|
}
|
|
|
|
}
|