Skip to content

Commit d36315f

Browse files
Optimize the slot chain execution mechanism (#264)
* Support resource level slot chain to reduce unnecessary slot execution * Support register the global singleton slot for all resource * Make api.WithSlotChain have the highest priority Co-authored-by: louyuting <[email protected]>
1 parent b93704d commit d36315f

22 files changed

+469
-64
lines changed

api/api.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"sync"
55

66
"github.com/alibaba/sentinel-golang/core/base"
7+
"github.com/alibaba/sentinel-golang/core/misc"
78
)
89

910
var entryOptsPool = sync.Pool{
@@ -123,12 +124,15 @@ func Entry(resource string, opts ...EntryOption) (*base.SentinelEntry, *base.Blo
123124
entryOptsPool.Put(options)
124125
}()
125126

126-
options.slotChain = globalSlotChain
127-
128127
for _, opt := range opts {
129128
opt(options)
130129
}
131-
130+
if options.slotChain == nil {
131+
options.slotChain = misc.GetResourceSlotChain(resource)
132+
if options.slotChain == nil {
133+
options.slotChain = globalSlotChain
134+
}
135+
}
132136
return entry(resource, options)
133137
}
134138

api/api_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ type prepareSlotMock struct {
1212
mock.Mock
1313
}
1414

15+
func (m *prepareSlotMock) Name() string {
16+
return "mock-sentinel-prepare-slot"
17+
}
18+
1519
func (m *prepareSlotMock) Prepare(ctx *base.EntryContext) {
1620
m.Called(ctx)
1721
return
@@ -21,6 +25,10 @@ type mockRuleCheckSlot1 struct {
2125
mock.Mock
2226
}
2327

28+
func (m *mockRuleCheckSlot1) Name() string {
29+
return "mock-sentinel-rule-check-slot1"
30+
}
31+
2432
func (m *mockRuleCheckSlot1) Check(ctx *base.EntryContext) *base.TokenResult {
2533
arg := m.Called(ctx)
2634
return arg.Get(0).(*base.TokenResult)
@@ -30,6 +38,10 @@ type mockRuleCheckSlot2 struct {
3038
mock.Mock
3139
}
3240

41+
func (m *mockRuleCheckSlot2) Name() string {
42+
return "mock-sentinel-rule-check-slot2"
43+
}
44+
3345
func (m *mockRuleCheckSlot2) Check(ctx *base.EntryContext) *base.TokenResult {
3446
arg := m.Called(ctx)
3547
return arg.Get(0).(*base.TokenResult)
@@ -39,6 +51,10 @@ type statisticSlotMock struct {
3951
mock.Mock
4052
}
4153

54+
func (m *statisticSlotMock) Name() string {
55+
return "mock-sentinel-stat-check-slot"
56+
}
57+
4258
func (m *statisticSlotMock) OnEntryPassed(ctx *base.EntryContext) {
4359
m.Called(ctx)
4460
return

api/slot_chain.go

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,37 +7,33 @@ import (
77
"github.com/alibaba/sentinel-golang/core/hotspot"
88
"github.com/alibaba/sentinel-golang/core/isolation"
99
"github.com/alibaba/sentinel-golang/core/log"
10+
"github.com/alibaba/sentinel-golang/core/misc"
1011
"github.com/alibaba/sentinel-golang/core/stat"
1112
"github.com/alibaba/sentinel-golang/core/system"
1213
)
1314

1415
var globalSlotChain = BuildDefaultSlotChain()
1516

16-
// SetSlotChain replaces current slot chain with the given one.
17-
// Note that this operation is not thread-safe, so it should be
18-
// called when pre-initializing Sentinel.
19-
func SetSlotChain(chain *base.SlotChain) {
20-
if chain != nil {
21-
globalSlotChain = chain
22-
}
23-
}
24-
2517
func GlobalSlotChain() *base.SlotChain {
2618
return globalSlotChain
2719
}
2820

2921
func BuildDefaultSlotChain() *base.SlotChain {
3022
sc := base.NewSlotChain()
31-
sc.AddStatPrepareSlotLast(&stat.ResourceNodePrepareSlot{})
32-
sc.AddRuleCheckSlotLast(&system.AdaptiveSlot{})
33-
sc.AddRuleCheckSlotLast(&flow.Slot{})
34-
sc.AddRuleCheckSlotLast(&isolation.Slot{})
35-
sc.AddRuleCheckSlotLast(&circuitbreaker.Slot{})
36-
sc.AddRuleCheckSlotLast(&hotspot.Slot{})
37-
sc.AddStatSlotLast(&stat.Slot{})
38-
sc.AddStatSlotLast(&log.Slot{})
39-
sc.AddStatSlotLast(&circuitbreaker.MetricStatSlot{})
40-
sc.AddStatSlotLast(&hotspot.ConcurrencyStatSlot{})
41-
sc.AddStatSlotLast(&flow.StandaloneStatSlot{})
23+
sc.AddStatPrepareSlotLast(stat.DefaultResourceNodePrepareSlot)
24+
25+
sc.AddRuleCheckSlotLast(system.DefaultAdaptiveSlot)
26+
sc.AddRuleCheckSlotLast(flow.DefaultSlot)
27+
sc.AddRuleCheckSlotLast(isolation.DefaultSlot)
28+
sc.AddRuleCheckSlotLast(circuitbreaker.DefaultSlot)
29+
sc.AddRuleCheckSlotLast(hotspot.DefaultSlot)
30+
31+
sc.AddStatSlotLast(stat.DefaultSlot)
32+
sc.AddStatSlotLast(log.DefaultSlot)
33+
sc.AddStatSlotLast(circuitbreaker.DefaultMetricStatSlot)
34+
sc.AddStatSlotLast(hotspot.DefaultConcurrencyStatSlot)
35+
sc.AddStatSlotLast(flow.DefaultStandaloneStatSlot)
36+
37+
misc.RegisterCustomGlobalSlotsToSc(sc)
4238
return sc
4339
}

core/base/slot_chain.go

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@ import (
88
"github.com/pkg/errors"
99
)
1010

11+
type NamedSlot interface {
12+
// Name returns its slot name which should not be the same as other slots.
13+
Name() string
14+
}
15+
1116
// StatPrepareSlot is responsible for some preparation before statistic
1217
// For example: init structure and so on
1318
type StatPrepareSlot interface {
19+
NamedSlot
1420
// Prepare function do some initialization
1521
// Such as: init statistic structure、node and etc
1622
// The result of preparing would store in EntryContext
@@ -22,6 +28,7 @@ type StatPrepareSlot interface {
2228
// RuleCheckSlot is rule based checking strategy
2329
// All checking rule must implement this interface.
2430
type RuleCheckSlot interface {
31+
NamedSlot
2532
// Check function do some validation
2633
// It can break off the slot pipeline
2734
// Each TokenResult will return check result
@@ -32,6 +39,7 @@ type RuleCheckSlot interface {
3239
// StatSlot is responsible for counting all custom biz metrics.
3340
// StatSlot would not handle any panic, and pass up all panic to slot chain
3441
type StatSlot interface {
42+
NamedSlot
3543
// OnEntryPass function will be invoked when StatPrepareSlots and RuleCheckSlots execute pass
3644
// StatSlots will do some statistic logic, such as QPS、log、etc
3745
OnEntryPassed(ctx *EntryContext)
@@ -53,28 +61,32 @@ type SlotChain struct {
5361
ruleChecks []RuleCheckSlot
5462
stats []StatSlot
5563
// EntryContext Pool, used for reuse EntryContext object
56-
ctxPool sync.Pool
64+
ctxPool *sync.Pool
5765
}
5866

67+
var (
68+
ctxPool = &sync.Pool{
69+
New: func() interface{} {
70+
ctx := NewEmptyEntryContext()
71+
ctx.RuleCheckResult = NewTokenResultPass()
72+
ctx.Data = make(map[interface{}]interface{})
73+
ctx.Input = &SentinelInput{
74+
BatchCount: 1,
75+
Flag: 0,
76+
Args: make([]interface{}, 0),
77+
Attachments: make(map[interface{}]interface{}),
78+
}
79+
return ctx
80+
},
81+
}
82+
)
83+
5984
func NewSlotChain() *SlotChain {
6085
return &SlotChain{
6186
statPres: make([]StatPrepareSlot, 0, 5),
6287
ruleChecks: make([]RuleCheckSlot, 0, 5),
6388
stats: make([]StatSlot, 0, 5),
64-
ctxPool: sync.Pool{
65-
New: func() interface{} {
66-
ctx := NewEmptyEntryContext()
67-
ctx.RuleCheckResult = NewTokenResultPass()
68-
ctx.Data = make(map[interface{}]interface{})
69-
ctx.Input = &SentinelInput{
70-
BatchCount: 1,
71-
Flag: 0,
72-
Args: make([]interface{}, 0),
73-
Attachments: make(map[interface{}]interface{}),
74-
}
75-
return ctx
76-
},
77-
},
89+
ctxPool: ctxPool,
7890
}
7991
}
8092

@@ -92,6 +104,12 @@ func (sc *SlotChain) RefurbishContext(c *EntryContext) {
92104
}
93105
}
94106

107+
func (sc *SlotChain) RangeStatPrepareSlot(f func(slot StatPrepareSlot)) {
108+
for _, slot := range sc.statPres {
109+
f(slot)
110+
}
111+
}
112+
95113
func (sc *SlotChain) AddStatPrepareSlotFirst(s StatPrepareSlot) {
96114
ns := make([]StatPrepareSlot, 0, len(sc.statPres)+1)
97115
// add to first
@@ -103,6 +121,12 @@ func (sc *SlotChain) AddStatPrepareSlotLast(s StatPrepareSlot) {
103121
sc.statPres = append(sc.statPres, s)
104122
}
105123

124+
func (sc *SlotChain) RangeRuleCheckSlot(f func(slot RuleCheckSlot)) {
125+
for _, slot := range sc.ruleChecks {
126+
f(slot)
127+
}
128+
}
129+
106130
func (sc *SlotChain) AddRuleCheckSlotFirst(s RuleCheckSlot) {
107131
ns := make([]RuleCheckSlot, 0, len(sc.ruleChecks)+1)
108132
ns = append(ns, s)
@@ -113,6 +137,12 @@ func (sc *SlotChain) AddRuleCheckSlotLast(s RuleCheckSlot) {
113137
sc.ruleChecks = append(sc.ruleChecks, s)
114138
}
115139

140+
func (sc *SlotChain) RangeStatSlot(f func(slot StatSlot)) {
141+
for _, slot := range sc.stats {
142+
f(slot)
143+
}
144+
}
145+
116146
func (sc *SlotChain) AddStatSlotFirst(s StatSlot) {
117147
ns := make([]StatSlot, 0, len(sc.stats)+1)
118148
ns = append(ns, s)

0 commit comments

Comments
 (0)