Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/pingcap/kvproto v0.0.0-20260703015547-e800f9e5a427
github.com/pingcap/log v1.1.1-0.20221110025148-ca232912c9f3
github.com/prometheus/client_golang v1.20.5
github.com/prometheus/client_model v0.6.1
github.com/stretchr/testify v1.9.0
go.uber.org/goleak v1.1.11
go.uber.org/zap v1.24.0
Expand All @@ -30,7 +31,6 @@ require (
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
Expand Down
22 changes: 22 additions & 0 deletions client/resource_group/controller/global_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,7 @@ func (c *ResourceGroupsController) cleanUpResourceGroup() {
metrics.WriteByteCost.DeleteLabelValues(resourceGroupName, refundDirection)
metrics.KVCPUCost.DeleteLabelValues(resourceGroupName)
metrics.SQLCPUCost.DeleteLabelValues(resourceGroupName)
gc.metrics.deletePagingLabels(resourceGroupName)
return true
}
gc.inactive = true
Expand Down Expand Up @@ -823,6 +824,27 @@ func (c *ResourceGroupsController) GetResourceGroup(resourceGroupName string) (*
return gc.getMeta(), nil
}

// ResourceGroupRuntimeState describes generic local runtime signals derived
// from token bucket responses.
type ResourceGroupRuntimeState struct {
// HasLimitedBurst is true when the request-unit token bucket has a finite
// burst limit instead of unlimited burst.
HasLimitedBurst bool
}

// GetResourceGroupRuntimeState returns the resource group's local runtime
// state. The second return value is false when the controller has no usable
// local state for the group.
func (c *ResourceGroupsController) GetResourceGroupRuntimeState(resourceGroupName string) (ResourceGroupRuntimeState, bool) {
gc, ok := c.loadGroupController(resourceGroupName)
if !ok || gc.tombstone.Load() || !gc.initialRequestCompleted.Load() {
return ResourceGroupRuntimeState{}, false
}
return ResourceGroupRuntimeState{
HasLimitedBurst: !gc.burstable.Load(),
}, true
}

// ReportConsumption is used to report ru consumption directly.
//
// Currently, this interface is used to report the consumption for TiFlash MPP cost
Expand Down
90 changes: 90 additions & 0 deletions client/resource_group/controller/global_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,96 @@ func TestGetResourceGroup(t *testing.T) {
re.Nil(gc02)
}

func TestGetResourceGroupRuntimeState(t *testing.T) {
testCases := []struct {
name string
responseBurstLimit int64
sendResponse bool
resourceGroupName string
expectOK bool
expectResourceGroupRuntimeState ResourceGroupRuntimeState
}{
{
name: "unknown before first token response",
resourceGroupName: "test-group",
},
{
name: "unlimited response remains burstable",
responseBurstLimit: -1,
sendResponse: true,
resourceGroupName: "test-group",
expectOK: true,
},
{
name: "override limited burst from token response",
responseBurstLimit: 100,
sendResponse: true,
resourceGroupName: "test-group",
expectOK: true,
expectResourceGroupRuntimeState: ResourceGroupRuntimeState{
HasLimitedBurst: true,
},
},
{
name: "unknown resource group",
responseBurstLimit: 100,
sendResponse: true,
resourceGroupName: "unknown",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
re := require.New(t)

group := &rmpb.ResourceGroup{
Name: "test-group",
Mode: rmpb.GroupMode_RUMode,
RUSettings: &rmpb.GroupRequestUnitSettings{
RU: &rmpb.TokenBucket{
Settings: &rmpb.TokenLimitSettings{
FillRate: 1000,
BurstLimit: -1,
},
},
},
}
gc, err := newGroupCostController(group, 1001, DefaultRUConfig(), make(chan notifyMsg), make(chan *groupCostController))
re.NoError(err)

controller := &ResourceGroupsController{}
controller.groupsController.Store(group.Name, gc)

if tc.sendResponse {
controller.handleTokenBucketResponse([]*rmpb.TokenBucketResponse{
{
ResourceGroupName: group.Name,
GrantedRUTokens: []*rmpb.GrantedRUTokenBucket{
{
GrantedTokens: &rmpb.TokenBucket{
Settings: &rmpb.TokenLimitSettings{
FillRate: 1000,
BurstLimit: tc.responseBurstLimit,
},
Tokens: 1000,
},
},
},
},
})
// Mirror the main loop, which refreshes the derived state
// (e.g. burstable) after handling token bucket responses.
gc.updateRunState()
gc.updateAvgRequestResourcePerSec()
}

state, ok := controller.GetResourceGroupRuntimeState(tc.resourceGroupName)
re.Equal(tc.expectOK, ok)
re.Equal(tc.expectResourceGroupRuntimeState, state)
})
}
}

func TestTokenBucketsRequestWithKeyspaceID(t *testing.T) {
re := require.New(t)
ctx, cancel := context.WithCancel(context.Background())
Expand Down
Loading
Loading