Skip to content

Commit

Permalink
ddl: add syntax for setting the cache step of auto id explicitly. (#1…
Browse files Browse the repository at this point in the history
  • Loading branch information
sre-bot authored Apr 28, 2020
1 parent cea3326 commit 62e8314
Show file tree
Hide file tree
Showing 15 changed files with 366 additions and 30 deletions.
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

0 comments on commit 62e8314

Please sign in to comment.