From ec60369299983d7677c1fa2544d71e5f54335e7d Mon Sep 17 00:00:00 2001 From: D3Hunter Date: Tue, 22 Aug 2023 11:15:33 +0800 Subject: [PATCH 1/4] import into: split real-tikv test (#46299) ref pingcap/tidb#42930 --- Makefile | 21 +++++ .../realtikvtest/importintotest2/BUILD.bazel | 22 +++++ .../importintotest2/dummy_test.go | 19 ++++ .../realtikvtest/importintotest2/main_test.go | 93 +++++++++++++++++++ .../realtikvtest/importintotest3/BUILD.bazel | 22 +++++ .../importintotest3/dummy_test.go | 19 ++++ .../realtikvtest/importintotest3/main_test.go | 93 +++++++++++++++++++ .../realtikvtest/importintotest4/BUILD.bazel | 22 +++++ .../importintotest4/dummy_test.go | 19 ++++ .../realtikvtest/importintotest4/main_test.go | 93 +++++++++++++++++++ 10 files changed, 423 insertions(+) create mode 100644 tests/realtikvtest/importintotest2/BUILD.bazel create mode 100644 tests/realtikvtest/importintotest2/dummy_test.go create mode 100644 tests/realtikvtest/importintotest2/main_test.go create mode 100644 tests/realtikvtest/importintotest3/BUILD.bazel create mode 100644 tests/realtikvtest/importintotest3/dummy_test.go create mode 100644 tests/realtikvtest/importintotest3/main_test.go create mode 100644 tests/realtikvtest/importintotest4/BUILD.bazel create mode 100644 tests/realtikvtest/importintotest4/dummy_test.go create mode 100644 tests/realtikvtest/importintotest4/main_test.go diff --git a/Makefile b/Makefile index 82959c269663c..81348bfa3c8cb 100644 --- a/Makefile +++ b/Makefile @@ -564,6 +564,27 @@ bazel_importintotest: failpoint-enable bazel_ci_simple_prepare -- //tests/realtikvtest/importintotest/... ./build/jenkins_collect_coverage.sh +# on timeout, bazel won't print log sometimes, so we use --test_output=all to print log always +bazel_importintotest2: failpoint-enable bazel_ci_simple_prepare + bazel $(BAZEL_GLOBAL_CONFIG) coverage $(BAZEL_CMD_CONFIG) --test_output=all --test_arg=-with-real-tikv --define gotags=deadlock,intest \ + --@io_bazel_rules_go//go/config:cover_format=go_cover \ + -- //tests/realtikvtest/importintotest2/... + ./build/jenkins_collect_coverage.sh + +# on timeout, bazel won't print log sometimes, so we use --test_output=all to print log always +bazel_importintotest3: failpoint-enable bazel_ci_simple_prepare + bazel $(BAZEL_GLOBAL_CONFIG) coverage $(BAZEL_CMD_CONFIG) --test_output=all --test_arg=-with-real-tikv --define gotags=deadlock,intest \ + --@io_bazel_rules_go//go/config:cover_format=go_cover \ + -- //tests/realtikvtest/importintotest3/... + ./build/jenkins_collect_coverage.sh + +# on timeout, bazel won't print log sometimes, so we use --test_output=all to print log always +bazel_importintotest4: failpoint-enable bazel_ci_simple_prepare + bazel $(BAZEL_GLOBAL_CONFIG) coverage $(BAZEL_CMD_CONFIG) --test_output=all --test_arg=-with-real-tikv --define gotags=deadlock,intest \ + --@io_bazel_rules_go//go/config:cover_format=go_cover \ + -- //tests/realtikvtest/importintotest4/... + ./build/jenkins_collect_coverage.sh + bazel_lint: bazel_prepare bazel build //... --//build:with_nogo_flag=true diff --git a/tests/realtikvtest/importintotest2/BUILD.bazel b/tests/realtikvtest/importintotest2/BUILD.bazel new file mode 100644 index 0000000000000..000264e402a9d --- /dev/null +++ b/tests/realtikvtest/importintotest2/BUILD.bazel @@ -0,0 +1,22 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_test") + +go_test( + name = "importintotest2_test", + timeout = "moderate", + srcs = [ + "dummy_test.go", + "main_test.go", + ], + flaky = True, + race = "on", + deps = [ + "//config", + "//kv", + "//testkit", + "//tests/realtikvtest", + "@com_github_fsouza_fake_gcs_server//fakestorage", + "@com_github_pingcap_failpoint//:failpoint", + "@com_github_stretchr_testify//require", + "@com_github_stretchr_testify//suite", + ], +) diff --git a/tests/realtikvtest/importintotest2/dummy_test.go b/tests/realtikvtest/importintotest2/dummy_test.go new file mode 100644 index 0000000000000..de58a6c9a8323 --- /dev/null +++ b/tests/realtikvtest/importintotest2/dummy_test.go @@ -0,0 +1,19 @@ +// 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 importintotest + +func (s *mockGCSSuite) TestDummy() { + s.True(true, gcsEndpoint) +} diff --git a/tests/realtikvtest/importintotest2/main_test.go b/tests/realtikvtest/importintotest2/main_test.go new file mode 100644 index 0000000000000..07c466b298680 --- /dev/null +++ b/tests/realtikvtest/importintotest2/main_test.go @@ -0,0 +1,93 @@ +// 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 importintotest + +import ( + "fmt" + "testing" + + "github.com/fsouza/fake-gcs-server/fakestorage" + "github.com/pingcap/failpoint" + "github.com/pingcap/tidb/config" + "github.com/pingcap/tidb/kv" + "github.com/pingcap/tidb/testkit" + "github.com/pingcap/tidb/tests/realtikvtest" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +type mockGCSSuite struct { + suite.Suite + + server *fakestorage.Server + store kv.Storage + tk *testkit.TestKit +} + +var ( + gcsHost = "127.0.0.1" + gcsPort = uint16(4443) + // for fake gcs server, we must use this endpoint format + // NOTE: must end with '/' + gcsEndpointFormat = "http://%s:%d/storage/v1/" + gcsEndpoint = fmt.Sprintf(gcsEndpointFormat, gcsHost, gcsPort) +) + +func TestLoadRemote(t *testing.T) { + suite.Run(t, &mockGCSSuite{}) +} + +func (s *mockGCSSuite) SetupSuite() { + s.Require().True(*realtikvtest.WithRealTiKV) + var err error + opt := fakestorage.Options{ + Scheme: "http", + Host: gcsHost, + Port: gcsPort, + PublicHost: gcsHost, + } + s.server, err = fakestorage.NewServerWithOptions(opt) + s.Require().NoError(err) + s.store = realtikvtest.CreateMockStoreAndSetup(s.T()) + s.tk = testkit.NewTestKit(s.T(), s.store) +} + +func (s *mockGCSSuite) TearDownSuite() { + s.server.Stop() +} + +func (s *mockGCSSuite) enableFailpoint(path, term string) { + require.NoError(s.T(), failpoint.Enable(path, term)) + s.T().Cleanup(func() { + _ = failpoint.Disable(path) + }) +} + +func (s *mockGCSSuite) cleanupSysTables() { + s.tk.MustExec("delete from mysql.tidb_import_jobs") + s.tk.MustExec("delete from mysql.tidb_global_task") + s.tk.MustExec("delete from mysql.tidb_background_subtask") +} + +func init() { + // need a real PD + config.UpdateGlobal(func(conf *config.Config) { + conf.Path = "127.0.0.1:2379" + }) +} + +func TestMain(m *testing.M) { + realtikvtest.RunTestMain(m) +} diff --git a/tests/realtikvtest/importintotest3/BUILD.bazel b/tests/realtikvtest/importintotest3/BUILD.bazel new file mode 100644 index 0000000000000..c7f783d02987e --- /dev/null +++ b/tests/realtikvtest/importintotest3/BUILD.bazel @@ -0,0 +1,22 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_test") + +go_test( + name = "importintotest3_test", + timeout = "moderate", + srcs = [ + "dummy_test.go", + "main_test.go", + ], + flaky = True, + race = "on", + deps = [ + "//config", + "//kv", + "//testkit", + "//tests/realtikvtest", + "@com_github_fsouza_fake_gcs_server//fakestorage", + "@com_github_pingcap_failpoint//:failpoint", + "@com_github_stretchr_testify//require", + "@com_github_stretchr_testify//suite", + ], +) diff --git a/tests/realtikvtest/importintotest3/dummy_test.go b/tests/realtikvtest/importintotest3/dummy_test.go new file mode 100644 index 0000000000000..de58a6c9a8323 --- /dev/null +++ b/tests/realtikvtest/importintotest3/dummy_test.go @@ -0,0 +1,19 @@ +// 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 importintotest + +func (s *mockGCSSuite) TestDummy() { + s.True(true, gcsEndpoint) +} diff --git a/tests/realtikvtest/importintotest3/main_test.go b/tests/realtikvtest/importintotest3/main_test.go new file mode 100644 index 0000000000000..07c466b298680 --- /dev/null +++ b/tests/realtikvtest/importintotest3/main_test.go @@ -0,0 +1,93 @@ +// 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 importintotest + +import ( + "fmt" + "testing" + + "github.com/fsouza/fake-gcs-server/fakestorage" + "github.com/pingcap/failpoint" + "github.com/pingcap/tidb/config" + "github.com/pingcap/tidb/kv" + "github.com/pingcap/tidb/testkit" + "github.com/pingcap/tidb/tests/realtikvtest" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +type mockGCSSuite struct { + suite.Suite + + server *fakestorage.Server + store kv.Storage + tk *testkit.TestKit +} + +var ( + gcsHost = "127.0.0.1" + gcsPort = uint16(4443) + // for fake gcs server, we must use this endpoint format + // NOTE: must end with '/' + gcsEndpointFormat = "http://%s:%d/storage/v1/" + gcsEndpoint = fmt.Sprintf(gcsEndpointFormat, gcsHost, gcsPort) +) + +func TestLoadRemote(t *testing.T) { + suite.Run(t, &mockGCSSuite{}) +} + +func (s *mockGCSSuite) SetupSuite() { + s.Require().True(*realtikvtest.WithRealTiKV) + var err error + opt := fakestorage.Options{ + Scheme: "http", + Host: gcsHost, + Port: gcsPort, + PublicHost: gcsHost, + } + s.server, err = fakestorage.NewServerWithOptions(opt) + s.Require().NoError(err) + s.store = realtikvtest.CreateMockStoreAndSetup(s.T()) + s.tk = testkit.NewTestKit(s.T(), s.store) +} + +func (s *mockGCSSuite) TearDownSuite() { + s.server.Stop() +} + +func (s *mockGCSSuite) enableFailpoint(path, term string) { + require.NoError(s.T(), failpoint.Enable(path, term)) + s.T().Cleanup(func() { + _ = failpoint.Disable(path) + }) +} + +func (s *mockGCSSuite) cleanupSysTables() { + s.tk.MustExec("delete from mysql.tidb_import_jobs") + s.tk.MustExec("delete from mysql.tidb_global_task") + s.tk.MustExec("delete from mysql.tidb_background_subtask") +} + +func init() { + // need a real PD + config.UpdateGlobal(func(conf *config.Config) { + conf.Path = "127.0.0.1:2379" + }) +} + +func TestMain(m *testing.M) { + realtikvtest.RunTestMain(m) +} diff --git a/tests/realtikvtest/importintotest4/BUILD.bazel b/tests/realtikvtest/importintotest4/BUILD.bazel new file mode 100644 index 0000000000000..4a8595bf816eb --- /dev/null +++ b/tests/realtikvtest/importintotest4/BUILD.bazel @@ -0,0 +1,22 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_test") + +go_test( + name = "importintotest4_test", + timeout = "moderate", + srcs = [ + "dummy_test.go", + "main_test.go", + ], + flaky = True, + race = "on", + deps = [ + "//config", + "//kv", + "//testkit", + "//tests/realtikvtest", + "@com_github_fsouza_fake_gcs_server//fakestorage", + "@com_github_pingcap_failpoint//:failpoint", + "@com_github_stretchr_testify//require", + "@com_github_stretchr_testify//suite", + ], +) diff --git a/tests/realtikvtest/importintotest4/dummy_test.go b/tests/realtikvtest/importintotest4/dummy_test.go new file mode 100644 index 0000000000000..de58a6c9a8323 --- /dev/null +++ b/tests/realtikvtest/importintotest4/dummy_test.go @@ -0,0 +1,19 @@ +// 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 importintotest + +func (s *mockGCSSuite) TestDummy() { + s.True(true, gcsEndpoint) +} diff --git a/tests/realtikvtest/importintotest4/main_test.go b/tests/realtikvtest/importintotest4/main_test.go new file mode 100644 index 0000000000000..07c466b298680 --- /dev/null +++ b/tests/realtikvtest/importintotest4/main_test.go @@ -0,0 +1,93 @@ +// 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 importintotest + +import ( + "fmt" + "testing" + + "github.com/fsouza/fake-gcs-server/fakestorage" + "github.com/pingcap/failpoint" + "github.com/pingcap/tidb/config" + "github.com/pingcap/tidb/kv" + "github.com/pingcap/tidb/testkit" + "github.com/pingcap/tidb/tests/realtikvtest" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +type mockGCSSuite struct { + suite.Suite + + server *fakestorage.Server + store kv.Storage + tk *testkit.TestKit +} + +var ( + gcsHost = "127.0.0.1" + gcsPort = uint16(4443) + // for fake gcs server, we must use this endpoint format + // NOTE: must end with '/' + gcsEndpointFormat = "http://%s:%d/storage/v1/" + gcsEndpoint = fmt.Sprintf(gcsEndpointFormat, gcsHost, gcsPort) +) + +func TestLoadRemote(t *testing.T) { + suite.Run(t, &mockGCSSuite{}) +} + +func (s *mockGCSSuite) SetupSuite() { + s.Require().True(*realtikvtest.WithRealTiKV) + var err error + opt := fakestorage.Options{ + Scheme: "http", + Host: gcsHost, + Port: gcsPort, + PublicHost: gcsHost, + } + s.server, err = fakestorage.NewServerWithOptions(opt) + s.Require().NoError(err) + s.store = realtikvtest.CreateMockStoreAndSetup(s.T()) + s.tk = testkit.NewTestKit(s.T(), s.store) +} + +func (s *mockGCSSuite) TearDownSuite() { + s.server.Stop() +} + +func (s *mockGCSSuite) enableFailpoint(path, term string) { + require.NoError(s.T(), failpoint.Enable(path, term)) + s.T().Cleanup(func() { + _ = failpoint.Disable(path) + }) +} + +func (s *mockGCSSuite) cleanupSysTables() { + s.tk.MustExec("delete from mysql.tidb_import_jobs") + s.tk.MustExec("delete from mysql.tidb_global_task") + s.tk.MustExec("delete from mysql.tidb_background_subtask") +} + +func init() { + // need a real PD + config.UpdateGlobal(func(conf *config.Config) { + conf.Path = "127.0.0.1:2379" + }) +} + +func TestMain(m *testing.M) { + realtikvtest.RunTestMain(m) +} From 7e476a502759530e42130d9074230c4f79a15811 Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Tue, 22 Aug 2023 11:56:04 +0800 Subject: [PATCH 2/4] *: use std/slices to replace exp/slices (#46292) ref pingcap/tidb#45933 --- br/pkg/lightning/backend/external/BUILD.bazel | 1 - .../lightning/backend/external/writer_test.go | 6 ++-- br/pkg/lightning/backend/local/BUILD.bazel | 1 - br/pkg/lightning/backend/local/disk_quota.go | 13 +++++--- br/pkg/lightning/importer/BUILD.bazel | 1 - br/pkg/lightning/importer/dup_detect_test.go | 2 +- ddl/ddl.go | 3 +- executor/executor.go | 11 ++++--- executor/index_lookup_merge_join.go | 24 ++++++++------ executor/sort.go | 31 ++++++++++++++++--- planner/core/BUILD.bazel | 1 - planner/core/optimizer.go | 23 +++++++------- planner/funcdep/BUILD.bazel | 1 - planner/funcdep/fast_int_set_test.go | 2 +- sessionctx/stmtctx/BUILD.bazel | 1 - sessionctx/stmtctx/stmtctx.go | 2 +- statistics/BUILD.bazel | 1 - statistics/cmsketch.go | 21 ++++++++----- statistics/merge_worker.go | 2 +- statistics/selectivity.go | 9 +++--- .../mockstore/unistore/cophandler/BUILD.bazel | 1 - .../mockstore/unistore/cophandler/analyze.go | 20 ++---------- store/pdtypes/BUILD.bazel | 1 - store/pdtypes/region_tree.go | 6 ++-- table/temptable/BUILD.bazel | 1 - table/temptable/main_test.go | 4 +-- 26 files changed, 102 insertions(+), 87 deletions(-) diff --git a/br/pkg/lightning/backend/external/BUILD.bazel b/br/pkg/lightning/backend/external/BUILD.bazel index 1bba1a5b87da7..fe3cfa189d067 100644 --- a/br/pkg/lightning/backend/external/BUILD.bazel +++ b/br/pkg/lightning/backend/external/BUILD.bazel @@ -55,7 +55,6 @@ go_test( "@com_github_pingcap_errors//:errors", "@com_github_stretchr_testify//require", "@org_golang_x_exp//rand", - "@org_golang_x_exp//slices", "@org_uber_go_atomic//:atomic", ], ) diff --git a/br/pkg/lightning/backend/external/writer_test.go b/br/pkg/lightning/backend/external/writer_test.go index d12afc3562ff9..3b3abce281190 100644 --- a/br/pkg/lightning/backend/external/writer_test.go +++ b/br/pkg/lightning/backend/external/writer_test.go @@ -19,6 +19,7 @@ import ( "context" "fmt" "io" + "slices" "strings" "testing" "time" @@ -28,7 +29,6 @@ import ( "github.com/pingcap/tidb/br/pkg/storage" "github.com/stretchr/testify/require" "golang.org/x/exp/rand" - "golang.org/x/exp/slices" ) func TestWriter(t *testing.T) { @@ -62,8 +62,8 @@ func TestWriter(t *testing.T) { _, err = writer.Close(ctx) require.NoError(t, err) - slices.SortFunc(kvs, func(i, j common.KvPair) bool { - return bytes.Compare(i.Key, j.Key) < 0 + slices.SortFunc(kvs, func(i, j common.KvPair) int { + return bytes.Compare(i.Key, j.Key) }) bufSize := rand.Intn(100) + 1 diff --git a/br/pkg/lightning/backend/local/BUILD.bazel b/br/pkg/lightning/backend/local/BUILD.bazel index 94867d6c7fd4f..feb9c00b7c2a8 100644 --- a/br/pkg/lightning/backend/local/BUILD.bazel +++ b/br/pkg/lightning/backend/local/BUILD.bazel @@ -86,7 +86,6 @@ go_library( "@org_golang_google_grpc//credentials/insecure", "@org_golang_google_grpc//keepalive", "@org_golang_google_grpc//status", - "@org_golang_x_exp//slices", "@org_golang_x_sync//errgroup", "@org_golang_x_time//rate", "@org_uber_go_atomic//:atomic", diff --git a/br/pkg/lightning/backend/local/disk_quota.go b/br/pkg/lightning/backend/local/disk_quota.go index 9f224665b7661..cc2a2f4708914 100644 --- a/br/pkg/lightning/backend/local/disk_quota.go +++ b/br/pkg/lightning/backend/local/disk_quota.go @@ -15,9 +15,11 @@ package local import ( + "cmp" + "slices" + "github.com/google/uuid" "github.com/pingcap/tidb/br/pkg/lightning/backend" - "golang.org/x/exp/slices" ) // DiskUsage is an interface to obtain the size occupied locally of all engines @@ -38,11 +40,14 @@ func CheckDiskQuota(mgr DiskUsage, quota int64) ( totalMemSize int64, ) { sizes := mgr.EngineFileSizes() - slices.SortFunc(sizes, func(i, j backend.EngineFileSize) bool { + slices.SortFunc(sizes, func(i, j backend.EngineFileSize) int { if i.IsImporting != j.IsImporting { - return i.IsImporting + if i.IsImporting { + return -1 + } + return 1 } - return i.DiskSize+i.MemSize < j.DiskSize+j.MemSize + return cmp.Compare(i.DiskSize+i.MemSize, j.DiskSize+j.MemSize) }) for _, size := range sizes { totalDiskSize += size.DiskSize diff --git a/br/pkg/lightning/importer/BUILD.bazel b/br/pkg/lightning/importer/BUILD.bazel index e52caf6f7aeee..7c8e2bc95b7a1 100644 --- a/br/pkg/lightning/importer/BUILD.bazel +++ b/br/pkg/lightning/importer/BUILD.bazel @@ -182,7 +182,6 @@ go_test( "@com_github_xitongsys_parquet_go_source//buffer", "@io_etcd_go_etcd_client_v3//:client", "@io_etcd_go_etcd_tests_v3//integration", - "@org_golang_x_exp//slices", "@org_uber_go_zap//:zap", ], ) diff --git a/br/pkg/lightning/importer/dup_detect_test.go b/br/pkg/lightning/importer/dup_detect_test.go index 2f6aaad85ea45..53f209023acc8 100644 --- a/br/pkg/lightning/importer/dup_detect_test.go +++ b/br/pkg/lightning/importer/dup_detect_test.go @@ -16,6 +16,7 @@ package importer import ( "context" + "slices" "testing" "github.com/pingcap/errors" @@ -27,7 +28,6 @@ import ( "github.com/pingcap/tidb/util/dbutil" "github.com/pingcap/tidb/util/extsort" "github.com/stretchr/testify/require" - "golang.org/x/exp/slices" ) var ( diff --git a/ddl/ddl.go b/ddl/ddl.go index 52853e10488b2..9a00e55e0afa7 100644 --- a/ddl/ddl.go +++ b/ddl/ddl.go @@ -64,7 +64,6 @@ import ( "github.com/pingcap/tidb/util/dbterror" "github.com/pingcap/tidb/util/gcutil" "github.com/pingcap/tidb/util/logutil" - "github.com/pingcap/tidb/util/mathutil" "github.com/pingcap/tidb/util/syncutil" "github.com/tikv/client-go/v2/tikvrpc" clientv3 "go.etcd.io/etcd/client/v3" @@ -747,7 +746,7 @@ func (d *ddl) prepareWorkers4ConcurrencyDDL() { } } // reorg worker count at least 1 at most 10. - reorgCnt := mathutil.Min(mathutil.Max(runtime.GOMAXPROCS(0)/4, 1), reorgWorkerCnt) + reorgCnt := min(max(runtime.GOMAXPROCS(0)/4, 1), reorgWorkerCnt) d.reorgWorkerPool = newDDLWorkerPool(pools.NewResourcePool(workerFactory(addIdxWorker), reorgCnt, reorgCnt, 0), reorg) d.generalDDLWorkerPool = newDDLWorkerPool(pools.NewResourcePool(workerFactory(generalWorker), generalWorkerCnt, generalWorkerCnt, 0), general) failpoint.Inject("NoDDLDispatchLoop", func(val failpoint.Value) { diff --git a/executor/executor.go b/executor/executor.go index f7eb3dabb1a43..5749f74a2e550 100644 --- a/executor/executor.go +++ b/executor/executor.go @@ -15,10 +15,12 @@ package executor import ( + "cmp" "context" "fmt" "math" "runtime/pprof" + "slices" "strconv" "strings" "sync" @@ -82,7 +84,6 @@ import ( tikvutil "github.com/tikv/client-go/v2/util" atomicutil "go.uber.org/atomic" "go.uber.org/zap" - "golang.org/x/exp/slices" ) var ( @@ -2475,8 +2476,8 @@ func (w *checkIndexWorker) HandleTask(task checkIndexTask) (_ workerpool.None) { trySaveErr(err) return } - slices.SortFunc(tableChecksum, func(i, j groupByChecksum) bool { - return i.bucket < j.bucket + slices.SortFunc(tableChecksum, func(i, j groupByChecksum) int { + return cmp.Compare(i.bucket, j.bucket) }) // compute index side checksum. @@ -2485,8 +2486,8 @@ func (w *checkIndexWorker) HandleTask(task checkIndexTask) (_ workerpool.None) { trySaveErr(err) return } - slices.SortFunc(indexChecksum, func(i, j groupByChecksum) bool { - return i.bucket < j.bucket + slices.SortFunc(indexChecksum, func(i, j groupByChecksum) int { + return cmp.Compare(i.bucket, j.bucket) }) currentOffset := 0 diff --git a/executor/index_lookup_merge_join.go b/executor/index_lookup_merge_join.go index 64a4abab1b7d2..b7de825f0e129 100644 --- a/executor/index_lookup_merge_join.go +++ b/executor/index_lookup_merge_join.go @@ -18,6 +18,7 @@ import ( "context" "fmt" "runtime/trace" + "slices" "sync" "sync/atomic" @@ -38,7 +39,6 @@ import ( "github.com/pingcap/tidb/util/memory" "github.com/pingcap/tidb/util/ranger" "go.uber.org/zap" - "golang.org/x/exp/slices" ) // IndexLookUpMergeJoin realizes IndexLookUpJoin by merge join @@ -450,23 +450,29 @@ func (imw *innerMergeWorker) handleTask(ctx context.Context, task *lookUpMergeJo // Because the necessary condition of merge join is both outer and inner keep order of join keys. // In this case, we need sort the outer side. if imw.outerMergeCtx.needOuterSort { - slices.SortFunc(task.outerOrderIdx, func(idxI, idxJ chunk.RowPtr) bool { + slices.SortFunc(task.outerOrderIdx, func(idxI, idxJ chunk.RowPtr) int { rowI, rowJ := task.outerResult.GetRow(idxI), task.outerResult.GetRow(idxJ) - var cmp int64 + var c int64 var err error for _, keyOff := range imw.keyOff2KeyOffOrderByIdx { joinKey := imw.outerMergeCtx.joinKeys[keyOff] - cmp, _, err = imw.outerMergeCtx.compareFuncs[keyOff](imw.ctx, joinKey, joinKey, rowI, rowJ) + c, _, err = imw.outerMergeCtx.compareFuncs[keyOff](imw.ctx, joinKey, joinKey, rowI, rowJ) terror.Log(err) - if cmp != 0 { + if c != 0 { break } } - if cmp != 0 || imw.nextColCompareFilters == nil { - return (cmp < 0 && !imw.desc) || (cmp > 0 && imw.desc) + if c != 0 || imw.nextColCompareFilters == nil { + if imw.desc { + return int(-c) + } + return int(c) + } + c = int64(imw.nextColCompareFilters.CompareRow(rowI, rowJ)) + if imw.desc { + return int(-c) } - cmp = int64(imw.nextColCompareFilters.CompareRow(rowI, rowJ)) - return (cmp < 0 && !imw.desc) || (cmp > 0 && imw.desc) + return int(c) }) } dLookUpKeys, err := imw.constructDatumLookupKeys(task) diff --git a/executor/sort.go b/executor/sort.go index 4210a086bcf30..5ccdab75d3db5 100644 --- a/executor/sort.go +++ b/executor/sort.go @@ -18,6 +18,7 @@ import ( "container/heap" "context" "errors" + "slices" "github.com/pingcap/failpoint" "github.com/pingcap/tidb/executor/internal/exec" @@ -29,7 +30,6 @@ import ( "github.com/pingcap/tidb/util/disk" "github.com/pingcap/tidb/util/mathutil" "github.com/pingcap/tidb/util/memory" - "golang.org/x/exp/slices" ) // SortExec represents sorting executor. @@ -143,7 +143,7 @@ func (e *SortExec) Next(ctx context.Context, req *chunk.Chunk) error { func (e *SortExec) externalSorting(req *chunk.Chunk) (err error) { if e.multiWayMerge == nil { - e.multiWayMerge = &multiWayMerge{e.lessRow, make([]partitionPointer, 0, len(e.partitionList))} + e.multiWayMerge = &multiWayMerge{e.lessRow, e.compressRow, make([]partitionPointer, 0, len(e.partitionList))} for i := 0; i < len(e.partitionList); i++ { row, err := e.partitionList[i].GetSortedRow(0) if err != nil { @@ -273,6 +273,20 @@ func (e *SortExec) lessRow(rowI, rowJ chunk.Row) bool { return false } +func (e *SortExec) compressRow(rowI, rowJ chunk.Row) int { + for i, colIdx := range e.keyColumns { + cmpFunc := e.keyCmpFuncs[i] + cmp := cmpFunc(rowI, colIdx, rowJ, colIdx) + if e.ByItems[i].Desc { + cmp = -cmp + } + if cmp != 0 { + return cmp + } + } + return 0 +} + type partitionPointer struct { row chunk.Row partitionID int @@ -280,8 +294,9 @@ type partitionPointer struct { } type multiWayMerge struct { - lessRowFunction func(rowI chunk.Row, rowJ chunk.Row) bool - elements []partitionPointer + lessRowFunction func(rowI chunk.Row, rowJ chunk.Row) bool + compressRowFunction func(rowI chunk.Row, rowJ chunk.Row) int + elements []partitionPointer } func (h *multiWayMerge) Less(i, j int) bool { @@ -376,6 +391,12 @@ func (e *TopNExec) keyColumnsLess(i, j chunk.RowPtr) bool { return e.lessRow(rowI, rowJ) } +func (e *TopNExec) keyColumnsCompare(i, j chunk.RowPtr) int { + rowI := e.rowChunks.GetRow(i) + rowJ := e.rowChunks.GetRow(j) + return e.compressRow(rowI, rowJ) +} + func (e *TopNExec) initPointers() { e.rowPtrs = make([]chunk.RowPtr, 0, e.rowChunks.Len()) e.memTracker.Consume(int64(8 * e.rowChunks.Len())) @@ -481,7 +502,7 @@ func (e *TopNExec) executeTopN(ctx context.Context) error { } } } - slices.SortFunc(e.rowPtrs, e.keyColumnsLess) + slices.SortFunc(e.rowPtrs, e.keyColumnsCompare) return nil } diff --git a/planner/core/BUILD.bazel b/planner/core/BUILD.bazel index d18fb0424f71a..c17af4b188ea6 100644 --- a/planner/core/BUILD.bazel +++ b/planner/core/BUILD.bazel @@ -171,7 +171,6 @@ go_library( "@com_github_tikv_client_go_v2//kv", "@com_github_tikv_client_go_v2//oracle", "@com_github_tikv_client_go_v2//tikv", - "@org_golang_x_exp//slices", "@org_uber_go_atomic//:atomic", "@org_uber_go_zap//:zap", ], diff --git a/planner/core/optimizer.go b/planner/core/optimizer.go index bf2d055c9b4bc..7519935dfe8eb 100644 --- a/planner/core/optimizer.go +++ b/planner/core/optimizer.go @@ -15,10 +15,12 @@ package core import ( + "cmp" "context" "fmt" "math" "runtime" + "slices" "strconv" "time" @@ -50,7 +52,6 @@ import ( "github.com/pingcap/tipb/go-tipb" "go.uber.org/atomic" "go.uber.org/zap" - "golang.org/x/exp/slices" ) // OptimizeAstNode optimizes the query to a physical plan directly. @@ -345,24 +346,24 @@ func DoOptimize(ctx context.Context, sctx sessionctx.Context, flag uint64, logic func refineCETrace(sctx sessionctx.Context) { stmtCtx := sctx.GetSessionVars().StmtCtx stmtCtx.OptimizerCETrace = tracing.DedupCETrace(stmtCtx.OptimizerCETrace) - slices.SortFunc(stmtCtx.OptimizerCETrace, func(i, j *tracing.CETraceRecord) bool { + slices.SortFunc(stmtCtx.OptimizerCETrace, func(i, j *tracing.CETraceRecord) int { if i == nil && j != nil { - return true + return -1 } if i == nil || j == nil { - return false + return 1 } - if i.TableID != j.TableID { - return i.TableID < j.TableID + if c := cmp.Compare(i.TableID, j.TableID); c != 0 { + return c } - if i.Type != j.Type { - return i.Type < j.Type + if c := cmp.Compare(i.Type, j.Type); c != 0 { + return c } - if i.Expr != j.Expr { - return i.Expr < j.Expr + if c := cmp.Compare(i.Expr, j.Expr); c != 0 { + return c } - return i.RowCount < j.RowCount + return cmp.Compare(i.RowCount, j.RowCount) }) traceRecords := stmtCtx.OptimizerCETrace is := sctx.GetDomainInfoSchema().(infoschema.InfoSchema) diff --git a/planner/funcdep/BUILD.bazel b/planner/funcdep/BUILD.bazel index e5f8591c1b675..4a140ec179d78 100644 --- a/planner/funcdep/BUILD.bazel +++ b/planner/funcdep/BUILD.bazel @@ -41,7 +41,6 @@ go_test( "//util/hint", "@com_github_stretchr_testify//require", "@org_golang_x_exp//maps", - "@org_golang_x_exp//slices", "@org_golang_x_tools//container/intsets", "@org_uber_go_goleak//:goleak", ], diff --git a/planner/funcdep/fast_int_set_test.go b/planner/funcdep/fast_int_set_test.go index 72cfef58ec870..110484f2849a2 100644 --- a/planner/funcdep/fast_int_set_test.go +++ b/planner/funcdep/fast_int_set_test.go @@ -19,13 +19,13 @@ import ( "math/rand" "reflect" "runtime" + "slices" "strings" "testing" "time" "github.com/stretchr/testify/require" "golang.org/x/exp/maps" - "golang.org/x/exp/slices" "golang.org/x/tools/container/intsets" ) diff --git a/sessionctx/stmtctx/BUILD.bazel b/sessionctx/stmtctx/BUILD.bazel index e16d9a44da20d..282d6332225a8 100644 --- a/sessionctx/stmtctx/BUILD.bazel +++ b/sessionctx/stmtctx/BUILD.bazel @@ -23,7 +23,6 @@ go_library( "@com_github_tikv_client_go_v2//tikvrpc", "@com_github_tikv_client_go_v2//util", "@org_golang_x_exp//maps", - "@org_golang_x_exp//slices", "@org_uber_go_atomic//:atomic", "@org_uber_go_zap//:zap", ], diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index 5e3ead54d0640..676647635869e 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -20,6 +20,7 @@ import ( "fmt" "io" "math" + "slices" "strconv" "strings" "sync" @@ -45,7 +46,6 @@ import ( atomic2 "go.uber.org/atomic" "go.uber.org/zap" "golang.org/x/exp/maps" - "golang.org/x/exp/slices" ) const ( diff --git a/statistics/BUILD.bazel b/statistics/BUILD.bazel index ff7c8f7cae493..9fedac82974df 100644 --- a/statistics/BUILD.bazel +++ b/statistics/BUILD.bazel @@ -58,7 +58,6 @@ go_library( "@com_github_pingcap_tipb//go-tipb", "@com_github_twmb_murmur3//:murmur3", "@org_golang_x_exp//maps", - "@org_golang_x_exp//slices", "@org_uber_go_atomic//:atomic", "@org_uber_go_zap//:zap", ], diff --git a/statistics/cmsketch.go b/statistics/cmsketch.go index f94d00ca08fa5..6c49861a77723 100644 --- a/statistics/cmsketch.go +++ b/statistics/cmsketch.go @@ -118,7 +118,7 @@ func newTopNHelper(sample [][]byte, numTop uint32) *topNHelper { sumTopN uint64 sampleNDV = uint32(len(sorted)) ) - numTop = mathutil.Min(sampleNDV, numTop) // Ensure numTop no larger than sampNDV. + numTop = min(sampleNDV, numTop) // Ensure numTop no larger than sampNDV. // Only element whose frequency is not smaller than 2/3 multiples the // frequency of the n-th element are added to the TopN statistics. We chose // 2/3 as an empirical value because the average cardinality estimation @@ -876,7 +876,7 @@ func MergePartTopN2GlobalTopN(loc *time.Location, version int, topNs []*TopN, n data := hack.Slice(string(value)) sorted = append(sorted, TopNMeta{Encoded: data, Count: uint64(cnt)}) } - globalTopN, leftTopN := getMergedTopNFromSortedSlice(sorted, n) + globalTopN, leftTopN := GetMergedTopNFromSortedSlice(sorted, n) return globalTopN, leftTopN, hists, nil } @@ -907,7 +907,7 @@ func MergeTopN(topNs []*TopN, n uint32) (*TopN, []TopNMeta) { data := hack.Slice(string(value)) sorted = append(sorted, TopNMeta{Encoded: data, Count: cnt}) } - return getMergedTopNFromSortedSlice(sorted, n) + return GetMergedTopNFromSortedSlice(sorted, n) } func checkEmptyTopNs(topNs []*TopN) bool { @@ -928,14 +928,19 @@ func SortTopnMeta(topnMetas []TopNMeta) { }) } -// GetMergedTopNFromSortedSlice returns merged topn -func GetMergedTopNFromSortedSlice(sorted []TopNMeta, n uint32) (*TopN, []TopNMeta) { - return getMergedTopNFromSortedSlice(sorted, n) +// TopnMetaCompare compare topnMeta +func TopnMetaCompare(i, j TopNMeta) int { + c := cmp.Compare(i.Count, j.Count) + if c == 0 { + return c + } + return bytes.Compare(i.Encoded, j.Encoded) } -func getMergedTopNFromSortedSlice(sorted []TopNMeta, n uint32) (*TopN, []TopNMeta) { +// GetMergedTopNFromSortedSlice returns merged topn +func GetMergedTopNFromSortedSlice(sorted []TopNMeta, n uint32) (*TopN, []TopNMeta) { SortTopnMeta(sorted) - n = mathutil.Min(uint32(len(sorted)), n) + n = min(uint32(len(sorted)), n) var finalTopN TopN finalTopN.TopN = sorted[:n] diff --git a/statistics/merge_worker.go b/statistics/merge_worker.go index 3d2987eee3007..22f631a8f3dcc 100644 --- a/statistics/merge_worker.go +++ b/statistics/merge_worker.go @@ -188,7 +188,7 @@ func (worker *topnStatsMergeWorker) Run(timeZone *time.Location, isIndex bool, data := hack.Slice(string(value)) sorted = append(sorted, TopNMeta{Encoded: data, Count: uint64(cnt)}) } - globalTopN, leftTopN := getMergedTopNFromSortedSlice(sorted, n) + globalTopN, leftTopN := GetMergedTopNFromSortedSlice(sorted, n) resp.TopN = globalTopN resp.PopedTopn = leftTopN worker.respCh <- resp diff --git a/statistics/selectivity.go b/statistics/selectivity.go index b49da070a7ada..a5b80961c5dee 100644 --- a/statistics/selectivity.go +++ b/statistics/selectivity.go @@ -16,8 +16,10 @@ package statistics import ( "bytes" + "cmp" "math" "math/bits" + "slices" "github.com/pingcap/errors" "github.com/pingcap/tidb/expression" @@ -35,7 +37,6 @@ import ( "github.com/pingcap/tidb/util/tracing" "go.uber.org/zap" "golang.org/x/exp/maps" - "golang.org/x/exp/slices" ) // If one condition can't be calculated, we will assume that the selectivity of this condition is 0.8. @@ -590,11 +591,11 @@ func getMaskAndRanges(ctx sessionctx.Context, exprs []expression.Expression, ran // GetUsableSetsByGreedy will select the indices and pk used for calculate selectivity by greedy algorithm. func GetUsableSetsByGreedy(nodes []*StatsNode) (newBlocks []*StatsNode) { - slices.SortFunc(nodes, func(i, j *StatsNode) bool { + slices.SortFunc(nodes, func(i, j *StatsNode) int { if r := compareType(i.Tp, j.Tp); r != 0 { - return r < 0 + return r } - return i.ID < j.ID + return cmp.Compare(i.ID, j.ID) }) marked := make([]bool, len(nodes)) mask := int64(math.MaxInt64) diff --git a/store/mockstore/unistore/cophandler/BUILD.bazel b/store/mockstore/unistore/cophandler/BUILD.bazel index c1e32c7bab2a8..d4dcc21200db7 100644 --- a/store/mockstore/unistore/cophandler/BUILD.bazel +++ b/store/mockstore/unistore/cophandler/BUILD.bazel @@ -48,7 +48,6 @@ go_library( "@com_github_pingcap_tipb//go-tipb", "@com_github_tikv_client_go_v2//tikvrpc", "@com_github_twmb_murmur3//:murmur3", - "@org_golang_x_exp//slices", "@org_uber_go_atomic//:atomic", ], ) diff --git a/store/mockstore/unistore/cophandler/analyze.go b/store/mockstore/unistore/cophandler/analyze.go index a04b158e4b4a6..626147ed16d22 100644 --- a/store/mockstore/unistore/cophandler/analyze.go +++ b/store/mockstore/unistore/cophandler/analyze.go @@ -19,6 +19,7 @@ import ( "context" "math" "math/rand" + "slices" "time" "github.com/golang/protobuf/proto" @@ -40,7 +41,6 @@ import ( "github.com/pingcap/tidb/util/rowcodec" "github.com/pingcap/tipb/go-tipb" "github.com/twmb/murmur3" - "golang.org/x/exp/slices" ) // handleCopAnalyzeRequest handles coprocessor analyze request. @@ -112,14 +112,7 @@ func handleAnalyzeIndexReq(dbReader *dbreader.DBReader, rans []kv.KeyRange, anal if processor.topNCurValuePair.Count != 0 { processor.topNValuePairs = append(processor.topNValuePairs, processor.topNCurValuePair) } - slices.SortFunc(processor.topNValuePairs, func(i, j statistics.TopNMeta) bool { - if i.Count > j.Count { - return true - } else if i.Count < j.Count { - return false - } - return bytes.Compare(i.Encoded, j.Encoded) < 0 - }) + slices.SortFunc(processor.topNValuePairs, statistics.TopnMetaCompare) if len(processor.topNValuePairs) > int(processor.topNCount) { processor.topNValuePairs = processor.topNValuePairs[:processor.topNCount] } @@ -564,14 +557,7 @@ func handleAnalyzeMixedReq(dbReader *dbreader.DBReader, rans []kv.KeyRange, anal if e.topNCurValuePair.Count != 0 { e.topNValuePairs = append(e.topNValuePairs, e.topNCurValuePair) } - slices.SortFunc(e.topNValuePairs, func(i, j statistics.TopNMeta) bool { - if i.Count > j.Count { - return true - } else if i.Count < j.Count { - return false - } - return bytes.Compare(i.Encoded, j.Encoded) < 0 - }) + slices.SortFunc(e.topNValuePairs, statistics.TopnMetaCompare) if len(e.topNValuePairs) > int(e.topNCount) { e.topNValuePairs = e.topNValuePairs[:e.topNCount] } diff --git a/store/pdtypes/BUILD.bazel b/store/pdtypes/BUILD.bazel index dd35cae23c4d9..fe59445be494a 100644 --- a/store/pdtypes/BUILD.bazel +++ b/store/pdtypes/BUILD.bazel @@ -17,6 +17,5 @@ go_library( "@com_github_pingcap_errors//:errors", "@com_github_pingcap_kvproto//pkg/metapb", "@com_github_pingcap_kvproto//pkg/pdpb", - "@org_golang_x_exp//slices", ], ) diff --git a/store/pdtypes/region_tree.go b/store/pdtypes/region_tree.go index cc99e981e0097..5112b7b810d6b 100644 --- a/store/pdtypes/region_tree.go +++ b/store/pdtypes/region_tree.go @@ -16,9 +16,9 @@ package pdtypes import ( "bytes" + "slices" "github.com/pingcap/kvproto/pkg/metapb" - "golang.org/x/exp/slices" ) // Region is a mock of PD's core.RegionInfo. For testing purpose. @@ -52,8 +52,8 @@ func (t *RegionTree) SetRegion(region *Region) { // ScanRange scans regions intersecting [start key, end key), returns at most // `limit` regions. limit <= 0 means no limit. func (t *RegionTree) ScanRange(startKey, endKey []byte, limit int) []*Region { - slices.SortFunc(t.Regions, func(i, j *Region) bool { - return bytes.Compare(i.Meta.StartKey, j.Meta.StartKey) < 0 + slices.SortFunc(t.Regions, func(i, j *Region) int { + return bytes.Compare(i.Meta.StartKey, j.Meta.StartKey) }) pivot := NewRegionInfo(&metapb.Region{StartKey: startKey, EndKey: endKey}, nil) var res []*Region diff --git a/table/temptable/BUILD.bazel b/table/temptable/BUILD.bazel index 6b37476e145f5..fa977d1b267a6 100644 --- a/table/temptable/BUILD.bazel +++ b/table/temptable/BUILD.bazel @@ -59,7 +59,6 @@ go_test( "//util/mock", "@com_github_pingcap_errors//:errors", "@com_github_stretchr_testify//require", - "@org_golang_x_exp//slices", "@org_uber_go_goleak//:goleak", ], ) diff --git a/table/temptable/main_test.go b/table/temptable/main_test.go index 8b8487b2eceba..94bc60c619666 100644 --- a/table/temptable/main_test.go +++ b/table/temptable/main_test.go @@ -18,6 +18,7 @@ import ( "bytes" "context" "fmt" + "slices" "testing" "github.com/pingcap/tidb/infoschema" @@ -31,7 +32,6 @@ import ( "github.com/pingcap/tidb/util/mock" "github.com/stretchr/testify/require" "go.uber.org/goleak" - "golang.org/x/exp/slices" ) func TestMain(m *testing.M) { @@ -126,7 +126,7 @@ func newMockedRetriever(t *testing.T) *mockedRetriever { } func (r *mockedRetriever) SetData(data []*kv.Entry) *mockedRetriever { - lessFunc := func(i, j *kv.Entry) bool { return bytes.Compare(i.Key, j.Key) < 0 } + lessFunc := func(i, j *kv.Entry) int { return bytes.Compare(i.Key, j.Key) } if !slices.IsSortedFunc(data, lessFunc) { data = append([]*kv.Entry{}, data...) slices.SortFunc(data, lessFunc) From a8cfe88abae6ce83889d3c2e811f412656c70a40 Mon Sep 17 00:00:00 2001 From: YangKeao Date: Tue, 22 Aug 2023 15:09:34 +0800 Subject: [PATCH 3/4] util/collate: add collation utf8mb4_0900_bin (#46269) close pingcap/tidb#46268 --- .../r/collation_misc_enabled.result | 2 + executor/test/seqtest/seq_executor_test.go | 1 + util/collate/collate.go | 2 + util/collate/collate_bench_test.go | 36 ++++++++++-- util/collate/collate_test.go | 57 +++++++++++-------- 5 files changed, 67 insertions(+), 31 deletions(-) diff --git a/cmd/explaintest/r/collation_misc_enabled.result b/cmd/explaintest/r/collation_misc_enabled.result index 4d8015bc67302..4e4db999b53bd 100644 --- a/cmd/explaintest/r/collation_misc_enabled.result +++ b/cmd/explaintest/r/collation_misc_enabled.result @@ -105,6 +105,7 @@ utf8 83 1 utf8 33 1 utf8 192 1 utf8mb4 255 1 +utf8mb4 309 1 utf8mb4 46 1 utf8mb4 45 1 utf8mb4 224 1 @@ -130,6 +131,7 @@ utf8_bin utf8 83 Yes Yes 1 utf8_general_ci utf8 33 Yes 1 utf8_unicode_ci utf8 192 Yes 1 utf8mb4_0900_ai_ci utf8mb4 255 Yes 1 +utf8mb4_0900_bin utf8mb4 309 Yes 1 utf8mb4_bin utf8mb4 46 Yes Yes 1 utf8mb4_general_ci utf8mb4 45 Yes 1 utf8mb4_unicode_ci utf8mb4 224 Yes 1 diff --git a/executor/test/seqtest/seq_executor_test.go b/executor/test/seqtest/seq_executor_test.go index 1f5d34b2526e8..b18181c8fb603 100644 --- a/executor/test/seqtest/seq_executor_test.go +++ b/executor/test/seqtest/seq_executor_test.go @@ -1203,6 +1203,7 @@ func TestShowForNewCollations(t *testing.T) { "utf8_general_ci utf8 33 Yes 1", "utf8_unicode_ci utf8 192 Yes 1", "utf8mb4_0900_ai_ci utf8mb4 255 Yes 1", + "utf8mb4_0900_bin utf8mb4 309 Yes 1", "utf8mb4_bin utf8mb4 46 Yes Yes 1", "utf8mb4_general_ci utf8mb4 45 Yes 1", "utf8mb4_unicode_ci utf8mb4 224 Yes 1", diff --git a/util/collate/collate.go b/util/collate/collate.go index 05d1a4750a741..0b544b00d8883 100644 --- a/util/collate/collate.go +++ b/util/collate/collate.go @@ -404,6 +404,8 @@ func init() { newCollatorIDMap[CollationName2ID("utf8mb4_bin")] = &binPaddingCollator{} newCollatorMap["utf8_bin"] = &binPaddingCollator{} newCollatorIDMap[CollationName2ID("utf8_bin")] = &binPaddingCollator{} + newCollatorMap["utf8mb4_0900_bin"] = &binCollator{} + newCollatorIDMap[CollationName2ID("utf8mb4_0900_bin")] = &binCollator{} newCollatorMap["utf8mb4_general_ci"] = &generalCICollator{} newCollatorIDMap[CollationName2ID("utf8mb4_general_ci")] = &generalCICollator{} newCollatorMap["utf8_general_ci"] = &generalCICollator{} diff --git a/util/collate/collate_bench_test.go b/util/collate/collate_bench_test.go index cad9e254d19ae..95707c6ec4511 100644 --- a/util/collate/collate_bench_test.go +++ b/util/collate/collate_bench_test.go @@ -54,7 +54,7 @@ func key(b *testing.B, collator Collator, length int) { } func BenchmarkUtf8mb4Bin_CompareShort(b *testing.B) { - compare(b, &binCollator{}, short) + compare(b, &binPaddingCollator{}, short) } func BenchmarkUtf8mb4GeneralCI_CompareShort(b *testing.B) { @@ -69,8 +69,12 @@ func BenchmarkUtf8mb40900AICI_CompareShort(b *testing.B) { compare(b, &unicode0900AICICollator{}, short) } +func BenchmarkUtf8mb40900Bin_CompareShort(b *testing.B) { + compare(b, &binCollator{}, short) +} + func BenchmarkUtf8mb4Bin_CompareMid(b *testing.B) { - compare(b, &binCollator{}, middle) + compare(b, &binPaddingCollator{}, middle) } func BenchmarkUtf8mb4GeneralCI_CompareMid(b *testing.B) { @@ -85,8 +89,12 @@ func BenchmarkUtf8mb40900AICI_CompareMid(b *testing.B) { compare(b, &unicode0900AICICollator{}, middle) } +func BenchmarkUtf8mb40900Bin_CompareMid(b *testing.B) { + compare(b, &binCollator{}, middle) +} + func BenchmarkUtf8mb4Bin_CompareLong(b *testing.B) { - compare(b, &binCollator{}, long) + compare(b, &binPaddingCollator{}, long) } func BenchmarkUtf8mb4GeneralCI_CompareLong(b *testing.B) { @@ -101,8 +109,12 @@ func BenchmarkUtf8mb40900AICI_CompareLong(b *testing.B) { compare(b, &unicode0900AICICollator{}, long) } +func BenchmarkUtf8mb40900Bin_CompareLong(b *testing.B) { + compare(b, &binCollator{}, long) +} + func BenchmarkUtf8mb4Bin_KeyShort(b *testing.B) { - key(b, &binCollator{}, short) + key(b, &binPaddingCollator{}, short) } func BenchmarkUtf8mb4GeneralCI_KeyShort(b *testing.B) { @@ -117,8 +129,12 @@ func BenchmarkUtf8mb40900AICI_KeyShort(b *testing.B) { key(b, &unicode0900AICICollator{}, short) } +func BenchmarkUtf8mb40900Bin_KeyShort(b *testing.B) { + key(b, &binCollator{}, short) +} + func BenchmarkUtf8mb4Bin_KeyMid(b *testing.B) { - key(b, &binCollator{}, middle) + key(b, &binPaddingCollator{}, middle) } func BenchmarkUtf8mb4GeneralCI_KeyMid(b *testing.B) { @@ -133,8 +149,12 @@ func BenchmarkUtf8mb40900AICI_KeyMid(b *testing.B) { key(b, &unicode0900AICICollator{}, middle) } +func BenchmarkUtf8mb40900Bin_KeyMid(b *testing.B) { + key(b, &binCollator{}, middle) +} + func BenchmarkUtf8mb4Bin_KeyLong(b *testing.B) { - key(b, &binCollator{}, long) + key(b, &binPaddingCollator{}, long) } func BenchmarkUtf8mb4GeneralCI_KeyLong(b *testing.B) { @@ -148,3 +168,7 @@ func BenchmarkUtf8mb4UnicodeCI_KeyLong(b *testing.B) { func BenchmarkUtf8mb40900AICI_KeyLong(b *testing.B) { key(b, &unicode0900AICICollator{}, long) } + +func BenchmarkUtf8mb40900Bin_KeyLong(b *testing.B) { + key(b, &binCollator{}, long) +} diff --git a/util/collate/collate_test.go b/util/collate/collate_test.go index c70e8f05ca71d..34ab6bc0cdce3 100644 --- a/util/collate/collate_test.go +++ b/util/collate/collate_test.go @@ -55,28 +55,28 @@ func testKeyTable(t *testing.T, collations []string, tests []keyTable) { func TestUTF8CollatorCompare(t *testing.T) { SetNewCollationEnabledForTest(true) defer SetNewCollationEnabledForTest(false) - collations := []string{"binary", "utf8mb4_bin", "utf8mb4_general_ci", "utf8mb4_unicode_ci", "utf8mb4_0900_ai_ci", "gbk_bin", "gbk_chinese_ci"} + collations := []string{"binary", "utf8mb4_bin", "utf8mb4_general_ci", "utf8mb4_unicode_ci", "utf8mb4_0900_ai_ci", "utf8mb4_0900_bin", "gbk_bin", "gbk_chinese_ci"} tests := []compareTable{ - {"a", "b", []int{-1, -1, -1, -1, -1, -1, -1}}, - {"a", "A", []int{1, 1, 0, 0, 0, 1, 0}}, - {"Γ€", "A", []int{1, 1, 0, 0, 0, -1, -1}}, - {"abc", "abc", []int{0, 0, 0, 0, 0, 0, 0}}, - {"abc", "ab", []int{1, 1, 1, 1, 1, 1, 1}}, - {"😜", "πŸ˜ƒ", []int{1, 1, 0, 0, 1, 0, 0}}, - {"a", "a ", []int{-1, 0, 0, 0, -1, 0, 0}}, - {"a ", "a ", []int{-1, 0, 0, 0, -1, 0, 0}}, - {"a\t", "a", []int{1, 1, 1, 1, 1, 1, 1}}, - {"ß", "s", []int{1, 1, 0, 1, 1, -1, -1}}, - {"ß", "ss", []int{1, 1, -1, 0, 0, -1, -1}}, - {"ε•Š", "吧", []int{1, 1, 1, 1, 1, -1, -1}}, - {"δΈ­ζ–‡", "汉字", []int{-1, -1, -1, -1, -1, 1, 1}}, - {"Γ¦", "ae", []int{1, 1, 1, 1, 0, -1, -1}}, - {"Å", "A", []int{1, 1, 1, 0, 0, 1, 1}}, - {"Γ…", "A", []int{1, 1, 0, 0, 0, -1, -1}}, - {"\U0001730F", "ε•Š", []int{1, 1, 1, 1, -1, -1, -1}}, - {"κ°€", "㉑", []int{1, 1, 1, 1, -1, 0, 0}}, - {"갟", "감1", []int{1, 1, 1, 1, 1, -1, -1}}, - {"\U000FFFFE", "\U000FFFFF", []int{-1, -1, 0, 0, -1, 0, 0}}, + {"a", "b", []int{-1, -1, -1, -1, -1, -1, -1, -1}}, + {"a", "A", []int{1, 1, 0, 0, 0, 1, 1, 0}}, + {"Γ€", "A", []int{1, 1, 0, 0, 0, 1, -1, -1}}, + {"abc", "abc", []int{0, 0, 0, 0, 0, 0, 0, 0}}, + {"abc", "ab", []int{1, 1, 1, 1, 1, 1, 1, 1}}, + {"😜", "πŸ˜ƒ", []int{1, 1, 0, 0, 1, 1, 0, 0}}, + {"a", "a ", []int{-1, 0, 0, 0, -1, -1, 0, 0}}, + {"a ", "a ", []int{-1, 0, 0, 0, -1, -1, 0, 0}}, + {"a\t", "a", []int{1, 1, 1, 1, 1, 1, 1, 1}}, + {"ß", "s", []int{1, 1, 0, 1, 1, 1, -1, -1}}, + {"ß", "ss", []int{1, 1, -1, 0, 0, 1, -1, -1}}, + {"ε•Š", "吧", []int{1, 1, 1, 1, 1, 1, -1, -1}}, + {"δΈ­ζ–‡", "汉字", []int{-1, -1, -1, -1, -1, -1, 1, 1}}, + {"Γ¦", "ae", []int{1, 1, 1, 1, 0, 1, -1, -1}}, + {"Å", "A", []int{1, 1, 1, 0, 0, 1, 1, 1}}, + {"Γ…", "A", []int{1, 1, 0, 0, 0, 1, -1, -1}}, + {"\U0001730F", "ε•Š", []int{1, 1, 1, 1, -1, 1, -1, -1}}, + {"κ°€", "㉑", []int{1, 1, 1, 1, -1, 1, 0, 0}}, + {"갟", "감1", []int{1, 1, 1, 1, 1, 1, -1, -1}}, + {"\U000FFFFE", "\U000FFFFF", []int{-1, -1, 0, 0, -1, -1, 0, 0}}, } testCompareTable(t, collations, tests) } @@ -84,26 +84,28 @@ func TestUTF8CollatorCompare(t *testing.T) { func TestUTF8CollatorKey(t *testing.T) { SetNewCollationEnabledForTest(true) defer SetNewCollationEnabledForTest(false) - collations := []string{"binary", "utf8mb4_bin", "utf8mb4_general_ci", "utf8mb4_unicode_ci", "utf8mb4_0900_ai_ci", "gbk_bin", "gbk_chinese_ci"} + collations := []string{"binary", "utf8mb4_bin", "utf8mb4_general_ci", "utf8mb4_unicode_ci", "utf8mb4_0900_ai_ci", "utf8mb4_0900_bin", "gbk_bin", "gbk_chinese_ci"} tests := []keyTable{ - {"a", [][]byte{{0x61}, {0x61}, {0x0, 0x41}, {0x0E, 0x33}, {0x1C, 0x47}, {0x61}, {0x41}}}, - {"A", [][]byte{{0x41}, {0x41}, {0x0, 0x41}, {0x0E, 0x33}, {0x1C, 0x47}, {0x41}, {0x41}}}, + {"a", [][]byte{{0x61}, {0x61}, {0x0, 0x41}, {0x0E, 0x33}, {0x1C, 0x47}, {0x61}, {0x61}, {0x41}}}, + {"A", [][]byte{{0x41}, {0x41}, {0x0, 0x41}, {0x0E, 0x33}, {0x1C, 0x47}, {0x41}, {0x41}, {0x41}}}, {"Foo Β© bar πŒ† baz β˜ƒ qux", [][]byte{ {0x46, 0x6f, 0x6f, 0x20, 0xc2, 0xa9, 0x20, 0x62, 0x61, 0x72, 0x20, 0xf0, 0x9d, 0x8c, 0x86, 0x20, 0x62, 0x61, 0x7a, 0x20, 0xe2, 0x98, 0x83, 0x20, 0x71, 0x75, 0x78}, {0x46, 0x6f, 0x6f, 0x20, 0xc2, 0xa9, 0x20, 0x62, 0x61, 0x72, 0x20, 0xf0, 0x9d, 0x8c, 0x86, 0x20, 0x62, 0x61, 0x7a, 0x20, 0xe2, 0x98, 0x83, 0x20, 0x71, 0x75, 0x78}, {0x0, 0x46, 0x0, 0x4f, 0x0, 0x4f, 0x0, 0x20, 0x0, 0xa9, 0x0, 0x20, 0x0, 0x42, 0x0, 0x41, 0x0, 0x52, 0x0, 0x20, 0xff, 0xfd, 0x0, 0x20, 0x0, 0x42, 0x0, 0x41, 0x0, 0x5a, 0x0, 0x20, 0x26, 0x3, 0x0, 0x20, 0x0, 0x51, 0x0, 0x55, 0x0, 0x58}, {0x0E, 0xB9, 0x0F, 0x82, 0x0F, 0x82, 0x02, 0x09, 0x02, 0xC5, 0x02, 0x09, 0x0E, 0x4A, 0x0E, 0x33, 0x0F, 0xC0, 0x02, 0x09, 0xFF, 0xFD, 0x02, 0x09, 0x0E, 0x4A, 0x0E, 0x33, 0x10, 0x6A, 0x02, 0x09, 0x06, 0xFF, 0x02, 0x09, 0x0F, 0xB4, 0x10, 0x1F, 0x10, 0x5A}, {0x1c, 0xe5, 0x1d, 0xdd, 0x1d, 0xdd, 0x2, 0x9, 0x5, 0x84, 0x2, 0x9, 0x1c, 0x60, 0x1c, 0x47, 0x1e, 0x33, 0x2, 0x9, 0xe, 0xf0, 0x2, 0x9, 0x1c, 0x60, 0x1c, 0x47, 0x1f, 0x21, 0x2, 0x9, 0x9, 0x1b, 0x2, 0x9, 0x1e, 0x21, 0x1e, 0xb5, 0x1e, 0xff}, + {0x46, 0x6f, 0x6f, 0x20, 0xc2, 0xa9, 0x20, 0x62, 0x61, 0x72, 0x20, 0xf0, 0x9d, 0x8c, 0x86, 0x20, 0x62, 0x61, 0x7a, 0x20, 0xe2, 0x98, 0x83, 0x20, 0x71, 0x75, 0x78}, {0x46, 0x6f, 0x6f, 0x20, 0x3f, 0x20, 0x62, 0x61, 0x72, 0x20, 0x3f, 0x20, 0x62, 0x61, 0x7a, 0x20, 0x3f, 0x20, 0x71, 0x75, 0x78}, {0x46, 0x4f, 0x4f, 0x20, 0x3f, 0x20, 0x42, 0x41, 0x52, 0x20, 0x3f, 0x20, 0x42, 0x41, 0x5a, 0x20, 0x3f, 0x20, 0x51, 0x55, 0x58}, }}, - {"a ", [][]byte{{0x61, 0x20}, {0x61}, {0x0, 0x41}, {0x0E, 0x33}, {0x1c, 0x47, 0x2, 0x9}, {0x61}, {0x41}}}, + {"a ", [][]byte{{0x61, 0x20}, {0x61}, {0x0, 0x41}, {0x0E, 0x33}, {0x1c, 0x47, 0x2, 0x9}, {0x61, 0x20}, {0x61}, {0x41}}}, {"ο·»", [][]byte{ {0xEF, 0xB7, 0xBB}, {0xEF, 0xB7, 0xBB}, {0xFD, 0xFB}, {0x13, 0x5E, 0x13, 0xAB, 0x02, 0x09, 0x13, 0x5E, 0x13, 0xAB, 0x13, 0x50, 0x13, 0xAB, 0x13, 0xB7}, {0x23, 0x25, 0x23, 0x9c, 0x2, 0x9, 0x23, 0x25, 0x23, 0x9c, 0x23, 0xb, 0x23, 0x9c, 0x23, 0xb1}, + {0xEF, 0xB7, 0xBB}, {0x3f}, {0x3F}, }}, @@ -113,6 +115,7 @@ func TestUTF8CollatorKey(t *testing.T) { {0x4E, 0x2D, 0x65, 0x87}, {0xFB, 0x40, 0xCE, 0x2D, 0xFB, 0x40, 0xE5, 0x87}, {0xFB, 0x40, 0xCE, 0x2D, 0xfB, 0x40, 0xE5, 0x87}, + {0xE4, 0xB8, 0xAD, 0xE6, 0x96, 0x87}, {0xD6, 0xD0, 0xCE, 0xC4}, {0xD3, 0x21, 0xC1, 0xAD}, }}, @@ -122,6 +125,7 @@ func TestUTF8CollatorKey(t *testing.T) { {0xac, 0x1f, 0xac, 0x10, 0x0, 0x31}, {0xfb, 0xc1, 0xac, 0x1f, 0xfb, 0xc1, 0xac, 0x10, 0xe, 0x2a}, {0x3b, 0xf5, 0x3c, 0x74, 0x3c, 0xd3, 0x3b, 0xf5, 0x3c, 0x73, 0x3c, 0xe0, 0x1c, 0x3e}, + {0xea, 0xb0, 0x9f, 0xea, 0xb0, 0x90, 0x31}, {0x3f, 0x3f, 0x31}, {0x3f, 0x3f, 0x31}, }}, @@ -131,6 +135,7 @@ func TestUTF8CollatorKey(t *testing.T) { {0xff, 0xfd, 0xff, 0xfd}, {0xff, 0xfd, 0xff, 0xfd}, {0xfb, 0xdf, 0xff, 0xfe, 0xfb, 0xdf, 0xff, 0xff}, + {0xf3, 0xbf, 0xbf, 0xbe, 0xf3, 0xbf, 0xbf, 0xbf}, {0x3f, 0x3f}, {0x3f, 0x3f}, }}, @@ -171,6 +176,7 @@ func TestGetCollator(t *testing.T) { require.IsType(t, &unicodeCICollator{}, GetCollator("utf8_unicode_ci")) require.IsType(t, &zhPinyinTiDBASCSCollator{}, GetCollator("utf8mb4_zh_pinyin_tidb_as_cs")) require.IsType(t, &unicode0900AICICollator{}, GetCollator("utf8mb4_0900_ai_ci")) + require.IsType(t, &binCollator{}, GetCollator("utf8mb4_0900_bin")) require.IsType(t, &binPaddingCollator{}, GetCollator("default_test")) require.IsType(t, &binCollator{}, GetCollatorByID(63)) require.IsType(t, &binPaddingCollator{}, GetCollatorByID(46)) @@ -201,6 +207,7 @@ func TestGetCollator(t *testing.T) { require.IsType(t, &binCollator{}, GetCollatorByID(33)) require.IsType(t, &binCollator{}, GetCollatorByID(224)) require.IsType(t, &binCollator{}, GetCollatorByID(255)) + require.IsType(t, &binCollator{}, GetCollatorByID(309)) require.IsType(t, &binCollator{}, GetCollatorByID(192)) require.IsType(t, &binCollator{}, GetCollatorByID(2048)) require.IsType(t, &binCollator{}, GetCollatorByID(9999)) From dd593b2e032b0aa92ad1cdeaf9666f156d37a40f Mon Sep 17 00:00:00 2001 From: djshow832 Date: Tue, 22 Aug 2023 16:30:34 +0800 Subject: [PATCH 4/4] session, sessionctx: consider the dependency of sysvars for session states (#46244) close pingcap/tidb#46214 --- session/session.go | 5 +++- .../sessionstates/session_states_test.go | 22 +++++++++++++++ sessionctx/variable/sysvar.go | 8 +++--- sessionctx/variable/variable.go | 20 ++++++++++++++ sessionctx/variable/variable_test.go | 27 +++++++++++++++++++ 5 files changed, 77 insertions(+), 5 deletions(-) diff --git a/session/session.go b/session/session.go index 5d74b720b1cd9..ffb343aeb8a00 100644 --- a/session/session.go +++ b/session/session.go @@ -4315,7 +4315,10 @@ func (s *session) DecodeSessionStates(ctx context.Context, } // Decode session variables. - for name, val := range sessionStates.SystemVars { + names := variable.OrderByDependency(sessionStates.SystemVars) + // Some variables must be set before others, e.g. tidb_enable_noop_functions should be before noop variables. + for _, name := range names { + val := sessionStates.SystemVars[name] // Experimental system variables may change scope, data types, or even be removed. // We just ignore the errors and continue. if err := s.sessionVars.SetSystemVar(name, val); err != nil { diff --git a/sessionctx/sessionstates/session_states_test.go b/sessionctx/sessionstates/session_states_test.go index 66ad5f7bc7f06..bcf0da7561dd4 100644 --- a/sessionctx/sessionstates/session_states_test.go +++ b/sessionctx/sessionstates/session_states_test.go @@ -171,6 +171,28 @@ func TestSystemVars(t *testing.T) { checkStmt: "select rand()", expectedValue: "0.11641535266900002", }, + { + // tidb_enforce_mpp depends on tidb_allow_mpp. + stmts: []string{ + "set @@global.tidb_allow_mpp=0", + "set @@tidb_allow_mpp=1", + "set @@tidb_enforce_mpp=1", + }, + inSessionStates: true, + varName: variable.TiDBEnforceMPPExecution, + expectedValue: "1", + }, + { + // tx_read_only depends on tidb_enable_noop_functions. + stmts: []string{ + "set @@global.tidb_enable_noop_functions=0", + "set @@tidb_enable_noop_functions=1", + "set @@tx_read_only=1", + }, + inSessionStates: true, + varName: variable.TxReadOnly, + expectedValue: "1", + }, } if !sem.IsEnabled() { diff --git a/sessionctx/variable/sysvar.go b/sessionctx/variable/sysvar.go index 9a31b9eb15181..5292d6badbfdb 100644 --- a/sessionctx/variable/sysvar.go +++ b/sessionctx/variable/sysvar.go @@ -678,7 +678,7 @@ var defaultSysVars = []*SysVar{ (*SetPDClientDynamicOption.Load())(TiDBEnableTSOFollowerProxy, val) return nil }}, - {Scope: ScopeGlobal, Name: TiDBEnableLocalTxn, Value: BoolToOnOff(DefTiDBEnableLocalTxn), Hidden: true, Type: TypeBool, GetGlobal: func(_ context.Context, sv *SessionVars) (string, error) { + {Scope: ScopeGlobal, Name: TiDBEnableLocalTxn, Value: BoolToOnOff(DefTiDBEnableLocalTxn), Hidden: true, Type: TypeBool, Depended: true, GetGlobal: func(_ context.Context, sv *SessionVars) (string, error) { return BoolToOnOff(EnableLocalTxn.Load()), nil }, SetGlobal: func(_ context.Context, s *SessionVars, val string) error { oldVal := EnableLocalTxn.Load() @@ -803,7 +803,7 @@ var defaultSysVars = []*SysVar{ return nil }}, {Scope: ScopeGlobal, Name: TiDBEnableTelemetry, Value: BoolToOnOff(DefTiDBEnableTelemetry), Type: TypeBool}, - {Scope: ScopeGlobal, Name: TiDBEnableHistoricalStats, Value: On, Type: TypeBool}, + {Scope: ScopeGlobal, Name: TiDBEnableHistoricalStats, Value: On, Type: TypeBool, Depended: true}, /* tikv gc metrics */ {Scope: ScopeGlobal, Name: TiDBGCEnable, Value: On, Type: TypeBool, GetGlobal: func(_ context.Context, s *SessionVars) (string, error) { return getTiDBTableValue(s, "tikv_gc_enable", On) @@ -1549,7 +1549,7 @@ var defaultSysVars = []*SysVar{ }}, {Scope: ScopeGlobal | ScopeSession, Name: BlockEncryptionMode, Value: "aes-128-ecb", Type: TypeEnum, PossibleValues: []string{"aes-128-ecb", "aes-192-ecb", "aes-256-ecb", "aes-128-cbc", "aes-192-cbc", "aes-256-cbc", "aes-128-ofb", "aes-192-ofb", "aes-256-ofb", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb"}}, /* TiDB specific variables */ - {Scope: ScopeGlobal | ScopeSession, Name: TiDBAllowMPPExecution, Type: TypeBool, Value: BoolToOnOff(DefTiDBAllowMPPExecution), SetSession: func(s *SessionVars, val string) error { + {Scope: ScopeGlobal | ScopeSession, Name: TiDBAllowMPPExecution, Type: TypeBool, Value: BoolToOnOff(DefTiDBAllowMPPExecution), Depended: true, SetSession: func(s *SessionVars, val string) error { s.allowMPPExecution = TiDBOptOn(val) return nil }}, @@ -1893,7 +1893,7 @@ var defaultSysVars = []*SysVar{ s.TiDBOptJoinReorderThreshold = tidbOptPositiveInt32(val, DefTiDBOptJoinReorderThreshold) return nil }}, - {Scope: ScopeGlobal | ScopeSession, Name: TiDBEnableNoopFuncs, Value: DefTiDBEnableNoopFuncs, Type: TypeEnum, PossibleValues: []string{Off, On, Warn}, Validation: func(vars *SessionVars, normalizedValue string, originalValue string, scope ScopeFlag) (string, error) { + {Scope: ScopeGlobal | ScopeSession, Name: TiDBEnableNoopFuncs, Value: DefTiDBEnableNoopFuncs, Type: TypeEnum, PossibleValues: []string{Off, On, Warn}, Depended: true, Validation: func(vars *SessionVars, normalizedValue string, originalValue string, scope ScopeFlag) (string, error) { // The behavior is very weird if someone can turn TiDBEnableNoopFuncs OFF, but keep any of the following on: // TxReadOnly, TransactionReadOnly, OfflineMode, SuperReadOnly, serverReadOnly, SQLAutoIsNull // To prevent this strange position, prevent setting to OFF when any of these sysVars are ON of the same scope. diff --git a/sessionctx/variable/variable.go b/sessionctx/variable/variable.go index 38457a4f5687f..ea570963d4b01 100644 --- a/sessionctx/variable/variable.go +++ b/sessionctx/variable/variable.go @@ -155,6 +155,10 @@ type SysVar struct { // GetStateValue gets the value for session states, which is used for migrating sessions. // We need a function to override GetSession sometimes, because GetSession may not return the real value. GetStateValue func(*SessionVars) (string, bool, error) + // Depended indicates whether other variables depend on this one. That is, if this one is not correctly set, + // another variable cannot be set either. + // This flag is used to decide the order to replay session variables. + Depended bool // skipInit defines if the sysvar should be loaded into the session on init. // This is only important to set for sysvars that include session scope, // since global scoped sysvars are not-applicable. @@ -614,6 +618,22 @@ func GetSysVars() map[string]*SysVar { return m } +// OrderByDependency orders the vars by dependency. The depended sys vars are in the front. +// Unknown sys vars are treated as not depended. +func OrderByDependency(names map[string]string) []string { + depended, notDepended := make([]string, 0, len(names)), make([]string, 0, len(names)) + sysVarsLock.RLock() + defer sysVarsLock.RUnlock() + for name := range names { + if sv, ok := sysVars[name]; ok && sv.Depended { + depended = append(depended, name) + } else { + notDepended = append(notDepended, name) + } + } + return append(depended, notDepended...) +} + func init() { sysVars = make(map[string]*SysVar) for _, v := range defaultSysVars { diff --git a/sessionctx/variable/variable_test.go b/sessionctx/variable/variable_test.go index 0c61d4e85b890..89da5597ee8fd 100644 --- a/sessionctx/variable/variable_test.go +++ b/sessionctx/variable/variable_test.go @@ -19,11 +19,13 @@ import ( "encoding/json" "fmt" "runtime" + "slices" "strings" "testing" "time" "github.com/pingcap/tidb/config" + "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/parser/mysql" "github.com/pingcap/tidb/parser/terror" "github.com/pingcap/tidb/types" @@ -687,3 +689,28 @@ func TestTimeValidationWithTimezone(t *testing.T) { require.NoError(t, err) require.Equal(t, "23:59 +0800", val) } + +func TestOrderByDependency(t *testing.T) { + // Some other exceptions: + // - tidb_snapshot and tidb_read_staleness can not be set at the same time. It doesn't affect dependency. + vars := map[string]string{ + "unknown": "1", + TxReadOnly: "1", + SQLAutoIsNull: "1", + TiDBEnableNoopFuncs: "1", + TiDBEnforceMPPExecution: "1", + TiDBAllowMPPExecution: "1", + TiDBTxnScope: kv.LocalTxnScope, + TiDBEnableLocalTxn: "1", + TiDBEnablePlanReplayerContinuousCapture: "1", + TiDBEnableHistoricalStats: "1", + } + names := OrderByDependency(vars) + require.Greater(t, slices.Index(names, TxReadOnly), slices.Index(names, TiDBEnableNoopFuncs)) + require.Greater(t, slices.Index(names, SQLAutoIsNull), slices.Index(names, TiDBEnableNoopFuncs)) + require.Greater(t, slices.Index(names, TiDBEnforceMPPExecution), slices.Index(names, TiDBAllowMPPExecution)) + // Depended variables below are global variables, so actually it doesn't matter. + require.Greater(t, slices.Index(names, TiDBTxnScope), slices.Index(names, TiDBEnableLocalTxn)) + require.Greater(t, slices.Index(names, TiDBEnablePlanReplayerContinuousCapture), slices.Index(names, TiDBEnableHistoricalStats)) + require.Contains(t, names, "unknown") +}