From 451b058f24e6fed719308c8f0499a937531b3cd7 Mon Sep 17 00:00:00 2001 From: Arenatlx Date: Mon, 16 Sep 2019 07:18:34 -0500 Subject: [PATCH] meta/autoid : fix the issue that MaxUint64 and MaxInt64 autoID is incorrectly allocated (#12119) (#12198) --- meta/autoid/autoid.go | 6 ++++++ meta/autoid/autoid_test.go | 20 ++++++++++++++++++++ session/session_test.go | 18 ++++++++++++------ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/meta/autoid/autoid.go b/meta/autoid/autoid.go index cccaa35875974..15329e8d7dc77 100644 --- a/meta/autoid/autoid.go +++ b/meta/autoid/autoid.go @@ -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)), @@ -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)), diff --git a/meta/autoid/autoid_test.go b/meta/autoid/autoid_test.go index 6714e322b4076..23961eac150e7 100644 --- a/meta/autoid/autoid_test.go +++ b/meta/autoid/autoid_test.go @@ -15,6 +15,7 @@ package autoid_test import ( "fmt" + "math" "sync" "testing" "time" @@ -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) { @@ -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 diff --git a/session/session_test.go b/session/session_test.go index 1d260a16f922b..6a279e80f230d 100644 --- a/session/session_test.go +++ b/session/session_test.go @@ -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)") @@ -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`))")