From 2561314d7a4782af0777ce768310c2b751901ad9 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Thu, 18 May 2023 18:45:36 +0800 Subject: [PATCH] partition: fix split and scatter region for truncate partition (#43271) (#43743) close pingcap/tidb#43028, close pingcap/tidb#43174 --- ddl/db_partition_test.go | 33 ++++++++++++++++++++++++++ ddl/ddl_api.go | 50 ++++++++++++++++++++++++---------------- 2 files changed, 63 insertions(+), 20 deletions(-) diff --git a/ddl/db_partition_test.go b/ddl/db_partition_test.go index 7b9e2f5a3e0b7..90d98b663c0da 100644 --- a/ddl/db_partition_test.go +++ b/ddl/db_partition_test.go @@ -1537,6 +1537,39 @@ func TestAlterTableTruncatePartitionByListColumns(t *testing.T) { tk.MustQuery("select * from t").Check(testkit.Rows()) } +func TestAlterTableTruncatePartitionPreSplitRegion(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + atomic.StoreUint32(&ddl.EnableSplitTableRegion, 1) + tk.MustExec("set @@global.tidb_scatter_region=1;") + tk.MustExec("use test;") + + tk.MustExec("drop table if exists t1;") + tk.MustExec(`CREATE TABLE t1 (id int, c varchar(128), key c(c)) partition by range (id) ( + partition p0 values less than (10), + partition p1 values less than MAXVALUE)`) + re := tk.MustQuery("show table t1 regions") + rows := re.Rows() + require.Len(t, rows, 2) + tk.MustExec(`alter table t1 truncate partition p0`) + re = tk.MustQuery("show table t1 regions") + rows = re.Rows() + require.Len(t, rows, 2) + + tk.MustExec("drop table if exists t2;") + tk.MustExec(`CREATE TABLE t2(id bigint(20) NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) NONCLUSTERED) SHARD_ROW_ID_BITS=4 PRE_SPLIT_REGIONS=3 PARTITION BY RANGE (id) ( + PARTITION p1 VALUES LESS THAN (10), + PARTITION p2 VALUES LESS THAN (20), + PARTITION p3 VALUES LESS THAN (MAXVALUE))`) + re = tk.MustQuery("show table t2 regions") + rows = re.Rows() + require.Len(t, rows, 24) + tk.MustExec(`alter table t2 truncate partition p3`) + re = tk.MustQuery("show table t2 regions") + rows = re.Rows() + require.Len(t, rows, 24) +} + func TestCreateTableWithKeyPartition(t *testing.T) { store := testkit.CreateMockStore(t, mockstore.WithDDLChecker()) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index eb2e20df13b63..4509aa0d954e9 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -4232,30 +4232,35 @@ func (d *ddl) TruncateTablePartition(ctx sessionctx.Context, ident ast.Ident, sp return errors.Trace(dbterror.ErrPartitionMgmtOnNonpartitioned) } - var pids []int64 - if spec.OnAllPartitions { - pids = make([]int64, len(meta.GetPartitionInfo().Definitions)) - for i, def := range meta.GetPartitionInfo().Definitions { - pids[i] = def.ID + getTruncatedParts := func(pi *model.PartitionInfo) (*model.PartitionInfo, error) { + if spec.OnAllPartitions { + return pi.Clone(), nil } - } else { + var defs []model.PartitionDefinition // MySQL allows duplicate partition names in truncate partition // so we filter them out through a hash - pidMap := make(map[int64]bool) + posMap := make(map[int]bool) for _, name := range spec.PartitionNames { - pid, err := tables.FindPartitionByName(meta, name.L) - if err != nil { - return errors.Trace(err) + pos := pi.FindPartitionDefinitionByName(name.L) + if pos < 0 { + return nil, errors.Trace(table.ErrUnknownPartition.GenWithStackByArgs(name.L, ident.Name.O)) + } + if _, ok := posMap[pos]; !ok { + defs = append(defs, pi.Definitions[pos]) + posMap[pos] = true } - pidMap[pid] = true - } - // linter makezero does not handle changing pids to zero length, - // so create a new var and then assign to pids... - newPids := make([]int64, 0, len(pidMap)) - for pid := range pidMap { - newPids = append(newPids, pid) } - pids = newPids + pi = pi.Clone() + pi.Definitions = defs + return pi, nil + } + pi, err := getTruncatedParts(meta.GetPartitionInfo()) + if err != nil { + return err + } + pids := make([]int64, 0, len(pi.Definitions)) + for i := range pi.Definitions { + pids = append(pids, pi.Definitions[i].ID) } job := &model.Job{ @@ -4269,11 +4274,16 @@ func (d *ddl) TruncateTablePartition(ctx sessionctx.Context, ident ast.Ident, sp } err = d.DoDDLJob(ctx, job) + err = d.callHookOnChanged(job, err) if err != nil { return errors.Trace(err) } - err = d.callHookOnChanged(job, err) - return errors.Trace(err) + if _, tb, err := d.getSchemaAndTableByIdent(ctx, ident); err == nil { + if p, err := getTruncatedParts(tb.Meta().GetPartitionInfo()); err == nil { + d.preSplitAndScatter(ctx, tb.Meta(), p) + } + } + return nil } func (d *ddl) DropTablePartition(ctx sessionctx.Context, ident ast.Ident, spec *ast.AlterTableSpec) error {