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

meta/autoid : fix the issue that MaxUint64 and MaxInt64 autoID is incorrectly allocated (#12119) #12162

Merged
merged 16 commits into from
Sep 16, 2019
Merged
6 changes: 6 additions & 0 deletions meta/autoid/autoid.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,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.Logger(context.Background()).Debug("alloc unsigned ID",
zap.Uint64("ID", uint64(alloc.base)),
Expand Down Expand Up @@ -284,6 +287,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.Logger(context.Background()).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 @@ -842,8 +842,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 @@ -866,12 +869,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