Skip to content

Commit

Permalink
meta/autoid : fix the issue that MaxUint64 and MaxInt64 autoID is inc…
Browse files Browse the repository at this point in the history
…orrectly allocated (#12119)
  • Loading branch information
AilinKid authored Sep 11, 2019
1 parent 39e9c9f commit c2901fe
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 6 deletions.
6 changes: 6 additions & 0 deletions meta/autoid/autoid.go
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ func (alloc *allocator) alloc4Unsigned(tableID int64) (int64, error) {
alloc.base, alloc.end = newBase, newEnd
}

if uint64(alloc.base)+uint64(1) == math.MaxUint64 {
return 0, ErrAutoincReadFailed
}
alloc.base = int64(uint64(alloc.base) + 1)
logutil.BgLogger().Debug("alloc unsigned ID",
zap.Uint64("ID", uint64(alloc.base)),
Expand Down Expand Up @@ -283,6 +286,9 @@ func (alloc *allocator) alloc4Signed(tableID int64) (int64, error) {
alloc.base, alloc.end = newBase, newEnd
}

if alloc.base+1 == math.MaxInt64 {
return 0, ErrAutoincReadFailed
}
alloc.base++
logutil.BgLogger().Debug("alloc signed ID",
zap.Uint64("ID", uint64(alloc.base)),
Expand Down
20 changes: 20 additions & 0 deletions meta/autoid/autoid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package autoid_test

import (
"fmt"
"math"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -133,6 +134,14 @@ func (*testSuite) TestT(c *C) {
id, err = alloc.Alloc(3)
c.Assert(err, IsNil)
c.Assert(id, Equals, int64(6544))

// Test the MaxInt64 is the upper bound of `alloc` function but not `rebase`.
err = alloc.Rebase(3, int64(math.MaxInt64-1), true)
c.Assert(err, IsNil)
_, err = alloc.Alloc(3)
c.Assert(alloc, NotNil)
err = alloc.Rebase(3, int64(math.MaxInt64), true)
c.Assert(err, IsNil)
}

func (*testSuite) TestUnsignedAutoid(c *C) {
Expand Down Expand Up @@ -229,6 +238,17 @@ func (*testSuite) TestUnsignedAutoid(c *C) {
id, err = alloc.Alloc(3)
c.Assert(err, IsNil)
c.Assert(id, Equals, int64(6544))

// Test the MaxUint64 is the upper bound of `alloc` func but not `rebase`.
var n uint64 = math.MaxUint64 - 1
un := int64(n)
err = alloc.Rebase(3, un, true)
c.Assert(err, IsNil)
_, err = alloc.Alloc(3)
c.Assert(err, NotNil)
un = int64(n + 1)
err = alloc.Rebase(3, un, true)
c.Assert(err, IsNil)
}

// TestConcurrentAlloc is used for the test that
Expand Down
18 changes: 12 additions & 6 deletions session/session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -913,8 +913,11 @@ func (s *testSessionSuite) TestAutoIncrementID(c *C) {
tk.MustExec("insert into autoid values();")
tk.MustExec("insert into autoid values();")
tk.MustQuery("select * from autoid").Check(testkit.Rows("9223372036854775808", "9223372036854775810", "9223372036854775812"))
tk.MustExec("insert into autoid values(18446744073709551614);")
_, err := tk.Exec("insert into autoid values()")
// In TiDB : _tidb_rowid will also consume the autoID when the auto_increment column is not the primary key.
// Using the MaxUint64 and MaxInt64 as the autoID upper limit like MySQL will cause _tidb_rowid allocation fail here.
_, err := tk.Exec("insert into autoid values(18446744073709551614)")
c.Assert(terror.ErrorEqual(err, autoid.ErrAutoincReadFailed), IsTrue)
_, err = tk.Exec("insert into autoid values()")
c.Assert(terror.ErrorEqual(err, autoid.ErrAutoincReadFailed), IsTrue)
// FixMe: MySQL works fine with the this sql.
_, err = tk.Exec("insert into autoid values(18446744073709551615)")
Expand All @@ -937,12 +940,15 @@ func (s *testSessionSuite) TestAutoIncrementID(c *C) {
// Corner cases for signed bigint auto_increment Columns.
tk.MustExec("drop table if exists autoid")
tk.MustExec("create table autoid(`auto_inc_id` bigint(20) NOT NULL AUTO_INCREMENT,UNIQUE KEY `auto_inc_id` (`auto_inc_id`))")
tk.MustExec("insert into autoid values(9223372036854775806);")
tk.MustQuery("select auto_inc_id, _tidb_rowid from autoid use index()").Check(testkit.Rows("9223372036854775806 9223372036854775807"))
// In TiDB : _tidb_rowid will also consume the autoID when the auto_increment column is not the primary key.
// Using the MaxUint64 and MaxInt64 as autoID upper limit like MySQL will cause insert fail if the values is
// 9223372036854775806. Because _tidb_rowid will be allocated 9223372036854775807 at same time.
tk.MustExec("insert into autoid values(9223372036854775805);")
tk.MustQuery("select auto_inc_id, _tidb_rowid from autoid use index()").Check(testkit.Rows("9223372036854775805 9223372036854775806"))
_, err = tk.Exec("insert into autoid values();")
c.Assert(terror.ErrorEqual(err, autoid.ErrAutoincReadFailed), IsTrue)
tk.MustQuery("select auto_inc_id, _tidb_rowid from autoid use index()").Check(testkit.Rows("9223372036854775806 9223372036854775807"))
tk.MustQuery("select auto_inc_id, _tidb_rowid from autoid use index(auto_inc_id)").Check(testkit.Rows("9223372036854775806 9223372036854775807"))
tk.MustQuery("select auto_inc_id, _tidb_rowid from autoid use index()").Check(testkit.Rows("9223372036854775805 9223372036854775806"))
tk.MustQuery("select auto_inc_id, _tidb_rowid from autoid use index(auto_inc_id)").Check(testkit.Rows("9223372036854775805 9223372036854775806"))

tk.MustExec("drop table if exists autoid")
tk.MustExec("create table autoid(`auto_inc_id` bigint(20) NOT NULL AUTO_INCREMENT,UNIQUE KEY `auto_inc_id` (`auto_inc_id`))")
Expand Down

0 comments on commit c2901fe

Please sign in to comment.