Skip to content

Commit bc372cc

Browse files
fliskyMichal Witkowski
authored andcommitted
implement noopTags as an allocation optimization (grpc-ecosystem#80)
* implement noopTags * fix tag reference
1 parent aed189a commit bc372cc

File tree

3 files changed

+43
-17
lines changed

3 files changed

+43
-17
lines changed

tags/context.go

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,43 +10,69 @@ var (
1010
// ctxMarkerKey is the Context value marker used by *all* logging middleware.
1111
// The logging middleware object must interf
1212
ctxMarkerKey = &ctxMarker{}
13+
// NoopTags is a trivial, minimum overhead implementation of Tags for which all operations are no-ops.
14+
NoopTags = &noopTags{}
1315
)
1416

15-
// Tags is the struct used for storing request tags between Context calls.
16-
// This object is *not* thread safe, and should be handled only in the context of the request.
17-
type Tags struct {
17+
// Tags is the interface used for storing request tags between Context calls.
18+
// The default implementation is *not* thread safe, and should be handled only in the context of the request.
19+
type Tags interface {
20+
// Set sets the given key in the metadata tags.
21+
Set(key string, value interface{}) Tags
22+
// Has checks if the given key exists.
23+
Has(key string) bool
24+
// Values returns a map of key to values.
25+
// Do not modify the underlying map, please use Set instead.
26+
Values() map[string]interface{}
27+
}
28+
29+
type mapTags struct {
1830
values map[string]interface{}
1931
}
2032

21-
// Set sets the given key in the metadata tags.
22-
func (t *Tags) Set(key string, value interface{}) *Tags {
33+
func (t *mapTags) Set(key string, value interface{}) Tags {
2334
t.values[key] = value
2435
return t
2536
}
2637

27-
// Has checks if the given key exists.
28-
func (t *Tags) Has(key string) bool {
38+
func (t *mapTags) Has(key string) bool {
2939
_, ok := t.values[key]
3040
return ok
3141
}
3242

33-
// Values returns a map of key to values.
34-
// Do not modify the underlying map, please use Set instead.
35-
func (t *Tags) Values() map[string]interface{} {
43+
func (t *mapTags) Values() map[string]interface{} {
3644
return t.values
3745
}
3846

47+
type noopTags struct{}
48+
49+
func (t *noopTags) Set(key string, value interface{}) Tags {
50+
return t
51+
}
52+
53+
func (t *noopTags) Has(key string) bool {
54+
return false
55+
}
56+
57+
func (t *noopTags) Values() map[string]interface{} {
58+
return nil
59+
}
60+
3961
// Extracts returns a pre-existing Tags object in the Context.
4062
// If the context wasn't set in a tag interceptor, a no-op Tag storage is returned that will *not* be propagated in context.
41-
func Extract(ctx context.Context) *Tags {
42-
t, ok := ctx.Value(ctxMarkerKey).(*Tags)
63+
func Extract(ctx context.Context) Tags {
64+
t, ok := ctx.Value(ctxMarkerKey).(Tags)
4365
if !ok {
44-
return &Tags{values: make(map[string]interface{})}
66+
return NoopTags
4567
}
4668

4769
return t
4870
}
4971

50-
func setInContext(ctx context.Context, tags *Tags) context.Context {
72+
func setInContext(ctx context.Context, tags Tags) context.Context {
5173
return context.WithValue(ctx, ctxMarkerKey, tags)
5274
}
75+
76+
func newTags() Tags {
77+
return &mapTags{values: make(map[string]interface{})}
78+
}

tags/interceptors.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func (w *wrappedStream) RecvMsg(m interface{}) error {
6666
}
6767

6868
func newTagsForCtx(ctx context.Context) context.Context {
69-
t := Extract(ctx) // will allocate a new one if it didn't exist.
69+
t := newTags()
7070
if peer, ok := peer.FromContext(ctx); ok {
7171
t.Set("peer.address", peer.Addr.String())
7272
}

tracing/opentracing/id_extract.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ const (
2222
// Most tracers have them encoded as keys with 'traceid' and 'spanid':
2323
// https://github.com/openzipkin/zipkin-go-opentracing/blob/594640b9ef7e5c994e8d9499359d693c032d738c/propagation_ot.go#L29
2424
// https://github.com/opentracing/basictracer-go/blob/1b32af207119a14b1b231d451df3ed04a72efebf/propagation_ot.go#L26
25-
func hackyInjectOpentracingIdsToTags(span opentracing.Span, tags *grpc_ctxtags.Tags) {
25+
func hackyInjectOpentracingIdsToTags(span opentracing.Span, tags grpc_ctxtags.Tags) {
2626
if err := span.Tracer().Inject(span.Context(), opentracing.HTTPHeaders, &hackyTagsCarrier{tags}); err != nil {
2727
grpclog.Printf("grpc_opentracing: failed extracting trace info into ctx %v", err)
2828
}
2929
}
3030

3131
// hackyTagsCarrier is a really hacky way of
3232
type hackyTagsCarrier struct {
33-
*grpc_ctxtags.Tags
33+
grpc_ctxtags.Tags
3434
}
3535

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

0 commit comments

Comments
 (0)