Commit ea8b0acd authored by Damien Neil's avatar Damien Neil

all: remove os.ErrTemporary

As discussed in
https://github.com/golang/go/issues/32463#issuecomment-506833421
the classification of deadline-based timeouts as "temporary" errors is a
historical accident. I/O timeouts used to be duration-based, so they
really were temporary--retrying a timed-out operation could succeed. Now
that they're deadline-based, timeouts aren't temporary unless you reset
the deadline.

Drop ErrTemporary from Go 1.13, since its definition is wrong. We'll
consider putting it back in Go 1.14 with a clear definition and
deprecate net.OpError.Temporary.

Fixes #32463

Change-Id: I70cda664590d8872541e17409a5780da76920891
Reviewed-on: https://go-review.googlesource.com/c/go/+/188398Reviewed-by: default avatarJonathan Amsterdam <jba@google.com>
parent 8a317ebc
...@@ -237,7 +237,6 @@ pkg os (netbsd-arm64), const O_SYNC = 128 ...@@ -237,7 +237,6 @@ pkg os (netbsd-arm64), const O_SYNC = 128
pkg os (netbsd-arm64), const O_TRUNC = 1024 pkg os (netbsd-arm64), const O_TRUNC = 1024
pkg os (netbsd-arm64), const PathListSeparator = 58 pkg os (netbsd-arm64), const PathListSeparator = 58
pkg os (netbsd-arm64), const PathSeparator = 47 pkg os (netbsd-arm64), const PathSeparator = 47
pkg os, var ErrTemporary error
pkg os, var ErrTimeout error pkg os, var ErrTimeout error
pkg path/filepath (netbsd-arm64-cgo), const ListSeparator = 58 pkg path/filepath (netbsd-arm64-cgo), const ListSeparator = 58
pkg path/filepath (netbsd-arm64-cgo), const Separator = 47 pkg path/filepath (netbsd-arm64-cgo), const Separator = 47
......
...@@ -164,7 +164,7 @@ func (deadlineExceededError) Error() string { return "context deadline exceede ...@@ -164,7 +164,7 @@ func (deadlineExceededError) Error() string { return "context deadline exceede
func (deadlineExceededError) Timeout() bool { return true } func (deadlineExceededError) Timeout() bool { return true }
func (deadlineExceededError) Temporary() bool { return true } func (deadlineExceededError) Temporary() bool { return true }
func (deadlineExceededError) Is(target error) bool { func (deadlineExceededError) Is(target error) bool {
return target == oserror.ErrTimeout || target == oserror.ErrTemporary return target == oserror.ErrTimeout
} }
// An emptyCtx is never canceled, has no values, and has no deadline. It is not // An emptyCtx is never canceled, has no values, and has no deadline. It is not
......
...@@ -15,7 +15,6 @@ var ( ...@@ -15,7 +15,6 @@ var (
ErrExist = errors.New("file already exists") ErrExist = errors.New("file already exists")
ErrNotExist = errors.New("file does not exist") ErrNotExist = errors.New("file does not exist")
ErrClosed = errors.New("file already closed") ErrClosed = errors.New("file already closed")
ErrTemporary = temporaryError{}
ErrTimeout = timeoutError{} ErrTimeout = timeoutError{}
) )
...@@ -45,20 +44,3 @@ func IsTimeout(err error) bool { ...@@ -45,20 +44,3 @@ func IsTimeout(err error) bool {
} }
return false return false
} }
// IsTemporary reports whether err indicates a temporary condition.
func IsTemporary(err error) bool {
for err != nil {
if err == ErrTemporary {
return true
}
if x, ok := err.(interface{ Temporary() bool }); ok {
return x.Temporary()
}
if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(ErrTemporary) {
return true
}
err = errors.Unwrap(err)
}
return false
}
...@@ -10,14 +10,12 @@ import ( ...@@ -10,14 +10,12 @@ import (
type ttError struct { type ttError struct {
timeout bool timeout bool
temporary bool
} }
func (e ttError) Error() string { func (e ttError) Error() string {
return fmt.Sprintf("ttError{timeout:%v temporary:%v}", e.timeout, e.temporary) return fmt.Sprintf("ttError{timeout:%v}", e.timeout)
} }
func (e ttError) Timeout() bool { return e.timeout } func (e ttError) Timeout() bool { return e.timeout }
func (e ttError) Temporary() bool { return e.temporary }
type isError struct { type isError struct {
err error err error
...@@ -43,21 +41,3 @@ func TestIsTimeout(t *testing.T) { ...@@ -43,21 +41,3 @@ func TestIsTimeout(t *testing.T) {
} }
} }
} }
func TestIsTemporary(t *testing.T) {
for _, test := range []struct {
want bool
err error
}{
{true, ttError{temporary: true}},
{true, isError{os.ErrTemporary}},
{true, os.ErrTemporary},
{true, fmt.Errorf("wrap: %w", os.ErrTemporary)},
{false, ttError{temporary: false}},
{false, errors.New("error")},
} {
if got, want := oserror.IsTemporary(test.err), test.want; got != want {
t.Errorf("IsTemporary(err) = %v, want %v\n%+v", got, want, test.err)
}
}
}
...@@ -48,7 +48,7 @@ func (e *TimeoutError) Timeout() bool { return true } ...@@ -48,7 +48,7 @@ func (e *TimeoutError) Timeout() bool { return true }
func (e *TimeoutError) Temporary() bool { return true } func (e *TimeoutError) Temporary() bool { return true }
func (e *TimeoutError) Is(target error) bool { func (e *TimeoutError) Is(target error) bool {
return target == oserror.ErrTimeout || target == oserror.ErrTemporary return target == oserror.ErrTimeout
} }
// ErrNotPollable is returned when the file or socket is not suitable // ErrNotPollable is returned when the file or socket is not suitable
......
...@@ -40,8 +40,6 @@ func (eai addrinfoErrno) Timeout() bool { return false } ...@@ -40,8 +40,6 @@ func (eai addrinfoErrno) Timeout() bool { return false }
func (eai addrinfoErrno) Is(target error) bool { func (eai addrinfoErrno) Is(target error) bool {
switch target { switch target {
case os.ErrTemporary:
return eai.Temporary()
case os.ErrTimeout: case os.ErrTimeout:
return eai.Timeout() return eai.Timeout()
} }
......
...@@ -2288,8 +2288,6 @@ func (e *httpError) Is(target error) bool { ...@@ -2288,8 +2288,6 @@ func (e *httpError) Is(target error) bool {
switch target { switch target {
case os.ErrTimeout: case os.ErrTimeout:
return e.timeout return e.timeout
case os.ErrTemporary:
return true
} }
return false return false
} }
...@@ -2629,7 +2627,7 @@ func (tlsHandshakeTimeoutError) Temporary() bool { return true } ...@@ -2629,7 +2627,7 @@ func (tlsHandshakeTimeoutError) Temporary() bool { return true }
func (tlsHandshakeTimeoutError) Error() string { return "net/http: TLS handshake timeout" } func (tlsHandshakeTimeoutError) Error() string { return "net/http: TLS handshake timeout" }
func (tlsHandshakeTimeoutError) Is(target error) bool { func (tlsHandshakeTimeoutError) Is(target error) bool {
return target == os.ErrTimeout || target == os.ErrTemporary return target == os.ErrTimeout
} }
// fakeLocker is a sync.Locker which does nothing. It's used to guard // fakeLocker is a sync.Locker which does nothing. It's used to guard
......
...@@ -518,8 +518,6 @@ func (e *OpError) Temporary() bool { ...@@ -518,8 +518,6 @@ func (e *OpError) Temporary() bool {
func (e *OpError) Is(target error) bool { func (e *OpError) Is(target error) bool {
switch target { switch target {
case os.ErrTemporary:
return e.Temporary()
case os.ErrTimeout: case os.ErrTimeout:
return e.Timeout() return e.Timeout()
} }
...@@ -619,8 +617,6 @@ func (e *DNSError) Temporary() bool { return e.IsTimeout || e.IsTemporary } ...@@ -619,8 +617,6 @@ func (e *DNSError) Temporary() bool { return e.IsTimeout || e.IsTemporary }
func (e *DNSError) Is(target error) bool { func (e *DNSError) Is(target error) bool {
switch target { switch target {
case os.ErrTemporary:
return e.Temporary()
case os.ErrTimeout: case os.ErrTimeout:
return e.Timeout() return e.Timeout()
} }
......
...@@ -86,7 +86,7 @@ func (timeoutError) Timeout() bool { return true } ...@@ -86,7 +86,7 @@ func (timeoutError) Timeout() bool { return true }
func (timeoutError) Temporary() bool { return true } func (timeoutError) Temporary() bool { return true }
func (timeoutError) Is(target error) bool { func (timeoutError) Is(target error) bool {
return target == os.ErrTemporary || target == os.ErrTimeout return target == os.ErrTimeout
} }
type pipeAddr struct{} type pipeAddr struct{}
......
...@@ -29,7 +29,13 @@ type Error struct { ...@@ -29,7 +29,13 @@ type Error struct {
func (e *Error) Unwrap() error { return e.Err } func (e *Error) Unwrap() error { return e.Err }
func (e *Error) Error() string { return e.Op + " " + e.URL + ": " + e.Err.Error() } func (e *Error) Error() string { return e.Op + " " + e.URL + ": " + e.Err.Error() }
func (e *Error) Timeout() bool { return oserror.IsTimeout(e.Err) } func (e *Error) Timeout() bool { return oserror.IsTimeout(e.Err) }
func (e *Error) Temporary() bool { return oserror.IsTemporary(e.Err) }
func (e *Error) Temporary() bool {
t, ok := e.Err.(interface {
Temporary() bool
})
return ok && t.Temporary()
}
func ishex(c byte) bool { func ishex(c byte) bool {
switch { switch {
......
...@@ -23,7 +23,6 @@ var ( ...@@ -23,7 +23,6 @@ var (
ErrNotExist = errNotExist() // "file does not exist" ErrNotExist = errNotExist() // "file does not exist"
ErrClosed = errClosed() // "file already closed" ErrClosed = errClosed() // "file already closed"
ErrTimeout = errTimeout() // "deadline exceeded" ErrTimeout = errTimeout() // "deadline exceeded"
ErrTemporary = errTemporary() // "temporary error"
ErrNoDeadline = errNoDeadline() // "file type does not support deadline" ErrNoDeadline = errNoDeadline() // "file type does not support deadline"
) )
...@@ -33,7 +32,6 @@ func errExist() error { return oserror.ErrExist } ...@@ -33,7 +32,6 @@ func errExist() error { return oserror.ErrExist }
func errNotExist() error { return oserror.ErrNotExist } func errNotExist() error { return oserror.ErrNotExist }
func errClosed() error { return oserror.ErrClosed } func errClosed() error { return oserror.ErrClosed }
func errTimeout() error { return oserror.ErrTimeout } func errTimeout() error { return oserror.ErrTimeout }
func errTemporary() error { return oserror.ErrTemporary }
func errNoDeadline() error { return poll.ErrNoDeadline } func errNoDeadline() error { return poll.ErrNoDeadline }
type timeout interface { type timeout interface {
......
...@@ -58,8 +58,6 @@ func (e Errno) Error() string { ...@@ -58,8 +58,6 @@ func (e Errno) Error() string {
func (e Errno) Is(target error) bool { func (e Errno) Is(target error) bool {
switch target { switch target {
case oserror.ErrTemporary:
return e.Temporary()
case oserror.ErrTimeout: case oserror.ErrTimeout:
return e.Timeout() return e.Timeout()
case oserror.ErrPermission: case oserror.ErrPermission:
......
...@@ -65,8 +65,6 @@ func (e Errno) Error() string { ...@@ -65,8 +65,6 @@ func (e Errno) Error() string {
func (e Errno) Is(target error) bool { func (e Errno) Is(target error) bool {
switch target { switch target {
case oserror.ErrTemporary:
return e.Temporary()
case oserror.ErrTimeout: case oserror.ErrTimeout:
return e.Timeout() return e.Timeout()
case oserror.ErrPermission: case oserror.ErrPermission:
......
...@@ -29,8 +29,6 @@ func NewError(s string) error { return ErrorString(s) } ...@@ -29,8 +29,6 @@ func NewError(s string) error { return ErrorString(s) }
func (e ErrorString) Is(target error) bool { func (e ErrorString) Is(target error) bool {
switch target { switch target {
case oserror.ErrTemporary:
return e.Temporary()
case oserror.ErrTimeout: case oserror.ErrTimeout:
return e.Timeout() return e.Timeout()
case oserror.ErrPermission: case oserror.ErrPermission:
......
...@@ -121,8 +121,6 @@ func (e Errno) Error() string { ...@@ -121,8 +121,6 @@ func (e Errno) Error() string {
func (e Errno) Is(target error) bool { func (e Errno) Is(target error) bool {
switch target { switch target {
case oserror.ErrTemporary:
return e.Temporary()
case oserror.ErrTimeout: case oserror.ErrTimeout:
return e.Timeout() return e.Timeout()
case oserror.ErrPermission: case oserror.ErrPermission:
......
...@@ -115,8 +115,6 @@ const _ERROR_BAD_NETPATH = Errno(53) ...@@ -115,8 +115,6 @@ const _ERROR_BAD_NETPATH = Errno(53)
func (e Errno) Is(target error) bool { func (e Errno) Is(target error) bool {
switch target { switch target {
case oserror.ErrTemporary:
return e.Temporary()
case oserror.ErrTimeout: case oserror.ErrTimeout:
return e.Timeout() return e.Timeout()
case oserror.ErrPermission: case oserror.ErrPermission:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment