Skip to content

Commit

Permalink
ddl: fix alter table share rowid bit problem (#9868)
Browse files Browse the repository at this point in the history
  • Loading branch information
crazycs520 authored Apr 9, 2019
1 parent 826c299 commit ed3e265
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 10 deletions.
37 changes: 37 additions & 0 deletions ddl/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2671,3 +2671,40 @@ func (s *testDBSuite) TestModifyColumnCharset(c *C) {
") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin"))

}

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

tk.MustExec("use test")
// Test alter shard_row_id_bits
tk.MustExec("drop table if exists t1")
defer tk.MustExec("drop table if exists t1")
tk.MustExec("create table t1 (a int) shard_row_id_bits = 5")
tk.MustExec(fmt.Sprintf("alter table t1 auto_increment = %d;", 1<<56))
tk.MustExec("insert into t1 set a=1;")

// Test increase shard_row_id_bits failed by overflow global auto ID.
_, err := tk.Exec("alter table t1 SHARD_ROW_ID_BITS = 10;")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[autoid:1467]shard_row_id_bits 10 will cause next global auto ID overflow")

// Test reduce shard_row_id_bits will be ok.
tk.MustExec("alter table t1 SHARD_ROW_ID_BITS = 3;")
checkShardRowID := func(maxShardRowIDBits, shardRowIDBits uint64) {
tbl := testGetTableByName(c, tk.Se, "test", "t1")
c.Assert(tbl.Meta().MaxShardRowIDBits == maxShardRowIDBits, IsTrue)
c.Assert(tbl.Meta().ShardRowIDBits == shardRowIDBits, IsTrue)
}
checkShardRowID(5, 3)

// Test reduce shard_row_id_bits but calculate overflow should use the max record shard_row_id_bits.
tk.MustExec("drop table if exists t1")
tk.MustExec("create table t1 (a int) shard_row_id_bits = 10")
tk.MustExec("alter table t1 SHARD_ROW_ID_BITS = 5;")
checkShardRowID(10, 5)
tk.MustExec(fmt.Sprintf("alter table t1 auto_increment = %d;", 1<<56))
_, err = tk.Exec("insert into t1 set a=1;")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[autoid:1467]Failed to read auto-increment value from storage engine")
}
9 changes: 9 additions & 0 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1563,6 +1563,7 @@ func handleTableOptions(options []*ast.TableOption, tbInfo *model.TableInfo) err
if tbInfo.ShardRowIDBits > shardRowIDBitsMax {
tbInfo.ShardRowIDBits = shardRowIDBitsMax
}
tbInfo.MaxShardRowIDBits = tbInfo.ShardRowIDBits
}
}

Expand Down Expand Up @@ -1804,6 +1805,14 @@ func (d *ddl) ShardRowID(ctx sessionctx.Context, tableIdent ast.Ident, uVal uint
if ok && uVal != 0 {
return errUnsupportedShardRowIDBits
}
if uVal == t.Meta().ShardRowIDBits {
// Nothing need to do.
return nil
}
err = verifyNoOverflowShardBits(d.sessPool, t, uVal)
if err != nil {
return err
}
job := &model.Job{
Type: model.ActionShardRowID,
SchemaID: schema.ID,
Expand Down
2 changes: 1 addition & 1 deletion ddl/ddl_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ func (w *worker) runDDLJob(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64,
case model.ActionRenameTable:
ver, err = onRenameTable(t, job)
case model.ActionShardRowID:
ver, err = onShardRowID(t, job)
ver, err = w.onShardRowID(d, t, job)
case model.ActionModifyTableComment:
ver, err = onModifyTableComment(t, job)
case model.ActionAddTablePartition:
Expand Down
38 changes: 36 additions & 2 deletions ddl/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/pingcap/tidb/meta"
"github.com/pingcap/tidb/meta/autoid"
"github.com/pingcap/tidb/table"
"github.com/pingcap/tidb/table/tables"
"github.com/pingcap/tidb/tablecodec"
"github.com/pingcap/tidb/util/gcutil"
"github.com/pingcap/tidb/util/logutil"
Expand Down Expand Up @@ -469,7 +470,7 @@ func onRebaseAutoID(store kv.Storage, t *meta.Meta, job *model.Job) (ver int64,
return ver, nil
}

func onShardRowID(t *meta.Meta, job *model.Job) (ver int64, _ error) {
func (w *worker) onShardRowID(d *ddlCtx, t *meta.Meta, job *model.Job) (ver int64, _ error) {
var shardRowIDBits uint64
err := job.DecodeArgs(&shardRowIDBits)
if err != nil {
Expand All @@ -481,7 +482,22 @@ func onShardRowID(t *meta.Meta, job *model.Job) (ver int64, _ error) {
job.State = model.JobStateCancelled
return ver, errors.Trace(err)
}
tblInfo.ShardRowIDBits = shardRowIDBits
if shardRowIDBits < tblInfo.ShardRowIDBits {
tblInfo.ShardRowIDBits = shardRowIDBits
} else {
tbl, err := getTable(d.store, job.SchemaID, tblInfo)
if err != nil {
return ver, errors.Trace(err)
}
err = verifyNoOverflowShardBits(w.sessPool, tbl, shardRowIDBits)
if err != nil {
job.State = model.JobStateCancelled
return ver, err
}
tblInfo.ShardRowIDBits = shardRowIDBits
// MaxShardRowIDBits use to check the overflow of auto ID.
tblInfo.MaxShardRowIDBits = shardRowIDBits
}
ver, err = updateVersionAndTableInfo(t, job, tblInfo, true)
if err != nil {
job.State = model.JobStateCancelled
Expand All @@ -491,6 +507,24 @@ func onShardRowID(t *meta.Meta, job *model.Job) (ver int64, _ error) {
return ver, nil
}

func verifyNoOverflowShardBits(s *sessionPool, tbl table.Table, shardRowIDBits uint64) error {
ctx, err := s.get()
if err != nil {
return errors.Trace(err)
}
defer s.put(ctx)

// Check next global max auto ID first.
autoIncID, err := tbl.Allocator(ctx).NextGlobalAutoID(tbl.Meta().ID)
if err != nil {
return errors.Trace(err)
}
if tables.OverflowShardBits(autoIncID, shardRowIDBits) {
return autoid.ErrAutoincReadFailed.GenWithStack("shard_row_id_bits %d will cause next global auto ID overflow", shardRowIDBits)
}
return nil
}

func onRenameTable(t *meta.Meta, job *model.Job) (ver int64, _ error) {
var oldSchemaID int64
var tableName model.CIStr
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ require (
github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e
github.com/pingcap/kvproto v0.0.0-20190215154024-7f2fc73ef562
github.com/pingcap/log v0.0.0-20190307075452-bd41d9273596
github.com/pingcap/parser v0.0.0-20190408064140-cdceeb2c5476
github.com/pingcap/parser v0.0.0-20190409044748-a0b301443a30
github.com/pingcap/pd v2.1.0-rc.4+incompatible
github.com/pingcap/tidb-tools v2.1.3-0.20190321065848-1e8b48f5c168+incompatible
github.com/pingcap/tipb v0.0.0-20190107072121-abbec73437b7
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ github.com/pingcap/kvproto v0.0.0-20190215154024-7f2fc73ef562 h1:32oF1/8lVnBR2JV
github.com/pingcap/kvproto v0.0.0-20190215154024-7f2fc73ef562/go.mod h1:QMdbTAXCHzzygQzqcG9uVUgU2fKeSN1GmfMiykdSzzY=
github.com/pingcap/log v0.0.0-20190307075452-bd41d9273596 h1:t2OQTpPJnrPDGlvA+3FwJptMTt6MEPdzK1Wt99oaefQ=
github.com/pingcap/log v0.0.0-20190307075452-bd41d9273596/go.mod h1:WpHUKhNZ18v116SvGrmjkA9CBhYmuUTKL+p8JC9ANEw=
github.com/pingcap/parser v0.0.0-20190408064140-cdceeb2c5476 h1:qKFG6B26Zfgpb7rUYB8PCGQzWB+USDCTmH+rR7rV+ow=
github.com/pingcap/parser v0.0.0-20190408064140-cdceeb2c5476/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/parser v0.0.0-20190409044748-a0b301443a30 h1:Cu+VJBHLUqI0TFj/0Kya4L1iHIJZ3VbtZcEwv+3zOxQ=
github.com/pingcap/parser v0.0.0-20190409044748-a0b301443a30/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/pd v2.1.0-rc.4+incompatible h1:/buwGk04aHO5odk/+O8ZOXGs4qkUjYTJ2UpCJXna8NE=
github.com/pingcap/pd v2.1.0-rc.4+incompatible/go.mod h1:nD3+EoYes4+aNNODO99ES59V83MZSI+dFbhyr667a0E=
github.com/pingcap/tidb-tools v2.1.3-0.20190321065848-1e8b48f5c168+incompatible h1:MkWCxgZpJBgY2f4HtwWMMFzSBb3+JPzeJgF3VrXE/bU=
Expand Down
9 changes: 5 additions & 4 deletions table/tables/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -925,7 +925,8 @@ func (t *tableCommon) AllocAutoID(ctx sessionctx.Context) (int64, error) {
return 0, err
}
if t.meta.ShardRowIDBits > 0 {
if t.overflowShardBits(rowID) {
// Use max record ShardRowIDBits to check overflow.
if OverflowShardBits(rowID, t.meta.MaxShardRowIDBits) {
// If overflow, the rowID may be duplicated. For examples,
// t.meta.ShardRowIDBits = 4
// rowID = 0010111111111111111111111111111111111111111111111111111111111111
Expand All @@ -945,9 +946,9 @@ func (t *tableCommon) AllocAutoID(ctx sessionctx.Context) (int64, error) {
return rowID, nil
}

// overflowShardBits check whether the rowID overflow `1<<(64-t.meta.ShardRowIDBits-1) -1`.
func (t *tableCommon) overflowShardBits(rowID int64) bool {
mask := (1<<t.meta.ShardRowIDBits - 1) << (64 - t.meta.ShardRowIDBits - 1)
// OverflowShardBits checks whether the rowID overflow `1<<(64-shardRowIDBits-1) -1`.
func OverflowShardBits(rowID int64, shardRowIDBits uint64) bool {
mask := (1<<shardRowIDBits - 1) << (64 - shardRowIDBits - 1)
return rowID&int64(mask) > 0
}

Expand Down

0 comments on commit ed3e265

Please sign in to comment.