mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 04:06:03 +00:00
api/errors: Improve performance of Is* functions
Type assertion is faster than "errors.As" when the error is not wrapped. Allocations are unaffected. Benchmark results: ``` name old time/op new time/op delta IsAlreadyExistsWrappedErrors/Nil-4 72.8ns ±11% 79.6ns ±12% ~ (p=0.343 n=4+4) IsAlreadyExistsWrappedErrors/Bare-4 336ns ± 6% 95ns ±10% -71.70% (p=0.029 n=4+4) IsAlreadyExistsWrappedErrors/Wrapped-4 416ns ± 1% 426ns ± 4% ~ (p=0.486 n=4+4) IsNotFoundWrappedErrors/Nil-4 102ns ± 4% 97ns ± 4% ~ (p=0.114 n=4+4) IsNotFoundWrappedErrors/Bare-4 350ns ± 3% 102ns ± 6% -70.78% (p=0.029 n=4+4) IsNotFoundWrappedErrors/Wrapped-4 448ns ± 3% 462ns ± 2% ~ (p=0.200 n=4+4) ```
This commit is contained in:
parent
d404991eff
commit
13ebe3b454
@ -96,8 +96,8 @@ func HasStatusCause(err error, name metav1.CauseType) bool {
|
||||
// StatusCause returns the named cause from the provided error if it exists and
|
||||
// the error unwraps to the type APIStatus. Otherwise it returns false.
|
||||
func StatusCause(err error, name metav1.CauseType) (metav1.StatusCause, bool) {
|
||||
var status APIStatus
|
||||
if errors.As(err, &status) && status.Status().Details != nil {
|
||||
status, ok := err.(APIStatus)
|
||||
if (ok || errors.As(err, &status)) && status.Status().Details != nil {
|
||||
for _, cause := range status.Status().Details.Causes {
|
||||
if cause.Type == name {
|
||||
return cause, true
|
||||
@ -757,7 +757,8 @@ func IsRequestEntityTooLargeError(err error) bool {
|
||||
// and may be the result of another HTTP actor.
|
||||
// It supports wrapped errors and returns false when the error is nil.
|
||||
func IsUnexpectedServerError(err error) bool {
|
||||
if status := APIStatus(nil); errors.As(err, &status) && status.Status().Details != nil {
|
||||
status, ok := err.(APIStatus)
|
||||
if (ok || errors.As(err, &status)) && status.Status().Details != nil {
|
||||
for _, cause := range status.Status().Details.Causes {
|
||||
if cause.Type == metav1.CauseTypeUnexpectedServerResponse {
|
||||
return true
|
||||
@ -770,8 +771,8 @@ func IsUnexpectedServerError(err error) bool {
|
||||
// IsUnexpectedObjectError determines if err is due to an unexpected object from the master.
|
||||
// It supports wrapped errors and returns false when the error is nil.
|
||||
func IsUnexpectedObjectError(err error) bool {
|
||||
uoe := &UnexpectedObjectError{}
|
||||
return err != nil && errors.As(err, &uoe)
|
||||
uoe, ok := err.(*UnexpectedObjectError)
|
||||
return err != nil && (ok || errors.As(err, &uoe))
|
||||
}
|
||||
|
||||
// SuggestsClientDelay returns true if this error suggests a client delay as well as the
|
||||
@ -780,7 +781,8 @@ func IsUnexpectedObjectError(err error) bool {
|
||||
// request delay without retry.
|
||||
// It supports wrapped errors and returns false when the error is nil.
|
||||
func SuggestsClientDelay(err error) (int, bool) {
|
||||
if t := APIStatus(nil); errors.As(err, &t) && t.Status().Details != nil {
|
||||
t, ok := err.(APIStatus)
|
||||
if (ok || errors.As(err, &t)) && t.Status().Details != nil {
|
||||
switch t.Status().Reason {
|
||||
// this StatusReason explicitly requests the caller to delay the action
|
||||
case metav1.StatusReasonServerTimeout:
|
||||
@ -798,14 +800,14 @@ func SuggestsClientDelay(err error) (int, bool) {
|
||||
// It supports wrapped errors and returns StatusReasonUnknown when
|
||||
// the error is nil or doesn't have a status.
|
||||
func ReasonForError(err error) metav1.StatusReason {
|
||||
if status := APIStatus(nil); errors.As(err, &status) {
|
||||
if status, ok := err.(APIStatus); ok || errors.As(err, &status) {
|
||||
return status.Status().Reason
|
||||
}
|
||||
return metav1.StatusReasonUnknown
|
||||
}
|
||||
|
||||
func reasonAndCodeForError(err error) (metav1.StatusReason, int32) {
|
||||
if status := APIStatus(nil); errors.As(err, &status) {
|
||||
if status, ok := err.(APIStatus); ok || errors.As(err, &status) {
|
||||
return status.Status().Reason, status.Status().Code
|
||||
}
|
||||
return metav1.StatusReasonUnknown, 0
|
||||
|
@ -657,3 +657,49 @@ func TestStatusCauseSupportsWrappedErrors(t *testing.T) {
|
||||
t.Errorf("expected cause when nested, got %v: %#v", ok, cause)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkIsAlreadyExistsWrappedErrors(b *testing.B) {
|
||||
err := NewAlreadyExists(schema.GroupResource{}, "")
|
||||
wrapped := fmt.Errorf("once: %w", err)
|
||||
|
||||
b.Run("Nil", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsAlreadyExists(nil)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Bare", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsAlreadyExists(err)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Wrapped", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsAlreadyExists(wrapped)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkIsNotFoundWrappedErrors(b *testing.B) {
|
||||
err := NewNotFound(schema.GroupResource{}, "")
|
||||
wrapped := fmt.Errorf("once: %w", err)
|
||||
|
||||
b.Run("Nil", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsNotFound(nil)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Bare", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsNotFound(err)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("Wrapped", func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
IsNotFound(wrapped)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user