backoff: make DefaultBackoffConfig a concrete value

To enforce immutability of the `DefaultBackoffConfig`, we've made it a
concrete value. While fields can still be set directly on the value,
taking a copy will not incidentally pull a reference to the variable.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day
2016-04-18 11:33:39 -07:00
parent 9ff38e9093
commit 8ef1dcabab
4 changed files with 16 additions and 13 deletions

View File

@ -8,7 +8,7 @@ import (
// DefaultBackoffConfig uses values specified for backoff in // DefaultBackoffConfig uses values specified for backoff in
// https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md. // https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md.
var ( var (
DefaultBackoffConfig = &BackoffConfig{ DefaultBackoffConfig = BackoffConfig{
MaxDelay: 120 * time.Second, MaxDelay: 120 * time.Second,
baseDelay: 1.0 * time.Second, baseDelay: 1.0 * time.Second,
factor: 1.6, factor: 1.6,
@ -33,7 +33,10 @@ type BackoffConfig struct {
// MaxDelay is the upper bound of backoff delay. // MaxDelay is the upper bound of backoff delay.
MaxDelay time.Duration MaxDelay time.Duration
// TODO(stevvooe): The following fields are not exported, as allowing changes // TODO(stevvooe): The following fields are not exported, as allowing
// changes would violate the current GRPC specification for backoff. If
// GRPC decides to allow more interesting backoff strategies, these fields
// may be opened up in the future.
// baseDelay is the amount of time to wait before retrying after the first // baseDelay is the amount of time to wait before retrying after the first
// failure. // failure.
@ -48,14 +51,14 @@ type BackoffConfig struct {
func (bc *BackoffConfig) setDefaults() { func (bc *BackoffConfig) setDefaults() {
md := bc.MaxDelay md := bc.MaxDelay
*bc = *DefaultBackoffConfig *bc = DefaultBackoffConfig
if md > 0 { if md > 0 {
bc.MaxDelay = md bc.MaxDelay = md
} }
} }
func (bc *BackoffConfig) backoff(retries int) (t time.Duration) { func (bc BackoffConfig) backoff(retries int) (t time.Duration) {
if retries == 0 { if retries == 0 {
return bc.baseDelay return bc.baseDelay
} }

View File

@ -5,7 +5,7 @@ import "testing"
func TestBackoffConfigDefaults(t *testing.T) { func TestBackoffConfigDefaults(t *testing.T) {
b := BackoffConfig{} b := BackoffConfig{}
b.setDefaults() b.setDefaults()
if b != *DefaultBackoffConfig { if b != DefaultBackoffConfig {
t.Fatalf("expected BackoffConfig to pickup default parameters: %v != %v", b, *DefaultBackoffConfig) t.Fatalf("expected BackoffConfig to pickup default parameters: %v != %v", b, DefaultBackoffConfig)
} }
} }

View File

@ -118,7 +118,7 @@ func WithPicker(p Picker) DialOption {
// WithBackoffMaxDelay configures the dialer to use the provided maximum delay // WithBackoffMaxDelay configures the dialer to use the provided maximum delay
// when backing off after failed connection attempts. // when backing off after failed connection attempts.
func WithBackoffMaxDelay(md time.Duration) DialOption { func WithBackoffMaxDelay(md time.Duration) DialOption {
return WithBackoffConfig(&BackoffConfig{MaxDelay: md}) return WithBackoffConfig(BackoffConfig{MaxDelay: md})
} }
// WithBackoffConfig configures the dialer to use the provided backoff // WithBackoffConfig configures the dialer to use the provided backoff
@ -126,7 +126,7 @@ func WithBackoffMaxDelay(md time.Duration) DialOption {
// //
// Use WithBackoffMaxDelay until more parameters on BackoffConfig are opened up // Use WithBackoffMaxDelay until more parameters on BackoffConfig are opened up
// for use. // for use.
func WithBackoffConfig(b *BackoffConfig) DialOption { func WithBackoffConfig(b BackoffConfig) DialOption {
// Set defaults to ensure that provided BackoffConfig is valid and // Set defaults to ensure that provided BackoffConfig is valid and
// unexported fields get default values. // unexported fields get default values.
b.setDefaults() b.setDefaults()

View File

@ -82,14 +82,14 @@ func TestCredentialsMisuse(t *testing.T) {
} }
func TestWithBackoffConfigDefault(t *testing.T) { func TestWithBackoffConfigDefault(t *testing.T) {
testBackoffConfigSet(t, DefaultBackoffConfig) testBackoffConfigSet(t, &DefaultBackoffConfig)
} }
func TestWithBackoffConfig(t *testing.T) { func TestWithBackoffConfig(t *testing.T) {
b := BackoffConfig{MaxDelay: DefaultBackoffConfig.MaxDelay / 2} b := BackoffConfig{MaxDelay: DefaultBackoffConfig.MaxDelay / 2}
expected := b expected := b
expected.setDefaults() // defaults should be set expected.setDefaults() // defaults should be set
testBackoffConfigSet(t, &expected, WithBackoffConfig(&b)) testBackoffConfigSet(t, &expected, WithBackoffConfig(b))
} }
func TestWithBackoffMaxDelay(t *testing.T) { func TestWithBackoffMaxDelay(t *testing.T) {
@ -110,12 +110,12 @@ func testBackoffConfigSet(t *testing.T, expected *BackoffConfig, opts ...DialOpt
t.Fatalf("backoff config not set") t.Fatalf("backoff config not set")
} }
actual, ok := conn.dopts.bs.(*BackoffConfig) actual, ok := conn.dopts.bs.(BackoffConfig)
if !ok { if !ok {
t.Fatalf("unexpected type of backoff config: %v", conn.dopts.bs) t.Fatalf("unexpected type of backoff config: %#v", conn.dopts.bs)
} }
if *actual != *expected { if actual != *expected {
t.Fatalf("unexpected backoff config on connection: %v, want %v", actual, expected) t.Fatalf("unexpected backoff config on connection: %v, want %v", actual, expected)
} }
} }