Repository: cloudwego/hertz
Pull request #1031 (2023-12-17 06:58:58)

feat: optimize HandlerName && add setIndex
#### What type of PR is this?
feat
#### Check the PR title.
feat: optimize HandlerName && add setIndex

#### (Optional) Translate the PR title into Chinese.
- 增加 SetIndex 方法
- 保证 HandlerName 操作的并发安全


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/cloudwego/hertz/pull/1031?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Comparison is base [(`82f9bfa`)](https://app.codecov.io/gh/cloudwego/hertz/commit/82f9bfa7e68d6fd724a39350f3b517ec68ab54fc?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) 82.55% compared to head [(`f68a164`)](https://app.codecov.io/gh/cloudwego/hertz/pull/1031?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego) 82.61%.


<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##           develop    #1031      +/-   ##
===========================================
+ Coverage    82.55%   82.61%   +0.06%     
===========================================
  Files           98       98              
  Lines         9974     9980       +6     
===========================================
+ Hits          8234     8245      +11     
+ Misses        1244     1240       -4     
+ Partials       496      495       -1     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/cloudwego/hertz/pull/1031?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=cloudwego).

FGYFFFF: 请补充下 pr 的描述相关内容

Patch:
diff --git a/pkg/app/context.go b/pkg/app/context.go
index 4e2d4be..510c972 100644
--- a/pkg/app/context.go
+++ b/pkg/app/context.go
@@ -328,19 +328,71 @@ func (ctx *RequestContext) GetIndex() int8 {
 	return ctx.index
 }
 
+// SetIndex reset the handler's execution index
+// Disclaimer: You can loop yourself to deal with this, use wisely.
+func (ctx *RequestContext) SetIndex(index int8) {
+	ctx.index = index
+}
+
 type HandlerFunc func(c context.Context, ctx *RequestContext)
 
 // HandlersChain defines a HandlerFunc array.
 type HandlersChain []HandlerFunc
 
-var handlerNames = make(map[uintptr]string)
+type HandlerNameOperator interface {
+	SetHandlerName(handler HandlerFunc, name string)
+	GetHandlerName(handler HandlerFunc) string
+}
+
+func SetHandlerNameOperator(o HandlerNameOperator) {
+	inbuiltHandlerNameOperator = o
+}
+
+type inbuiltHandlerNameOperatorStruct struct {
+	handlerNames map[uintptr]string
+}
+
+func (o *inbuiltHandlerNameOperatorStruct) SetHandlerName(handler HandlerFunc, name string) {
+	o.handlerNames[getFuncAddr(handler)] = name
+}
+
+func (o *inbuiltHandlerNameOperatorStruct) GetHandlerName(handler HandlerFunc) string {
+	return o.handlerNames[getFuncAddr(handler)]
+}
+
+type concurrentHandlerNameOperatorStruct struct {
+	handlerNames map[uintptr]string
+	lock         sync.RWMutex
+}
+
+func (o *concurrentHandlerNameOperatorStruct) SetHandlerName(handler HandlerFunc, name string) {
+	o.lock.Lock()
+	defer o.lock.Unlock()
+	o.handlerNames[getFuncAddr(handler)] = name
+}
+
+func (o *concurrentHandlerNameOperatorStruct) GetHandlerName(handler HandlerFunc) string {
+	o.lock.RLock()
+	defer o.lock.RUnlock()
+	return o.handlerNames[getFuncAddr(handler)]
+}
+
+func SetConcurrentHandlerNameOperator() {
+	SetHandlerNameOperator(&concurrentHandlerNameOperatorStruct{handlerNames: map[uintptr]string{}})
+}
+
+func init() {
+	inbuiltHandlerNameOperator = &inbuiltHandlerNameOperatorStruct{handlerNames: map[uintptr]string{}}
+}
+
+var inbuiltHandlerNameOperator HandlerNameOperator
 
 func SetHandlerName(handler HandlerFunc, name string) {
-	handlerNames[getFuncAddr(handler)] = name
+	inbuiltHandlerNameOperator.SetHandlerName(handler, name)
 }
 
 func GetHandlerName(handler HandlerFunc) string {
-	return handlerNames[getFuncAddr(handler)]
+	return inbuiltHandlerNameOperator.GetHandlerName(handler)
 }
 
 func getFuncAddr(v interface{}) uintptr {


Test patch:
diff --git a/pkg/app/context_test.go b/pkg/app/context_test.go
index c065d48..85d686c 100644
--- a/pkg/app/context_test.go
+++ b/pkg/app/context_test.go
@@ -1344,16 +1344,44 @@ func TestGetWriter(t *testing.T) {
 func TestIndex(t *testing.T) {
 	ctx := NewContext(0)
 	ctx.ResetWithoutConn()
-	res := ctx.GetIndex()
 	exc := int8(-1)
+	res := ctx.GetIndex()
+	assert.DeepEqual(t, exc, res)
+	ctx.SetIndex(int8(1))
+	res = ctx.GetIndex()
+	exc = int8(1)
 	assert.DeepEqual(t, exc, res)
 }
 
+func TestConcurrentHandlerName(t *testing.T) {
+	SetConcurrentHandlerNameOperator()
+	defer SetHandlerNameOperator(&inbuiltHandlerNameOperatorStruct{handlerNames: map[uintptr]string{}})
+	h := func(c context.Context, ctx *RequestContext) {}
+	SetHandlerName(h, "test1")
+	for i := 0; i < 50; i++ {
+		go func() {
+			name := GetHandlerName(h)
+			assert.DeepEqual(t, "test1", name)
+		}()
+	}
+
+	time.Sleep(time.Second)
+
+	go func() {
+		SetHandlerName(h, "test2")
+	}()
+
+	time.Sleep(time.Second)
+
+	name := GetHandlerName(h)
+	assert.DeepEqual(t, "test2", name)
+}
+
 func TestHandlerName(t *testing.T) {
 	h := func(c context.Context, ctx *RequestContext) {}
-	SetHandlerName(h, "test")
+	SetHandlerName(h, "test1")
 	name := GetHandlerName(h)
-	assert.DeepEqual(t, "test", name)
+	assert.DeepEqual(t, "test1", name)
 }
 
 func TestHijack(t *testing.T) {
@@ -1644,3 +1672,23 @@ func TestRequestContext_VisitAll(t *testing.T) {
 			})
 	})
 }
+
+func BenchmarkInbuiltHandlerNameOperator(b *testing.B) {
+	for n := 0; n < b.N; n++ {
+		fn := func(c context.Context, ctx *RequestContext) {
+		}
+		SetHandlerName(fn, fmt.Sprintf("%d", n))
+		GetHandlerName(fn)
+	}
+}
+
+func BenchmarkConcurrentHandlerNameOperator(b *testing.B) {
+	SetConcurrentHandlerNameOperator()
+	defer SetHandlerNameOperator(&inbuiltHandlerNameOperatorStruct{handlerNames: map[uintptr]string{}})
+	for n := 0; n < b.N; n++ {
+		fn := func(c context.Context, ctx *RequestContext) {
+		}
+		SetHandlerName(fn, fmt.Sprintf("%d", n))
+		GetHandlerName(fn)
+	}
+}