Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

roachpb: clarify parameter to (*Error).SetDetail #56581

Merged
merged 2 commits into from
Nov 12, 2020

Conversation

tbg
Copy link
Member

@tbg tbg commented Nov 11, 2020

roachpb: clarify parameter to (*Error).SetDetail

The circuitous error handling has long been a source of confusion,
but there are some straightforward modifications, one of which this
commit makes: there is no reason to pass an error to SetDetail;
it can always be an ErrorDetail. In particular, this prevents a
situation which caused problems in the past, namely that of passing
an *Error to SetDetail (which in itself is a method on *Error).
This is just not possible now, period, because we're also changing
internalError to not implement ErrorDetailInterface.

Most of the time in this change was verifying that nothing in the
code relies on GetDetail() always returning a non-nil value for
a non-nil pErr. I did a full review (prod and tests) and found
a few such instances, but the vast majority of callers are of the
pattern

if pErr != nil {
  if _, ok := pErr.GetDetail().(*roachpb.SomeErrorDetail); ok {
    return specialHandling()
  }
  return pErr
}

and thus required no change.

Release note: None

@cockroach-teamcity
Copy link
Member

This change is Reviewable

Copy link
Member

@nvanbenschoten nvanbenschoten left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm_strong:

Reviewed 1 of 1 files at r1, 7 of 7 files at r2.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @tbg)


pkg/kv/kvserver/store.go, line 1740 at r2 (raw file):

				annotatedCtx := repl.AnnotateCtx(ctx)
				if _, pErr := repl.redirectOnOrAcquireLease(annotatedCtx); pErr != nil {
					if _, ok := pErr.GoError().(*roachpb.NotLeaseHolderError); !ok {

Do we want GoError in cases like these where we're testing for a specific ErrorDetail type? Doesn't that have a chance of being more expensive than GetDetail, due to the creation of an UnhandledRetryableError?

I wonder whether this is common enough that we should invest in a HasDetail or HasDetailType method. Maybe even one that accepts an ErrorDetailType. That's a drive-by comment so don't pursue it unless you think it's a good idea.


pkg/roachpb/errors.go, line 311 at r2 (raw file):

	}
	// If the specific error type exists in the detail union, set it.
	if !e.Detail.SetInner(detail) {

Does it make sense for this to ever return false anymore? Should we assert that it doesn't? Or even create a MustSetInner method like we have elsewhere?

This code path is only hit when `err` is not an `*internalError`.

Release note: None
The circuitous error handling has long been a source of confusion,
but there are some straightforward modifications, one of which this
commit makes: there is no reason to pass an `error` to `SetDetail`;
it can always be an `ErrorDetail`. In particular, this prevents a
situation which caused problems in the past, namely that of passing
an `*Error` to `SetDetail` (which in itself is a method on `*Error`).
This is just not possible now, period, because we're also changing
`internalError` to *not* implement `ErrorDetailInterface`.

Most of the time in this change was verifying that nothing in the
code relies on `GetDetail()` always returning a non-nil value for
a non-nil `pErr`. I did a full review (prod and tests) and found
a few such instances, but the vast majority of callers are of the
pattern

```go
if pErr != nil {
  if _, ok := pErr.GetDetail().(*roachpb.SomeErrorDetail); ok {
    return specialHandling()
  }
  return pErr
}
```

and thus required no change.

Release note: None
Copy link
Member Author

@tbg tbg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @nvanbenschoten)


pkg/kv/kvserver/store.go, line 1740 at r2 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

Do we want GoError in cases like these where we're testing for a specific ErrorDetail type? Doesn't that have a chance of being more expensive than GetDetail, due to the creation of an UnhandledRetryableError?

I wonder whether this is common enough that we should invest in a HasDetail or HasDetailType method. Maybe even one that accepts an ErrorDetailType. That's a drive-by comment so don't pursue it unless you think it's a good idea.

Huh, I'm not sure why I even changed this line. The original was fine and didn't incur the alloc.


pkg/roachpb/errors.go, line 311 at r2 (raw file):

Previously, nvanbenschoten (Nathan VanBenschoten) wrote…

Does it make sense for this to ever return false anymore? Should we assert that it doesn't? Or even create a MustSetInner method like we have elsewhere?

good idea, #56600

@tbg
Copy link
Member Author

tbg commented Nov 12, 2020

bors r=nvanbenschoten

@craig
Copy link
Contributor

craig bot commented Nov 12, 2020

Build succeeded:

@craig craig bot merged commit 6d2ce39 into cockroachdb:master Nov 12, 2020
Copy link
Contributor

@andreimatei andreimatei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In particular, this prevents a
situation which caused problems in the past, namely that of passing
an *Error to SetDetail (which in itself is a method on *Error).
This is just not possible now, period, because we're also changing
internalError to not implement ErrorDetailInterface.

I think this is a fine patch, but I'm a bit confused about this motivation. It is not true that a *Error could have been passed to SetDetail() - *Error does not implement error. What you could have done is pErr.SetDetail(pErr2.GoError()). Is that what you were trying to prevent?

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @nvanbenschoten)

Copy link
Member Author

@tbg tbg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was a bit sloppy in the description - GoError() can return an *internalError which is structually equivalent to *Error. The whole cyclical nature of everything here just got me really confused so it had to go.

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @nvanbenschoten)

Copy link
Member Author

@tbg tbg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "true" motivation is that I wanted to do #56603, and so I needed some initial cleanups to get some sanity going :-)

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @nvanbenschoten)

@andreimatei
Copy link
Contributor

andreimatei commented Nov 12, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants