Skip to content

Commit

Permalink
implement noopTags as an allocation optimization (#80)
Browse files Browse the repository at this point in the history
* implement noopTags
* fix tag reference
  • Loading branch information
flisky authored and Michal Witkowski committed Apr 1, 2018
1 parent aed189a commit bc372cc
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 17 deletions.
54 changes: 40 additions & 14 deletions tags/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,43 +10,69 @@ var (
// ctxMarkerKey is the Context value marker used by *all* logging middleware.
// The logging middleware object must interf
ctxMarkerKey = &ctxMarker{}
// NoopTags is a trivial, minimum overhead implementation of Tags for which all operations are no-ops.
NoopTags = &noopTags{}
)

// Tags is the struct used for storing request tags between Context calls.
// This object is *not* thread safe, and should be handled only in the context of the request.
type Tags struct {
// Tags is the interface used for storing request tags between Context calls.
// The default implementation is *not* thread safe, and should be handled only in the context of the request.
type Tags interface {
// Set sets the given key in the metadata tags.
Set(key string, value interface{}) Tags
// Has checks if the given key exists.
Has(key string) bool
// Values returns a map of key to values.
// Do not modify the underlying map, please use Set instead.
Values() map[string]interface{}
}

type mapTags struct {
values map[string]interface{}
}

// Set sets the given key in the metadata tags.
func (t *Tags) Set(key string, value interface{}) *Tags {
func (t *mapTags) Set(key string, value interface{}) Tags {
t.values[key] = value
return t
}

// Has checks if the given key exists.
func (t *Tags) Has(key string) bool {
func (t *mapTags) Has(key string) bool {
_, ok := t.values[key]
return ok
}

// Values returns a map of key to values.
// Do not modify the underlying map, please use Set instead.
func (t *Tags) Values() map[string]interface{} {
func (t *mapTags) Values() map[string]interface{} {
return t.values
}

type noopTags struct{}

func (t *noopTags) Set(key string, value interface{}) Tags {
return t
}

func (t *noopTags) Has(key string) bool {
return false
}

func (t *noopTags) Values() map[string]interface{} {
return nil
}

// Extracts returns a pre-existing Tags object in the Context.
// If the context wasn't set in a tag interceptor, a no-op Tag storage is returned that will *not* be propagated in context.
func Extract(ctx context.Context) *Tags {
t, ok := ctx.Value(ctxMarkerKey).(*Tags)
func Extract(ctx context.Context) Tags {
t, ok := ctx.Value(ctxMarkerKey).(Tags)
if !ok {
return &Tags{values: make(map[string]interface{})}
return NoopTags
}

return t
}

func setInContext(ctx context.Context, tags *Tags) context.Context {
func setInContext(ctx context.Context, tags Tags) context.Context {
return context.WithValue(ctx, ctxMarkerKey, tags)
}

func newTags() Tags {
return &mapTags{values: make(map[string]interface{})}
}
2 changes: 1 addition & 1 deletion tags/interceptors.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (w *wrappedStream) RecvMsg(m interface{}) error {
}

func newTagsForCtx(ctx context.Context) context.Context {
t := Extract(ctx) // will allocate a new one if it didn't exist.
t := newTags()
if peer, ok := peer.FromContext(ctx); ok {
t.Set("peer.address", peer.Addr.String())
}
Expand Down
4 changes: 2 additions & 2 deletions tracing/opentracing/id_extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@ const (
// Most tracers have them encoded as keys with 'traceid' and 'spanid':
// https://github.com/openzipkin/zipkin-go-opentracing/blob/594640b9ef7e5c994e8d9499359d693c032d738c/propagation_ot.go#L29
// https://github.com/opentracing/basictracer-go/blob/1b32af207119a14b1b231d451df3ed04a72efebf/propagation_ot.go#L26
func hackyInjectOpentracingIdsToTags(span opentracing.Span, tags *grpc_ctxtags.Tags) {
func hackyInjectOpentracingIdsToTags(span opentracing.Span, tags grpc_ctxtags.Tags) {
if err := span.Tracer().Inject(span.Context(), opentracing.HTTPHeaders, &hackyTagsCarrier{tags}); err != nil {
grpclog.Printf("grpc_opentracing: failed extracting trace info into ctx %v", err)
}
}

// hackyTagsCarrier is a really hacky way of
type hackyTagsCarrier struct {
*grpc_ctxtags.Tags
grpc_ctxtags.Tags
}

func (t *hackyTagsCarrier) Set(key, val string) {
Expand Down

0 comments on commit bc372cc

Please sign in to comment.