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

*: fix 'Duplicate entry' error when @@auto_increment_increment and @@auto_increment_offset is set #52626

Merged
merged 4 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions pkg/autoid_service/autoid.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func (alloc *autoIDValue) rebase4Unsigned(ctx context.Context,
return nil
}
// Satisfied by alloc.end, need to update alloc.base.
if requiredBase <= uint64(alloc.end) {
if requiredBase > uint64(alloc.base) && requiredBase <= uint64(alloc.end) {
alloc.base = int64(requiredBase)
return nil
}
Expand Down Expand Up @@ -243,7 +243,7 @@ func (alloc *autoIDValue) rebase4Signed(ctx context.Context, store kv.Storage, d
return nil
}
// Satisfied by alloc.end, need to update alloc.base.
if requiredBase <= alloc.end {
if requiredBase > alloc.base && requiredBase <= alloc.end {
alloc.base = requiredBase
return nil
}
Expand Down Expand Up @@ -501,6 +501,7 @@ func (s *Service) allocAutoID(ctx context.Context, req *autoid.AutoIDRequest) (*
if err1 != nil {
return err1
}
val.base = currentEnd
val.end = currentEnd
return nil
})
Expand Down
2 changes: 1 addition & 1 deletion pkg/executor/test/autoidtest/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ go_test(
],
flaky = True,
race = "on",
shard_count = 4,
shard_count = 5,
deps = [
"//pkg/autoid_service",
"//pkg/config",
Expand Down
40 changes: 40 additions & 0 deletions pkg/executor/test/autoidtest/autoid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -567,3 +567,43 @@ func TestIssue39528(t *testing.T) {
// Make sure the code does not visit tikv on allocate path.
require.False(t, codeRun)
}

func TestIssue52622(t *testing.T) {
store := testkit.CreateMockStore(t)

tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec(`set @@auto_increment_increment = 66;`)
tk.MustExec(`set @@auto_increment_offset = 9527;`)

tk.MustQuery(`select @@auto_increment_increment;`).Check(testkit.Rows("66"))
tk.MustQuery(`select @@auto_increment_offset;`).Check(testkit.Rows("9527"))

for i := 0; i < 2; i++ {
createTableSQL := "create table issue52622 (id int primary key auto_increment, k int)"
if i == 0 {
createTableSQL = createTableSQL + " AUTO_ID_CACHE 1"
}

tk.MustExec(createTableSQL)
tk.MustExec("insert into issue52622 (k) values (1),(2),(3);")
tk.MustQuery("select * from issue52622").Check(testkit.Rows("1 1", "67 2", "133 3"))
if i == 0 {
tk.MustQuery("show create table issue52622").CheckContain("134")
}
tk.MustExec("insert into issue52622 (k) values (4);")
tk.MustQuery("select * from issue52622").Check(testkit.Rows("1 1", "67 2", "133 3", "199 4"))

tk.MustExec("truncate table issue52622;")
tk.MustExec("insert into issue52622 (k) values (1)")
tk.MustExec("insert into issue52622 (k) values (2)")
tk.MustExec("insert into issue52622 (k) values (3)")
if i == 0 {
tk.MustQuery("show create table issue52622").CheckContain("134")
}
tk.MustExec("insert into issue52622 (k) values (4);")
tk.MustQuery("select * from issue52622").Check(testkit.Rows("1 1", "67 2", "133 3", "199 4"))
tiancaiamao marked this conversation as resolved.
Show resolved Hide resolved

tk.MustExec("drop table issue52622;")
}
}
27 changes: 19 additions & 8 deletions pkg/table/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/pingcap/tidb/pkg/meta/autoid"
"github.com/pingcap/tidb/pkg/parser/model"
"github.com/pingcap/tidb/pkg/sessionctx"
"github.com/pingcap/tidb/pkg/sessionctx/variable"
tbctx "github.com/pingcap/tidb/pkg/table/context"
"github.com/pingcap/tidb/pkg/types"
"github.com/pingcap/tidb/pkg/util/dbterror"
Expand Down Expand Up @@ -214,12 +215,23 @@ type Table interface {
GetPartitionedTable() PartitionedTable
}

func getIncrementAndOffset(vars *variable.SessionVars) (int, int) {
increment := vars.AutoIncrementIncrement
offset := vars.AutoIncrementOffset
// When the value of auto_increment_offset is greater than that of auto_increment_increment,
// the value of auto_increment_offset is ignored.
// Ref https://dev.mysql.com/doc/refman/8.0/en/replication-options-source.html
if offset > increment {
offset = 1
}
return increment, offset
}

// AllocAutoIncrementValue allocates an auto_increment value for a new row.
func AllocAutoIncrementValue(ctx context.Context, t Table, sctx sessionctx.Context) (int64, error) {
r, ctx := tracing.StartRegionEx(ctx, "table.AllocAutoIncrementValue")
defer r.End()
increment := sctx.GetSessionVars().AutoIncrementIncrement
offset := sctx.GetSessionVars().AutoIncrementOffset
increment, offset := getIncrementAndOffset(sctx.GetSessionVars())
alloc := t.Allocators(sctx.GetTableCtx()).Get(autoid.AutoIncrementType)
_, max, err := alloc.Alloc(ctx, uint64(1), int64(increment), int64(offset))
if err != nil {
Expand All @@ -230,18 +242,17 @@ func AllocAutoIncrementValue(ctx context.Context, t Table, sctx sessionctx.Conte

// AllocBatchAutoIncrementValue allocates batch auto_increment value for rows, returning firstID, increment and err.
// The caller can derive the autoID by adding increment to firstID for N-1 times.
func AllocBatchAutoIncrementValue(ctx context.Context, t Table, sctx sessionctx.Context, N int) (firstID int64, increment int64, err error) {
increment = int64(sctx.GetSessionVars().AutoIncrementIncrement)
offset := int64(sctx.GetSessionVars().AutoIncrementOffset)
func AllocBatchAutoIncrementValue(ctx context.Context, t Table, sctx sessionctx.Context, N int) ( /* firstID */ int64 /* increment */, int64 /* err */, error) {
increment1, offset := getIncrementAndOffset(sctx.GetSessionVars())
alloc := t.Allocators(sctx.GetTableCtx()).Get(autoid.AutoIncrementType)
min, max, err := alloc.Alloc(ctx, uint64(N), increment, offset)
min, max, err := alloc.Alloc(ctx, uint64(N), int64(increment1), int64(offset))
if err != nil {
return min, max, err
}
// SeekToFirstAutoIDUnSigned seeks to first autoID. Because AutoIncrement always allocate from 1,
// signed and unsigned value can be unified as the unsigned handle.
nr := int64(autoid.SeekToFirstAutoIDUnSigned(uint64(min), uint64(increment), uint64(offset)))
return nr, increment, nil
nr := int64(autoid.SeekToFirstAutoIDUnSigned(uint64(min), uint64(increment1), uint64(offset)))
return nr, int64(increment1), nil
}

// PhysicalTable is an abstraction for two kinds of table representation: partition or non-partitioned table.
Expand Down
80 changes: 40 additions & 40 deletions tests/integrationtest/r/executor/autoid.result
Original file line number Diff line number Diff line change
Expand Up @@ -575,123 +575,123 @@ create table io (a int key auto_increment);
insert into io values (null),(null),(null);
select * from io;
a
10
15
20
1
6
11
drop table io;
create table io (a int key auto_increment) AUTO_ID_CACHE 1;
insert into io values (null),(null),(null);
select * from io;
a
10
15
20
1
6
11
drop table io;
create table io (a int key auto_increment);
set auto_increment_offset = 10;
set auto_increment_increment = 2;
insert into io values (),(),();
select * from io;
a
10
12
14
1
3
5
delete from io;
set auto_increment_increment = 5;
insert into io values (),(),();
select * from io;
a
15
20
25
6
11
16
delete from io;
set auto_increment_increment = 10;
insert into io values (),(),();
select * from io;
a
20
30
40
50
delete from io;
set auto_increment_increment = 5;
insert into io values (),(),();
select * from io;
a
55
60
65
41
46
51
drop table io;
create table io (a int key auto_increment) AUTO_ID_CACHE 1;
set auto_increment_offset = 10;
set auto_increment_increment = 2;
insert into io values (),(),();
select * from io;
a
10
12
14
1
3
5
delete from io;
set auto_increment_increment = 5;
insert into io values (),(),();
select * from io;
a
15
20
25
6
11
16
delete from io;
set auto_increment_increment = 10;
insert into io values (),(),();
select * from io;
a
20
30
40
50
delete from io;
set auto_increment_increment = 5;
insert into io values (),(),();
select * from io;
a
55
60
65
41
46
51
drop table io;
set auto_increment_offset = 10;
set auto_increment_increment = 2;
create table io (a int, b int auto_increment, key(b));
insert into io(b) values (null),(null),(null);
select b from io;
b
10
12
14
1
3
5
select _tidb_rowid from io;
_tidb_rowid
15
16
17
6
7
8
delete from io;
set auto_increment_increment = 10;
insert into io(b) values (null),(null),(null);
select b from io;
b
10
20
30
40
select _tidb_rowid from io;
_tidb_rowid
41
42
43
31
32
33
drop table io;
set auto_increment_offset = 10;
set auto_increment_increment = 2;
create table io (a int, b int auto_increment, key(b)) AUTO_ID_CACHE 1;
insert into io(b) values (null),(null),(null);
select b from io;
b
10
12
14
1
3
5
select _tidb_rowid from io;
_tidb_rowid
1
Expand All @@ -702,9 +702,9 @@ set auto_increment_increment = 10;
insert into io(b) values (null),(null),(null);
select b from io;
b
10
20
30
40
select _tidb_rowid from io;
_tidb_rowid
4
Expand Down