Files
tidb/pkg/domain/ru_stats_test.go

173 lines
6.6 KiB
Go

// Copyright 2023 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package domain_test
import (
"context"
"testing"
"time"
rmpb "github.com/pingcap/kvproto/pkg/resource_manager"
"github.com/pingcap/tidb/pkg/domain"
"github.com/pingcap/tidb/pkg/infoschema"
"github.com/pingcap/tidb/pkg/meta/model"
pmodel "github.com/pingcap/tidb/pkg/parser/model"
"github.com/pingcap/tidb/pkg/testkit"
"github.com/stretchr/testify/require"
pd "github.com/tikv/pd/client"
)
func TestWriteRUStatistics(t *testing.T) {
tz, _ := time.LoadLocation("Asia/Shanghai")
testWriteRUStatisticsTz(t, tz)
// test with DST timezone.
tz, _ = time.LoadLocation("Australia/Lord_Howe")
testWriteRUStatisticsTz(t, tz)
testWriteRUStatisticsTz(t, time.Local)
testWriteRUStatisticsTz(t, time.UTC)
}
func testWriteRUStatisticsTz(t *testing.T, tz *time.Location) {
store, dom := testkit.CreateMockStoreAndDomain(t)
tk := newTestKit(t, store)
testRUWriter := domain.NewRUStatsWriter(dom)
testRMClient := &testRMClient{
groups: []*rmpb.ResourceGroup{
{
Name: "default",
RUStats: &rmpb.Consumption{
RRU: 200.0,
WRU: 150.0,
},
},
{
Name: "test",
RUStats: &rmpb.Consumption{
RRU: 100.0,
WRU: 50.0,
},
},
},
}
infoGroups := make(map[string]*model.ResourceGroupInfo, 2)
infoGroups["default"] = &model.ResourceGroupInfo{
ID: 1,
Name: pmodel.NewCIStr("default"),
}
infoGroups["test"] = &model.ResourceGroupInfo{
ID: 2,
Name: pmodel.NewCIStr("test"),
}
testInfo := &testInfoschema{
groups: infoGroups,
}
testInfoCache := infoschema.NewCache(nil, 1)
testInfoCache.Insert(testInfo, uint64(time.Now().Unix()))
testRUWriter.RMClient = testRMClient
testRUWriter.InfoCache = testInfoCache
tk.MustQuery("SELECT count(*) from mysql.request_unit_by_group").Check(testkit.Rows("0"))
testRUWriter.StartTime = time.Date(2023, 12, 26, 0, 0, 1, 0, tz)
require.NoError(t, testRUWriter.DoWriteRUStatistics(context.Background()))
tk.MustQuery("SELECT resource_group, total_ru from mysql.request_unit_by_group").Check(testkit.Rows("default 350", "test 150"))
// after 1 day, only 1 group has delta ru.
testRMClient.groups[1].RUStats.RRU = 500
testRUWriter.StartTime = time.Date(2023, 12, 27, 0, 0, 1, 0, tz)
require.NoError(t, testRUWriter.DoWriteRUStatistics(context.Background()))
tk.MustQuery("SELECT resource_group, total_ru from mysql.request_unit_by_group where end_time = '2023-12-27'").Check(testkit.Rows("test 400"))
// test after 1 day with 0 delta ru, no data inserted.
testRUWriter.StartTime = time.Date(2023, 12, 28, 0, 0, 1, 0, tz)
require.NoError(t, testRUWriter.DoWriteRUStatistics(context.Background()))
tk.MustQuery("SELECT count(*) from mysql.request_unit_by_group where end_time = '2023-12-28'").Check(testkit.Rows("0"))
testRUWriter.StartTime = time.Date(2023, 12, 29, 0, 0, 0, 0, tz)
testRMClient.groups[0].RUStats.WRU = 200
require.NoError(t, testRUWriter.DoWriteRUStatistics(context.Background()))
tk.MustQuery("SELECT resource_group, total_ru from mysql.request_unit_by_group where end_time = '2023-12-29'").Check(testkit.Rows("default 50"))
// after less than 1 day, even if ru changes, no new rows inserted.
// This is to test after restart, no unexpected data are inserted.
testRMClient.groups[0].RUStats.RRU = 1000
testRMClient.groups[1].RUStats.WRU = 2000
testRUWriter.StartTime = time.Date(2023, 12, 29, 1, 0, 0, 0, tz)
require.NoError(t, testRUWriter.DoWriteRUStatistics(context.Background()))
tk.MustQuery("SELECT resource_group, total_ru from mysql.request_unit_by_group where end_time = '2023-12-29'").Check(testkit.Rows("default 50"))
// after 61 days, old record should be GCed.
testRUWriter.StartTime = time.Date(2023, 12, 26, 0, 0, 0, 0, tz).Add(92 * 24 * time.Hour)
tk.MustQuery("SELECT count(*) from mysql.request_unit_by_group where end_time = '2023-12-26'").Check(testkit.Rows("2"))
require.NoError(t, testRUWriter.GCOutdatedRecords(testRUWriter.StartTime))
tk.MustQuery("SELECT count(*) from mysql.request_unit_by_group where end_time = '2023-12-26'").Check(testkit.Rows("0"))
tk.MustQuery("SELECT count(*) from mysql.request_unit_by_group where end_time = '2023-12-27'").Check(testkit.Rows("1"))
}
type testRMClient struct {
pd.ResourceManagerClient
groups []*rmpb.ResourceGroup
}
func (c *testRMClient) ListResourceGroups(ctx context.Context, opts ...pd.GetResourceGroupOption) ([]*rmpb.ResourceGroup, error) {
return c.groups, nil
}
type testInfoschema struct {
infoschema.InfoSchema
groups map[string]*model.ResourceGroupInfo
}
func (is *testInfoschema) ResourceGroupByName(name pmodel.CIStr) (*model.ResourceGroupInfo, bool) {
g, ok := is.groups[name.L]
return g, ok
}
func (is *testInfoschema) SchemaMetaVersion() int64 {
return 1
}
func TestGetLastExpectedTime(t *testing.T) {
tz, _ := time.LoadLocation("Asia/Shanghai")
testGetLastExpectedTimeTz(t, tz)
// test with DST affected timezone.
tz, _ = time.LoadLocation("Australia/Lord_Howe")
testGetLastExpectedTimeTz(t, tz)
testGetLastExpectedTimeTz(t, time.Local)
}
func testGetLastExpectedTimeTz(t *testing.T, tz *time.Location) {
// 2023-12-28 10:46:23.000
now := time.Date(2023, 12, 28, 10, 46, 23, 0, tz)
newTime := func(hour, minute int) time.Time {
return time.Date(2023, 12, 28, hour, minute, 0, 0, tz)
}
require.Equal(t, domain.GetLastExpectedTimeTZ(now, 5*time.Minute, tz), newTime(10, 45))
require.Equal(t, domain.GetLastExpectedTimeTZ(time.Date(2023, 12, 28, 10, 45, 0, 0, tz), 5*time.Minute, tz), newTime(10, 45))
require.Equal(t, domain.GetLastExpectedTimeTZ(now, 10*time.Minute, tz), newTime(10, 40))
require.Equal(t, domain.GetLastExpectedTimeTZ(now, 30*time.Minute, tz), newTime(10, 30))
require.Equal(t, domain.GetLastExpectedTimeTZ(now, time.Hour, tz), newTime(10, 0))
require.Equal(t, domain.GetLastExpectedTimeTZ(now, 3*time.Hour, tz), newTime(9, 0))
require.Equal(t, domain.GetLastExpectedTimeTZ(now, 4*time.Hour, tz), newTime(8, 0))
require.Equal(t, domain.GetLastExpectedTimeTZ(now, 12*time.Hour, tz), newTime(0, 0))
require.Equal(t, domain.GetLastExpectedTimeTZ(now, 24*time.Hour, tz), newTime(0, 0))
require.Equal(t, domain.GetLastExpectedTimeTZ(time.Date(2023, 12, 28, 0, 0, 0, 0, tz), 24*time.Hour, tz), newTime(0, 0))
}