github.com/erda-project/erda-infra@v1.0.9/pkg/trace/inject/context/context.go (about) 1 // Copyright (c) 2021 Terminus, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package hook 16 17 import ( 18 "context" 19 "runtime" 20 "sync" 21 22 "github.com/go-eden/routine" 23 "go.opentelemetry.io/otel/trace" 24 ) 25 26 const bucketsSize = 128 27 const armSystem = "arm64" 28 29 type ( 30 contextBucket struct { 31 lock sync.RWMutex 32 data map[int64]context.Context 33 } 34 contextBuckets struct { 35 buckets [bucketsSize]*contextBucket 36 } 37 ) 38 39 var goroutineContext contextBuckets 40 41 func init() { 42 for i := range goroutineContext.buckets { 43 goroutineContext.buckets[i] = &contextBucket{ 44 data: make(map[int64]context.Context), 45 } 46 } 47 } 48 49 // GetContext . 50 func GetContext() context.Context { 51 if runtime.GOARCH == armSystem { 52 return context.Background() 53 } 54 goid := routine.Goid() 55 idx := goid % bucketsSize 56 bucket := goroutineContext.buckets[idx] 57 bucket.lock.RLock() 58 ctx := bucket.data[goid] 59 bucket.lock.RUnlock() 60 return ctx 61 } 62 63 // SetContext . 64 func SetContext(ctx context.Context) { 65 if runtime.GOARCH == armSystem { 66 return 67 } 68 goid := routine.Goid() 69 idx := goid % bucketsSize 70 bucket := goroutineContext.buckets[idx] 71 bucket.lock.Lock() 72 defer bucket.lock.Unlock() 73 bucket.data[goid] = ctx 74 } 75 76 // ClearContext . 77 func ClearContext() { 78 if runtime.GOARCH == armSystem { 79 return 80 } 81 goid := routine.Goid() 82 idx := goid % bucketsSize 83 bucket := goroutineContext.buckets[idx] 84 bucket.lock.Lock() 85 defer bucket.lock.Unlock() 86 delete(bucket.data, goid) 87 } 88 89 // RunWithContext . 90 func RunWithContext(ctx context.Context, fn func(ctx context.Context)) { 91 SetContext(ctx) 92 defer ClearContext() 93 fn(ctx) 94 } 95 96 // ContextWithSpan . 97 func ContextWithSpan(ctx context.Context) context.Context { 98 if span := trace.SpanFromContext(ctx); !span.SpanContext().IsValid() { 99 pctx := GetContext() 100 if pctx != nil { 101 if span := trace.SpanFromContext(pctx); span.SpanContext().IsValid() { 102 ctx = trace.ContextWithSpan(ctx, span) 103 } 104 } 105 } 106 return ctx 107 }