From d41baf2ce2a923ff951e36bac4d61b8c9c2e5391 Mon Sep 17 00:00:00 2001 From: tiancaiamao Date: Mon, 22 Apr 2019 16:48:19 +0800 Subject: [PATCH 1/4] ddl: pre-split region for partitioned table --- ddl/table.go | 10 +++++++++- ddl/table_split_test.go | 29 ++++++++++++++++++++++++----- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/ddl/table.go b/ddl/table.go index 7cb63bf6e6915..49cc37c8be4b9 100644 --- a/ddl/table.go +++ b/ddl/table.go @@ -72,7 +72,15 @@ func onCreateTable(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error) } if atomic.LoadUint32(&EnableSplitTableRegion) != 0 { // TODO: Add restrictions to this operation. - go splitTableRegion(d.store, tbInfo.ID) + pi := tbInfo.GetPartitionInfo() + if pi != nil { + // Max partition count is 4096, should we sample and just choose some of the partition to split? + for _, def := range pi.Definitions { + go splitTableRegion(d.store, def.ID) + } + } else { + go splitTableRegion(d.store, tbInfo.ID) + } } // Finish this job. job.FinishTableJob(model.JobStateDone, model.StatePublic, ver, tbInfo) diff --git a/ddl/table_split_test.go b/ddl/table_split_test.go index ca6aa9b97d236..31c67c5fb2cd0 100644 --- a/ddl/table_split_test.go +++ b/ddl/table_split_test.go @@ -26,6 +26,7 @@ import ( "github.com/pingcap/tidb/store/mockstore" "github.com/pingcap/tidb/store/tikv" "github.com/pingcap/tidb/tablecodec" + "github.com/pingcap/tidb/util/testkit" ) type testDDLTableSplitSuite struct{} @@ -41,21 +42,39 @@ func (s *testDDLTableSplitSuite) TestTableSplit(c *C) { atomic.StoreUint32(&ddl.EnableSplitTableRegion, 1) dom, err := session.BootstrapSession(store) c.Assert(err, IsNil) + tk := testkit.NewTestKit(c, store) + tk.MustExec("use test") + tk.MustExec(`create table t_part (a int key) partition by range(a) ( + partition p0 values less than (10), + partition p1 values less than (20) + )`) defer dom.Close() atomic.StoreUint32(&ddl.EnableSplitTableRegion, 0) infoSchema := dom.InfoSchema() c.Assert(infoSchema, NotNil) t, err := infoSchema.TableByName(model.NewCIStr("mysql"), model.NewCIStr("tidb")) c.Assert(err, IsNil) - regionStartKey := tablecodec.EncodeTablePrefix(t.Meta().ID) + checkRegionStartWithTableID(c, t.Meta().ID, store.(kvStore)) - type kvStore interface { - GetRegionCache() *tikv.RegionCache + t, err = infoSchema.TableByName(model.NewCIStr("test"), model.NewCIStr("t_part")) + c.Assert(err, IsNil) + pi := t.Meta().GetPartitionInfo() + c.Assert(pi, NotNil) + for _, def := range pi.Definitions { + checkRegionStartWithTableID(c, def.ID, store.(kvStore)) } +} + +type kvStore interface { + GetRegionCache() *tikv.RegionCache +} + +func checkRegionStartWithTableID(c *C, id int64, store kvStore) { + regionStartKey := tablecodec.EncodeTablePrefix(id) var loc *tikv.KeyLocation for i := 0; i < 10; i++ { - cache := store.(kvStore).GetRegionCache() - loc, err = cache.LocateKey(tikv.NewBackoffer(context.Background(), 5000), regionStartKey) + cache := store.GetRegionCache() + loc, err := cache.LocateKey(tikv.NewBackoffer(context.Background(), 5000), regionStartKey) c.Assert(err, IsNil) // Region cache may be out of date, so we need to drop this expired region and load it again. From bdab34c0a42e4b66b756ee6a9dc63d0e039adc70 Mon Sep 17 00:00:00 2001 From: tiancaiamao Date: Tue, 23 Apr 2019 23:24:07 +0800 Subject: [PATCH 2/4] address comment --- ddl/table.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ddl/table.go b/ddl/table.go index 49cc37c8be4b9..d8b66a1cc38a5 100644 --- a/ddl/table.go +++ b/ddl/table.go @@ -75,9 +75,11 @@ func onCreateTable(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error) pi := tbInfo.GetPartitionInfo() if pi != nil { // Max partition count is 4096, should we sample and just choose some of the partition to split? - for _, def := range pi.Definitions { - go splitTableRegion(d.store, def.ID) - } + go func(pi *model.PartitionInfo) { + for _, def := range pi.Definitions { + splitTableRegion(d.store, def.ID) + } + }(pi) } else { go splitTableRegion(d.store, tbInfo.ID) } From 9d336c2eed7298e3e2673ea7d680f7e4e12a58b1 Mon Sep 17 00:00:00 2001 From: tiancaiamao Date: Wed, 24 Apr 2019 09:53:49 +0800 Subject: [PATCH 3/4] address comment --- ddl/table_split_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ddl/table_split_test.go b/ddl/table_split_test.go index 31c67c5fb2cd0..132255a986dc6 100644 --- a/ddl/table_split_test.go +++ b/ddl/table_split_test.go @@ -72,9 +72,10 @@ type kvStore interface { func checkRegionStartWithTableID(c *C, id int64, store kvStore) { regionStartKey := tablecodec.EncodeTablePrefix(id) var loc *tikv.KeyLocation + var err error for i := 0; i < 10; i++ { cache := store.GetRegionCache() - loc, err := cache.LocateKey(tikv.NewBackoffer(context.Background(), 5000), regionStartKey) + loc, err = cache.LocateKey(tikv.NewBackoffer(context.Background(), 5000), regionStartKey) c.Assert(err, IsNil) // Region cache may be out of date, so we need to drop this expired region and load it again. From 8fd783cb805b7970a97e1983fe119c6f8e1f2507 Mon Sep 17 00:00:00 2001 From: tiancaiamao Date: Thu, 25 Apr 2019 14:36:40 +0800 Subject: [PATCH 4/4] address comment --- ddl/ddl_api.go | 16 ++++++++++++++-- ddl/table.go | 22 +++++++--------------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/ddl/ddl_api.go b/ddl/ddl_api.go index d49b228c46677..fc27a1be8e2d0 100644 --- a/ddl/ddl_api.go +++ b/ddl/ddl_api.go @@ -1202,14 +1202,26 @@ func (d *ddl) CreateTable(ctx sessionctx.Context, s *ast.CreateTableStmt) (err e err = d.doDDLJob(ctx, job) if err == nil { + var preSplitAndScatter func() // do pre-split and scatter. if tbInfo.ShardRowIDBits > 0 && tbInfo.PreSplitRegions > 0 { + preSplitAndScatter = func() { preSplitTableRegion(d.store, tbInfo, ctx.GetSessionVars().WaitTableSplitFinish) } + } else if atomic.LoadUint32(&EnableSplitTableRegion) != 0 { + pi := tbInfo.GetPartitionInfo() + if pi != nil { + preSplitAndScatter = func() { splitPartitionTableRegion(d.store, pi) } + } else { + preSplitAndScatter = func() { splitTableRegion(d.store, tbInfo.ID) } + } + } + if preSplitAndScatter != nil { if ctx.GetSessionVars().WaitTableSplitFinish { - preSplitTableRegion(d.store, tbInfo, true) + preSplitAndScatter() } else { - go preSplitTableRegion(d.store, tbInfo, false) + go preSplitAndScatter() } } + if tbInfo.AutoIncID > 1 { // Default tableAutoIncID base is 0. // If the first ID is expected to greater than 1, we need to do rebase. diff --git a/ddl/table.go b/ddl/table.go index f8fa9ac20fa6d..22c8a15fe6b42 100644 --- a/ddl/table.go +++ b/ddl/table.go @@ -17,7 +17,6 @@ import ( "fmt" "strconv" "strings" - "sync/atomic" "github.com/pingcap/errors" "github.com/pingcap/failpoint" @@ -74,20 +73,6 @@ func onCreateTable(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error) if err != nil { return ver, errors.Trace(err) } - if atomic.LoadUint32(&EnableSplitTableRegion) != 0 { - // TODO: Add restrictions to this operation. - pi := tbInfo.GetPartitionInfo() - if pi != nil { - // Max partition count is 4096, should we sample and just choose some of the partition to split? - go func(pi *model.PartitionInfo) { - for _, def := range pi.Definitions { - splitTableRegion(d.store, def.ID) - } - }(pi) - } else { - go splitTableRegion(d.store, tbInfo.ID) - } - } // Finish this job. job.FinishTableJob(model.JobStateDone, model.StatePublic, ver, tbInfo) asyncNotifyEvent(d, &util.Event{Tp: model.ActionCreateTable, TableInfo: tbInfo}) @@ -350,6 +335,13 @@ type splitableStore interface { WaitScatterRegionFinish(regionID uint64) error } +func splitPartitionTableRegion(store kv.Storage, pi *model.PartitionInfo) { + // Max partition count is 4096, should we sample and just choose some of the partition to split? + for _, def := range pi.Definitions { + splitTableRegion(store, def.ID) + } +} + func splitTableRegion(store kv.Storage, tableID int64) { s, ok := store.(splitableStore) if !ok {