Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ddl: add syntax for setting the cache step of auto id explicitly. (#15409) #16287

Merged
merged 6 commits into from
Apr 28, 2020
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
105 changes: 105 additions & 0 deletions ddl/db_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package ddl_test
import (
"context"
"fmt"
"strconv"
"strings"
"sync/atomic"
"time"
Expand Down Expand Up @@ -1935,3 +1936,107 @@ func (s *testIntegrationSuite3) TestForeignKeyOnUpdateOnDelete(c *C) {
tk.MustExec("create table t5 (a int, b int, foreign key (b) references t (a) on update restrict)")
tk.MustExec("create table t6 (a int, b int, foreign key (b) references t (a) on update restrict on delete restrict)")
}

// TestCreateTableWithAutoIdCache test the auto_id_cache table option.
// `auto_id_cache` take effects on handle too when `PKIshandle` is false,
// or even there is no auto_increment column at all.
func (s *testIntegrationSuite3) TestCreateTableWithAutoIdCache(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("USE test;")
tk.MustExec("drop table if exists t;")
tk.MustExec("drop table if exists t1;")

// Test primary key is handle.
tk.MustExec("create table t(a int auto_increment key) auto_id_cache 100")
tblInfo, err := s.dom.InfoSchema().TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
c.Assert(err, IsNil)
c.Assert(tblInfo.Meta().AutoIdCache, Equals, int64(100))
tk.MustExec("insert into t values()")
tk.MustQuery("select * from t").Check(testkit.Rows("1"))
tk.MustExec("delete from t")

// Invalid the allocator cache, insert will trigger a new cache
tk.MustExec("rename table t to t1;")
tk.MustExec("insert into t1 values()")
tk.MustQuery("select * from t1").Check(testkit.Rows("101"))

// Test primary key is not handle.
tk.MustExec("drop table if exists t;")
tk.MustExec("drop table if exists t1;")
tk.MustExec("create table t(a int) auto_id_cache 100")
tblInfo, err = s.dom.InfoSchema().TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
c.Assert(err, IsNil)

tk.MustExec("insert into t values()")
tk.MustQuery("select _tidb_rowid from t").Check(testkit.Rows("1"))
tk.MustExec("delete from t")

// Invalid the allocator cache, insert will trigger a new cache
tk.MustExec("rename table t to t1;")
tk.MustExec("insert into t1 values()")
tk.MustQuery("select _tidb_rowid from t1").Check(testkit.Rows("101"))

// Test both auto_increment and rowid exist.
tk.MustExec("drop table if exists t;")
tk.MustExec("drop table if exists t1;")
tk.MustExec("create table t(a int null, b int auto_increment unique) auto_id_cache 100")
tblInfo, err = s.dom.InfoSchema().TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
c.Assert(err, IsNil)

tk.MustExec("insert into t(b) values(NULL)")
tk.MustQuery("select b, _tidb_rowid from t").Check(testkit.Rows("1 2"))
tk.MustExec("delete from t")

// Invalid the allocator cache, insert will trigger a new cache.
tk.MustExec("rename table t to t1;")
tk.MustExec("insert into t1(b) values(NULL)")
tk.MustQuery("select b, _tidb_rowid from t1").Check(testkit.Rows("101 102"))
tk.MustExec("delete from t1")

// Test alter auto_id_cache.
tk.MustExec("alter table t1 auto_id_cache 200")
tblInfo, err = s.dom.InfoSchema().TableByName(model.NewCIStr("test"), model.NewCIStr("t1"))
c.Assert(err, IsNil)
c.Assert(tblInfo.Meta().AutoIdCache, Equals, int64(200))

tk.MustExec("insert into t1(b) values(NULL)")
tk.MustQuery("select b, _tidb_rowid from t1").Check(testkit.Rows("201 202"))
tk.MustExec("delete from t1")

// Invalid the allocator cache, insert will trigger a new cache.
tk.MustExec("rename table t1 to t;")
tk.MustExec("insert into t(b) values(NULL)")
tk.MustQuery("select b, _tidb_rowid from t").Check(testkit.Rows("401 402"))
tk.MustExec("delete from t")

tk.MustExec("drop table if exists t;")
tk.MustExec("drop table if exists t1;")
tk.MustExec("create table t(a int auto_increment key) auto_id_cache 3")
tblInfo, err = s.dom.InfoSchema().TableByName(model.NewCIStr("test"), model.NewCIStr("t"))
c.Assert(err, IsNil)
c.Assert(tblInfo.Meta().AutoIdCache, Equals, int64(3))

// Test insert batch size(4 here) greater than the customized autoid step(3 here).
tk.MustExec("insert into t(a) values(NULL),(NULL),(NULL),(NULL)")
tk.MustQuery("select a from t").Check(testkit.Rows("1", "2", "3", "4"))
tk.MustExec("delete from t")

// Invalid the allocator cache, insert will trigger a new cache.
tk.MustExec("rename table t to t1;")
tk.MustExec("insert into t1(a) values(NULL)")
next := tk.MustQuery("select a from t1").Rows()[0][0].(string)
nextInt, err := strconv.Atoi(next)
c.Assert(err, IsNil)
c.Assert(nextInt, Greater, 5)

// Test auto_id_cache overflows int64.
tk.MustExec("drop table if exists t;")
_, err = tk.Exec("create table t(a int) auto_id_cache = 9223372036854775808")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "table option auto_id_cache overflows int64")

tk.MustExec("create table t(a int) auto_id_cache = 9223372036854775807")
_, err = tk.Exec("alter table t auto_id_cache = 9223372036854775808")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "table option auto_id_cache overflows int64")
}
41 changes: 40 additions & 1 deletion ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"bytes"
"context"
"fmt"
"math"
"strconv"
"strings"
"sync/atomic"
Expand Down Expand Up @@ -1747,7 +1748,12 @@ func checkCharsetAndCollation(cs string, co string) error {
// handleAutoIncID handles auto_increment option in DDL. It creates a ID counter for the table and initiates the counter to a proper value.
// For example if the option sets auto_increment to 10. The counter will be set to 9. So the next allocated ID will be 10.
func (d *ddl) handleAutoIncID(tbInfo *model.TableInfo, schemaID int64) error {
alloc := autoid.NewAllocator(d.store, tbInfo.GetDBID(schemaID), tbInfo.IsAutoIncColUnsigned())
var alloc autoid.Allocator
if tbInfo.AutoIdCache > 0 {
alloc = autoid.NewAllocator(d.store, tbInfo.GetDBID(schemaID), tbInfo.IsAutoIncColUnsigned(), autoid.CustomAutoIncCacheOption(tbInfo.AutoIdCache))
} else {
alloc = autoid.NewAllocator(d.store, tbInfo.GetDBID(schemaID), tbInfo.IsAutoIncColUnsigned())
}
tbInfo.State = model.StatePublic
tb, err := table.TableFromMeta(alloc, tbInfo)
if err != nil {
Expand Down Expand Up @@ -1783,6 +1789,12 @@ func handleTableOptions(options []*ast.TableOption, tbInfo *model.TableInfo) err
switch op.Tp {
case ast.TableOptionAutoIncrement:
tbInfo.AutoIncID = int64(op.UintValue)
case ast.TableOptionAutoIdCache:
if op.UintValue > uint64(math.MaxInt64) {
// TODO: Refine this error.
return errors.New("table option auto_id_cache overflows int64")
}
tbInfo.AutoIdCache = int64(op.UintValue)
case ast.TableOptionComment:
tbInfo.Comment = op.StrValue
case ast.TableOptionCompression:
Expand Down Expand Up @@ -1967,6 +1979,12 @@ func (d *ddl) AlterTable(ctx sessionctx.Context, ident ast.Ident, specs []*ast.A
err = d.ShardRowID(ctx, ident, opt.UintValue)
case ast.TableOptionAutoIncrement:
err = d.RebaseAutoID(ctx, ident, int64(opt.UintValue))
case ast.TableOptionAutoIdCache:
if opt.UintValue > uint64(math.MaxInt64) {
// TODO: Refine this error.
return errors.New("table option auto_id_cache overflows int64")
}
err = d.AlterTableAutoIDCache(ctx, ident, int64(opt.UintValue))
case ast.TableOptionComment:
spec.Comment = opt.StrValue
err = d.AlterTableComment(ctx, ident, spec)
Expand Down Expand Up @@ -2879,6 +2897,27 @@ func (d *ddl) AlterTableComment(ctx sessionctx.Context, ident ast.Ident, spec *a
return errors.Trace(err)
}

// AlterTableAutoIDCache updates the table comment information.
func (d *ddl) AlterTableAutoIDCache(ctx sessionctx.Context, ident ast.Ident, newCache int64) error {
schema, tb, err := d.getSchemaAndTableByIdent(ctx, ident)
if err != nil {
return errors.Trace(err)
}

job := &model.Job{
SchemaID: schema.ID,
TableID: tb.Meta().ID,
SchemaName: schema.Name.L,
Type: model.ActionModifyTableAutoIdCache,
BinlogInfo: &model.HistoryInfo{},
Args: []interface{}{newCache},
}

err = d.doDDLJob(ctx, job)
err = d.callHookOnChanged(err)
return errors.Trace(err)
}

// AlterTableCharset changes the table charset and collate.
func (d *ddl) AlterTableCharsetAndCollate(ctx sessionctx.Context, ident ast.Ident, toCharset, toCollate string) error {
// use the last one.
Expand Down
2 changes: 2 additions & 0 deletions ddl/ddl_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,8 @@ func (w *worker) runDDLJob(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64,
ver, err = w.onShardRowID(d, t, job)
case model.ActionModifyTableComment:
ver, err = onModifyTableComment(t, job)
case model.ActionModifyTableAutoIdCache:
ver, err = onModifyTableAutoIDCache(t, job)
case model.ActionAddTablePartition:
ver, err = onAddTablePartition(d, t, job)
case model.ActionModifyTableCharsetAndCollate:
Expand Down
2 changes: 1 addition & 1 deletion ddl/rollingback.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ func convertJob2RollbackJob(w *worker, d *ddlCtx, t *meta.Meta, job *model.Job)
model.ActionModifyColumn, model.ActionAddForeignKey,
model.ActionDropForeignKey, model.ActionRenameTable,
model.ActionModifyTableCharsetAndCollate, model.ActionTruncateTablePartition,
model.ActionModifySchemaCharsetAndCollate:
model.ActionModifySchemaCharsetAndCollate, model.ActionModifyTableAutoIdCache:
ver, err = cancelOnlyNotHandledJob(job)
default:
job.State = model.JobStateCancelled
Expand Down
28 changes: 27 additions & 1 deletion ddl/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,12 @@ func checkSafePoint(w *worker, snapshotTS uint64) error {
}

func getTable(store kv.Storage, schemaID int64, tblInfo *model.TableInfo) (table.Table, error) {
alloc := autoid.NewAllocator(store, tblInfo.GetDBID(schemaID), tblInfo.IsAutoIncColUnsigned())
var alloc autoid.Allocator
if tblInfo.AutoIdCache > 0 {
alloc = autoid.NewAllocator(store, tblInfo.GetDBID(schemaID), tblInfo.IsAutoIncColUnsigned(), autoid.CustomAutoIncCacheOption(tblInfo.AutoIdCache))
} else {
alloc = autoid.NewAllocator(store, tblInfo.GetDBID(schemaID), tblInfo.IsAutoIncColUnsigned())
}
tbl, err := table.TableFromMeta(alloc, tblInfo)
return tbl, errors.Trace(err)
}
Expand Down Expand Up @@ -487,6 +492,27 @@ func onRebaseAutoID(store kv.Storage, t *meta.Meta, job *model.Job) (ver int64,
return ver, nil
}

func onModifyTableAutoIDCache(t *meta.Meta, job *model.Job) (int64, error) {
var cache int64
if err := job.DecodeArgs(&cache); err != nil {
job.State = model.JobStateCancelled
return 0, errors.Trace(err)
}

tblInfo, err := getTableInfoAndCancelFaultJob(t, job, job.SchemaID)
if err != nil {
return 0, errors.Trace(err)
}

tblInfo.AutoIdCache = cache
ver, err := updateVersionAndTableInfo(t, job, tblInfo, true)
if err != nil {
return ver, errors.Trace(err)
}
job.FinishTableJob(model.JobStateDone, model.StatePublic, ver, tblInfo)
return ver, nil
}

func (w *worker) onShardRowID(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error) {
var shardRowIDBits uint64
err := job.DecodeArgs(&shardRowIDBits)
Expand Down
4 changes: 4 additions & 0 deletions executor/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,10 @@ func (e *ShowExec) fetchShowCreateTable() error {
}
}

if tb.Meta().AutoIdCache != 0 {
fmt.Fprintf(&buf, " /*T![auto_id_cache] AUTO_ID_CACHE=%d */", tb.Meta().AutoIdCache)
}

if tb.Meta().ShardRowIDBits > 0 {
fmt.Fprintf(&buf, "/*!90000 SHARD_ROW_ID_BITS=%d ", tb.Meta().ShardRowIDBits)
if tb.Meta().PreSplitRegions > 0 {
Expand Down
37 changes: 37 additions & 0 deletions executor/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,43 @@ func (s *testSuite2) TestShowCreateTable(c *C) {
))
}

// Override testSuite2 to test auto id cache.
func (s *testSuite2) TestAutoIdCache(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("use test")

tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int auto_increment key) auto_id_cache = 10")
tk.MustQuery("show create table t").Check(testutil.RowsWithSep("|",
""+
"t CREATE TABLE `t` (\n"+
" `a` int(11) NOT NULL AUTO_INCREMENT,\n"+
" PRIMARY KEY (`a`)\n"+
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin /*T![auto_id_cache] AUTO_ID_CACHE=10 */",
))
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int auto_increment unique, b int key) auto_id_cache 100")
tk.MustQuery("show create table t").Check(testutil.RowsWithSep("|",
""+
"t CREATE TABLE `t` (\n"+
" `a` int(11) NOT NULL AUTO_INCREMENT,\n"+
" `b` int(11) NOT NULL,\n"+
" PRIMARY KEY (`b`),\n"+
" UNIQUE KEY `a` (`a`)\n"+
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin /*T![auto_id_cache] AUTO_ID_CACHE=100 */",
))
tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int key) auto_id_cache 5")
tk.MustQuery("show create table t").Check(testutil.RowsWithSep("|",
""+
"t CREATE TABLE `t` (\n"+
" `a` int(11) NOT NULL,\n"+
" PRIMARY KEY (`a`)\n"+
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin /*T![auto_id_cache] AUTO_ID_CACHE=5 */",
))
tk.MustExec("drop table if exists t")
}

func (s *testSuite2) TestShowEscape(c *C) {
tk := testkit.NewTestKit(c, s.store)

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ require (
github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e
github.com/pingcap/kvproto v0.0.0-20200311073257-e53d835099b0
github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd
github.com/pingcap/parser v3.0.13-0.20200428065913-b93e38b9c865+incompatible
github.com/pingcap/parser v3.0.13-0.20200428073321-7e525711e35d+incompatible
github.com/pingcap/pd v1.1.0-beta.0.20191223090411-ea2b748f6ee2
github.com/pingcap/tidb-tools v3.0.6-0.20191119150227-ff0a3c6e5763+incompatible
github.com/pingcap/tipb v0.0.0-20200401051346-bec3080a5428
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ github.com/pingcap/kvproto v0.0.0-20200311073257-e53d835099b0 h1:dXXNHvDwAEN1YNg
github.com/pingcap/kvproto v0.0.0-20200311073257-e53d835099b0/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY=
github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd h1:hWDol43WY5PGhsh3+8794bFHY1bPrmu6bTalpssCrGg=
github.com/pingcap/log v0.0.0-20190715063458-479153f07ebd/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw=
github.com/pingcap/parser v3.0.13-0.20200428065913-b93e38b9c865+incompatible h1:rW5mMhtEXf8A/Kx+1l48x3N6RWJ4zXmqoE925YH3Vqg=
github.com/pingcap/parser v3.0.13-0.20200428065913-b93e38b9c865+incompatible/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/parser v3.0.13-0.20200428073321-7e525711e35d+incompatible h1:t/vYVkoW99IdMdDKCL1SbvHRvsbcg5fwTatehu2iDoU=
github.com/pingcap/parser v3.0.13-0.20200428073321-7e525711e35d+incompatible/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/pd v1.1.0-beta.0.20191223090411-ea2b748f6ee2 h1:NL23b8tsg6M1QpSQedK14/Jx++QeyKL2rGiBvXAQVfA=
github.com/pingcap/pd v1.1.0-beta.0.20191223090411-ea2b748f6ee2/go.mod h1:b4gaAPSxaVVtaB+EHamV4Nsv8JmTdjlw0cTKmp4+dRQ=
github.com/pingcap/tidb-tools v3.0.6-0.20191119150227-ff0a3c6e5763+incompatible h1:I8HirWsu1MZp6t9G/g8yKCEjJJxtHooKakEgccvdJ4M=
Expand Down
15 changes: 12 additions & 3 deletions infoschema/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func (b *Builder) ApplyDiff(m *meta.Meta, diff *model.SchemaDiff) ([]int64, erro
// We try to reuse the old allocator, so the cached auto ID can be reused.
var alloc autoid.Allocator
if tableIDIsValid(oldTableID) {
if oldTableID == newTableID && diff.Type != model.ActionRenameTable && diff.Type != model.ActionRebaseAutoID {
if oldTableID == newTableID && diff.Type != model.ActionRenameTable && diff.Type != model.ActionRebaseAutoID && diff.Type != model.ActionModifyTableAutoIdCache {
alloc, _ = b.is.AllocByID(oldTableID)
}

Expand Down Expand Up @@ -213,7 +213,11 @@ func (b *Builder) applyCreateTable(m *meta.Meta, dbInfo *model.DBInfo, tableID i

if alloc == nil {
schemaID := dbInfo.ID
alloc = autoid.NewAllocator(b.handle.store, tblInfo.GetDBID(schemaID), tblInfo.IsAutoIncColUnsigned())
if tblInfo.AutoIdCache > 0 {
alloc = autoid.NewAllocator(b.handle.store, tblInfo.GetDBID(schemaID), tblInfo.IsAutoIncColUnsigned(), autoid.CustomAutoIncCacheOption(tblInfo.AutoIdCache))
} else {
alloc = autoid.NewAllocator(b.handle.store, tblInfo.GetDBID(schemaID), tblInfo.IsAutoIncColUnsigned())
}
}
tbl, err := tables.TableFromMeta(alloc, tblInfo)
if err != nil {
Expand Down Expand Up @@ -360,7 +364,12 @@ func (b *Builder) createSchemaTablesForDB(di *model.DBInfo, tableFromMeta tableF
b.is.schemaMap[di.Name.L] = schTbls
for _, t := range di.Tables {
schemaID := di.ID
alloc := autoid.NewAllocator(b.handle.store, t.GetDBID(schemaID), t.IsAutoIncColUnsigned())
var alloc autoid.Allocator
if t.AutoIdCache > 0 {
alloc = autoid.NewAllocator(b.handle.store, t.GetDBID(schemaID), t.IsAutoIncColUnsigned(), autoid.CustomAutoIncCacheOption(t.AutoIdCache))
} else {
alloc = autoid.NewAllocator(b.handle.store, t.GetDBID(schemaID), t.IsAutoIncColUnsigned())
}
var tbl table.Table
tbl, err := tableFromMeta(alloc, t)
if err != nil {
Expand Down
Loading