Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 15 additions & 45 deletions Makefile.update-protos
Original file line number Diff line number Diff line change
@@ -1,32 +1,18 @@
# This makefile can be used to-regenerate the protobuf files.
# This makefile can be used to regenerate the protobuf files.
#
# Prerequisites:
# "protoc" from https://github.com/protocolbuffers/protobuf
# go get github.com/cockroachdb/protoc-gen-gogoroach
# go get github.com/gogo/protobuf/types
# go get github.com/gogo/protobuf/protoc-gen-gogo
# protoc https://github.com/protocolbuffers/protobuf
# protoc-gen-go go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
# protoc-gen-go-grpc go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
#
# Note: as of 2021-04-13, we like to use a custom protoc-gen-gogo
# with additional options, to stabilize the marshalled
# encoding of objects (so that they are deterministic
# across marshal/unmarshal cycles) and reduce the memory footprint
# of objects:
# Run: make -f Makefile.update-protos
#
# vanity.TurnOnStable_MarshalerAll,
# vanity.TurnOffGoUnrecognizedAll,
# vanity.TurnOffGoUnkeyedAll,
# vanity.TurnOffGoSizecacheAll,
#
# Until this is resolved, the "go get" commands above are not
# adequate; instead:
#
# 1. set the PATH env var to point to CockroachDB's `bin`
# sub-directory (after a successful CockroachDB build), where a
# suitable version of protoc-gen-gogoroach is provided.
#
# 2. run `make -f Makefile.update-protos` with this PATH active.

export SHELL := env PWD=$(CURDIR) bash
# Note: the standard protoc-gen-go runtime always embeds state/sizeCache/
# unknownFields per message and has no equivalent of the old gogo vanity
# options. These messages have no map fields, so proto.Marshal output is
# already byte-stable across marshal/unmarshal cycles (add
# proto.MarshalOptions{Deterministic: true} if a map field is ever added).
# The gogo memory-footprint trimming has no standard equivalent.

PROTOS := $(wildcard \
errbase/internal/*.proto \
Expand All @@ -38,25 +24,9 @@ PROTOS := $(wildcard \
)
GO_SOURCES = $(PROTOS:.proto=.pb.go)

SED = sed
SED_INPLACE := $(shell $(SED) --version 2>&1 | grep -q GNU && echo -i || echo "-i ''")

all: $(PROTOS)
set -e; for dir in $(sort $(dir $(PROTOS))); do \
protoc \
-I. \
-I$$GOPATH/src/ \
-I$$GOPATH/src/github.com \
-I$$GOPATH/src/github.com/cockroachdb/errors \
-I$$GOPATH/src/github.com/gogo/protobuf \
-I$$GOPATH/src/github.com/gogo/protobuf/protobuf \
--gogoroach_out=Mgoogle/protobuf/any.proto=github.com/gogo/protobuf/types,plugins=grpc,import_prefix=:. \
$$dir/*.proto; \
done
$(SED) $(SED_INPLACE) -E \
-e '/import _ /d' \
-e 's!import (fmt|math) "github.com/(fmt|math)"! !g' \
-e 's!github.com/((bytes|encoding/binary|errors|fmt|io|math|github\.com|(google\.)?golang\.org)([^a-z]|$$))!\1!g' \
-e 's!golang.org/x/net/context!context!g' \
$(GO_SOURCES)
protoc -I. \
--go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
$(PROTOS)
gofmt -s -w $(GO_SOURCES)
2 changes: 1 addition & 1 deletion assert/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
"github.com/cockroachdb/errors/errbase"
"github.com/cockroachdb/errors/markers"
"github.com/cockroachdb/errors/stdstrings"
"github.com/gogo/protobuf/proto"
"google.golang.org/protobuf/proto"
)

// WithAssertionFailure decorates the error with an assertion failure marker.
Expand Down
2 changes: 1 addition & 1 deletion assert/assert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func TestAssert(t *testing.T) {
tt.CheckEqual(err.Error(), "hello: world")

enc := errbase.EncodeError(context.Background(), err)
newErr := errbase.DecodeError(context.Background(), enc)
newErr := errbase.DecodeError(context.Background(), &enc)

tt.Check(markers.Is(newErr, baseErr))

Expand Down
6 changes: 3 additions & 3 deletions barriers/barriers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (

"github.com/cockroachdb/errors/errbase"
"github.com/cockroachdb/redact"
"github.com/gogo/protobuf/proto"
"google.golang.org/protobuf/proto"
)

// Handled swallows the provided error and hides it from the
Expand Down Expand Up @@ -123,13 +123,13 @@ func encodeBarrier(
// A barrier error is decoded exactly.
func decodeBarrier(ctx context.Context, msg string, _ []string, payload proto.Message) error {
enc := payload.(*errbase.EncodedError)
return &barrierErr{smsg: redact.RedactableString(msg), maskedErr: errbase.DecodeError(ctx, *enc)}
return &barrierErr{smsg: redact.RedactableString(msg), maskedErr: errbase.DecodeError(ctx, enc)}
}

// Previous versions of barrier errors.
func decodeBarrierPrev(ctx context.Context, msg string, _ []string, payload proto.Message) error {
enc := payload.(*errbase.EncodedError)
return &barrierErr{smsg: redact.Sprint(msg), maskedErr: errbase.DecodeError(ctx, *enc)}
return &barrierErr{smsg: redact.Sprint(msg), maskedErr: errbase.DecodeError(ctx, enc)}
}

// barrierError is the "old" type name of barrierErr. We use a new
Expand Down
2 changes: 1 addition & 1 deletion barriers/barriers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func TestBarrierMaskedDetails(t *testing.T) {

// Simulate a network traversal.
enc := errbase.EncodeError(context.Background(), b)
newB := errbase.DecodeError(context.Background(), enc)
newB := errbase.DecodeError(context.Background(), &enc)

// The friends message is hidden.
tt.Check(!strings.Contains(b.Error(), "friends"))
Expand Down
4 changes: 2 additions & 2 deletions contexttags/contexttags_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func TestWithContext(t *testing.T) {
tt.Run("local", func(tt testutils.T) { theTest(tt, decoratedErr) })

enc := errbase.EncodeError(context.Background(), decoratedErr)
newErr := errbase.DecodeError(context.Background(), enc)
newErr := errbase.DecodeError(context.Background(), &enc)

tt.Run("remote", func(tt testutils.T) { theTest(tt, newErr) })
}
Expand Down Expand Up @@ -137,7 +137,7 @@ func TestTagRedactionInSafeDetails(t *testing.T) {
tt.Run("local", func(tt testutils.T) { theTest(tt, decoratedErr) })

enc := errbase.EncodeError(context.Background(), decoratedErr)
newErr := errbase.DecodeError(context.Background(), enc)
newErr := errbase.DecodeError(context.Background(), &enc)

tt.Run("remote", func(tt testutils.T) { theTest(tt, newErr) })

Expand Down
4 changes: 2 additions & 2 deletions contexttags/with_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"github.com/cockroachdb/errors/errorspb"
"github.com/cockroachdb/logtags"
"github.com/cockroachdb/redact"
"github.com/gogo/protobuf/proto"
"google.golang.org/protobuf/proto"
)

type withContext struct {
Expand Down Expand Up @@ -79,7 +79,7 @@ func encodeWithContext(_ context.Context, err error) (string, []string, proto.Me
w := err.(*withContext)
p := &errorspb.TagsPayload{}
for _, t := range w.tags.Get() {
p.Tags = append(p.Tags, errorspb.TagPayload{Tag: t.Key(), Value: t.ValueStr()})
p.Tags = append(p.Tags, &errorspb.TagPayload{Tag: t.Key(), Value: t.ValueStr()})
}
return "", w.SafeDetails(), p
}
Expand Down
2 changes: 1 addition & 1 deletion domains/with_domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (

"github.com/cockroachdb/errors/errbase"
"github.com/cockroachdb/redact"
"github.com/gogo/protobuf/proto"
"google.golang.org/protobuf/proto"
)

// withDomain is a wrapper type that adds a domain annotation to an
Expand Down
2 changes: 1 addition & 1 deletion errbase/adapters.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import (
"os"

"github.com/cockroachdb/errors/errorspb"
"github.com/gogo/protobuf/proto"
pkgErr "github.com/pkg/errors"
"google.golang.org/protobuf/proto"
)

// This file provides the library the ability to encode/decode
Expand Down
3 changes: 2 additions & 1 deletion errbase/adapters_errno.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// implied. See the License for the specific language governing
// permissions and limitations under the License.

//go:build !plan9
// +build !plan9

package errbase
Expand All @@ -23,7 +24,7 @@ import (
"syscall"

"github.com/cockroachdb/errors/errorspb"
"github.com/gogo/protobuf/proto"
"google.golang.org/protobuf/proto"
)

const thisArch = runtime.GOOS + ":" + runtime.GOARCH
Expand Down
15 changes: 8 additions & 7 deletions errbase/adapters_errno_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// implied. See the License for the specific language governing
// permissions and limitations under the License.

//go:build !plan9
// +build !plan9

package errbase_test
Expand All @@ -26,7 +27,7 @@ import (
"github.com/cockroachdb/errors/errorspb"
"github.com/cockroachdb/errors/oserror"
"github.com/cockroachdb/errors/testutils"
"github.com/gogo/protobuf/types"
"google.golang.org/protobuf/types/known/anypb"
)

func TestAdaptErrno(t *testing.T) {
Expand All @@ -46,21 +47,21 @@ func TestAdaptErrno(t *testing.T) {
enc := errbase.EncodeError(context.Background(), origErr)

// Trick the decoder into thinking the error comes from a different platform.
details := &enc.Error.(*errorspb.EncodedError_Leaf).Leaf.Details
var d types.DynamicAny
if err := types.UnmarshalAny(details.FullDetails, &d); err != nil {
details := enc.Error.(*errorspb.EncodedError_Leaf).Leaf.Details
d, err := details.FullDetails.UnmarshalNew()
if err != nil {
t.Fatal(err)
}
errnoDetails := d.Message.(*errorspb.ErrnoPayload)
errnoDetails := d.(*errorspb.ErrnoPayload)
errnoDetails.Arch = "OTHER"
any, err := types.MarshalAny(errnoDetails)
any, err := anypb.New(errnoDetails)
if err != nil {
t.Fatal(err)
}
details.FullDetails = any

// Now decode the error. This produces an OpaqueErrno payload.
dec := errbase.DecodeError(context.Background(), enc)
dec := errbase.DecodeError(context.Background(), &enc)
if _, ok := dec.(*errbase.OpaqueErrno); !ok {
t.Fatalf("expected OpaqueErrno, got %T", dec)
}
Expand Down
22 changes: 16 additions & 6 deletions errbase/adapters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,14 @@ import (
"github.com/cockroachdb/errors/testutils"
"github.com/kr/pretty"
pkgErr "github.com/pkg/errors"
"google.golang.org/protobuf/proto"
)

func network(t *testing.T, err error) error {
t.Helper()
enc := errbase.EncodeError(context.Background(), err)
t.Logf("encoded: %# v", pretty.Formatter(enc))
newErr := errbase.DecodeError(context.Background(), enc)
t.Logf("encoded: %# v", pretty.Formatter(&enc))
newErr := errbase.DecodeError(context.Background(), &enc)
t.Logf("decoded: %# v", pretty.Formatter(newErr))
return newErr
}
Expand Down Expand Up @@ -188,8 +189,12 @@ func TestAdaptProtoErrors(t *testing.T) {
// In any case, the library preserves the error message.
tt.CheckEqual(newErr.Error(), origErr.Error())

// Moreover, it preserves the entire structure.
tt.CheckDeepEqual(newErr, origErr)
// Moreover, it preserves the entire structure. Proto v2 messages
// carry internal bookkeeping state that reflect.DeepEqual would
// also (unreliably) compare, so use proto.Equal instead.
newErrProto, ok := newErr.(proto.Message)
tt.Check(ok)
tt.Check(proto.Equal(newErrProto, origErr))
}

func TestAdaptProtoErrorsWithWrapper(t *testing.T) {
Expand All @@ -206,8 +211,13 @@ func TestAdaptProtoErrorsWithWrapper(t *testing.T) {
// In any case, the library preserves the error message.
tt.CheckEqual(newErr.Error(), origErr.Error())

// Moreover, it preserves the entire structure.
tt.CheckDeepEqual(newErr, origErr)
// Moreover, it preserves the entire structure, including the
// wrapped proto message. Proto v2 messages carry internal
// bookkeeping state that reflect.DeepEqual would also (unreliably)
// compare, so compare the wrapped cause with proto.Equal instead.
newCause, ok := goErr.Unwrap(newErr).(proto.Message)
tt.Check(ok)
tt.Check(proto.Equal(newCause, rErr))
}

func TestAdaptContextCanceled(t *testing.T) {
Expand Down
33 changes: 15 additions & 18 deletions errbase/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@ import (
"context"

"github.com/cockroachdb/errors/errorspb"
"github.com/gogo/protobuf/proto"
"github.com/gogo/protobuf/types"
"google.golang.org/protobuf/proto"
)

// DecodeError decodes an error.
//
// Can only be called if the EncodedError is set (see IsSet()).
func DecodeError(ctx context.Context, enc EncodedError) error {
func DecodeError(ctx context.Context, enc *EncodedError) error {
if w := enc.GetWrapper(); w != nil {
return decodeWrapper(ctx, w)
}
Expand All @@ -35,23 +34,22 @@ func DecodeError(ctx context.Context, enc EncodedError) error {
func decodeLeaf(ctx context.Context, enc *errorspb.EncodedErrorLeaf) error {
// In case there is a detailed payload, decode it.
var payload proto.Message
if enc.Details.FullDetails != nil {
var d types.DynamicAny
err := types.UnmarshalAny(enc.Details.FullDetails, &d)
if fd := enc.GetDetails().GetFullDetails(); fd != nil {
d, err := fd.UnmarshalNew()
if err != nil {
// It's OK if we can't decode. We'll use
// the opaque type below.
warningFn(ctx, "error while unmarshalling error: %+v", err)
} else {
payload = d.Message
payload = d
}
}

// Do we have a leaf decoder for this type?
typeKey := TypeKey(enc.Details.ErrorTypeMark.FamilyName)
typeKey := TypeKey(enc.GetDetails().GetErrorTypeMark().GetFamilyName())
if decoder, ok := leafDecoders[typeKey]; ok {
// Yes, use it.
genErr := decoder(ctx, enc.Message, enc.Details.ReportablePayload, payload)
genErr := decoder(ctx, enc.Message, enc.GetDetails().GetReportablePayload(), payload)
if genErr != nil {
// Decoding succeeded. Use this.
return genErr
Expand All @@ -60,9 +58,9 @@ func decodeLeaf(ctx context.Context, enc *errorspb.EncodedErrorLeaf) error {
} else if decoder, ok := multiCauseDecoders[typeKey]; ok {
causes := make([]error, len(enc.MultierrorCauses))
for i, e := range enc.MultierrorCauses {
causes[i] = DecodeError(ctx, *e)
causes[i] = DecodeError(ctx, e)
}
genErr := decoder(ctx, causes, enc.Message, enc.Details.ReportablePayload, payload)
genErr := decoder(ctx, causes, enc.Message, enc.GetDetails().GetReportablePayload(), payload)
if genErr != nil {
return genErr
}
Expand All @@ -78,7 +76,7 @@ func decodeLeaf(ctx context.Context, enc *errorspb.EncodedErrorLeaf) error {
if len(enc.MultierrorCauses) > 0 {
causes := make([]error, len(enc.MultierrorCauses))
for i, e := range enc.MultierrorCauses {
causes[i] = DecodeError(ctx, *e)
causes[i] = DecodeError(ctx, e)
}
leaf := &opaqueLeafCauses{
causes: causes,
Expand All @@ -103,23 +101,22 @@ func decodeWrapper(ctx context.Context, enc *errorspb.EncodedWrapper) error {

// In case there is a detailed payload, decode it.
var payload proto.Message
if enc.Details.FullDetails != nil {
var d types.DynamicAny
err := types.UnmarshalAny(enc.Details.FullDetails, &d)
if fd := enc.GetDetails().GetFullDetails(); fd != nil {
d, err := fd.UnmarshalNew()
if err != nil {
// It's OK if we can't decode. We'll use
// the opaque type below.
warningFn(ctx, "error while unmarshalling wrapper error: %+v", err)
} else {
payload = d.Message
payload = d
}
}

// Do we have a wrapper decoder for this?
typeKey := TypeKey(enc.Details.ErrorTypeMark.FamilyName)
typeKey := TypeKey(enc.GetDetails().GetErrorTypeMark().GetFamilyName())
if decoder, ok := decoders[typeKey]; ok {
// Yes, use it.
genErr := decoder(ctx, cause, enc.Message, enc.Details.ReportablePayload, payload)
genErr := decoder(ctx, cause, enc.Message, enc.GetDetails().GetReportablePayload(), payload)
if genErr != nil {
// Decoding succeeded. Use this.
return genErr
Expand Down
Loading