Skip to content

Commit

Permalink
executor, session: refine insert unsigned bigint autoIncreID (#8181)
Browse files Browse the repository at this point in the history
  • Loading branch information
XuHuaiyu authored Dec 18, 2018
1 parent df55d38 commit 7056bb0
Show file tree
Hide file tree
Showing 15 changed files with 321 additions and 46 deletions.
2 changes: 1 addition & 1 deletion ddl/column_change_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -347,7 +347,7 @@ func getCurrentTable(d *ddl, schemaID, tableID int64) (table.Table, error) {
if err != nil {
return nil, errors.Trace(err)
}
alloc := autoid.NewAllocator(d.store, schemaID)
alloc := autoid.NewAllocator(d.store, schemaID, false)
tbl, err := table.TableFromMeta(alloc, tblInfo)
if err != nil {
return nil, errors.Trace(err)
Expand Down
2 changes: 1 addition & 1 deletion ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1132,7 +1132,7 @@ func checkCharsetAndCollation(cs string, co string) error {
// handleAutoIncID handles auto_increment option in DDL. It creates a ID counter for the table and initiates the counter to a proper value.
// For example if the option sets auto_increment to 10. The counter will be set to 9. So the next allocated ID will be 10.
func (d *ddl) handleAutoIncID(tbInfo *model.TableInfo, schemaID int64) error {
alloc := autoid.NewAllocator(d.store, tbInfo.GetDBID(schemaID))
alloc := autoid.NewAllocator(d.store, tbInfo.GetDBID(schemaID), tbInfo.IsAutoIncColUnsigned())
tbInfo.State = model.StatePublic
tb, err := table.TableFromMeta(alloc, tbInfo)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion ddl/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func splitTableRegion(store kv.Storage, tableID int64) {
}

func getTable(store kv.Storage, schemaID int64, tblInfo *model.TableInfo) (table.Table, error) {
alloc := autoid.NewAllocator(store, tblInfo.GetDBID(schemaID))
alloc := autoid.NewAllocator(store, tblInfo.GetDBID(schemaID), tblInfo.IsAutoIncColUnsigned())
tbl, err := table.TableFromMeta(alloc, tblInfo)
return tbl, errors.Trace(err)
}
Expand Down
2 changes: 1 addition & 1 deletion ddl/table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ func testGetTableWithError(d *ddl, schemaID, tableID int64) (table.Table, error)
if tblInfo == nil {
return nil, errors.New("table not found")
}
alloc := autoid.NewAllocator(d.store, schemaID)
alloc := autoid.NewAllocator(d.store, schemaID, false)
tbl, err := table.TableFromMeta(alloc, tblInfo)
if err != nil {
return nil, errors.Trace(err)
Expand Down
2 changes: 1 addition & 1 deletion executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2848,7 +2848,7 @@ func (s *testSuite) TestCheckIndex(c *C) {
c.Assert(err, IsNil)
tbInfo := tbl.Meta()

alloc := autoid.NewAllocator(s.store, dbInfo.ID)
alloc := autoid.NewAllocator(s.store, dbInfo.ID, false)
tb, err := tables.TableFromMeta(alloc, tbInfo)
c.Assert(err, IsNil)

Expand Down
8 changes: 5 additions & 3 deletions executor/insert_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -473,10 +473,12 @@ func (e *InsertValues) adjustAutoIncrementDatum(d types.Datum, hasValue bool, c
d.SetNull()
}
if !d.IsNull() {
recordID, err = d.ToInt64(e.ctx.GetSessionVars().StmtCtx)
if e.filterErr(err) != nil {
return types.Datum{}, errors.Trace(err)
sc := e.ctx.GetSessionVars().StmtCtx
datum, err1 := d.ConvertTo(sc, &c.FieldType)
if e.filterErr(err1) != nil {
return types.Datum{}, err1
}
recordID = datum.GetInt64()
}
// Use the value if it's not null and not 0.
if recordID != 0 {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ require (
github.com/pingcap/errors v0.11.0
github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e
github.com/pingcap/kvproto v0.0.0-20181105061835-1b5d69cd1d26
github.com/pingcap/parser v0.0.0-20181214132045-732efe993f70
github.com/pingcap/parser v0.0.0-20181218071912-deacf026787e
github.com/pingcap/pd v2.1.0-rc.4+incompatible
github.com/pingcap/tidb-tools v0.0.0-20181112132202-4860a0d5de03
github.com/pingcap/tipb v0.0.0-20181012112600-11e33c750323
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e h1:P73/4dPCL96rG
github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e/go.mod h1:O17XtbryoCJhkKGbT62+L2OlrniwqiGLSqrmdHCMzZw=
github.com/pingcap/kvproto v0.0.0-20181105061835-1b5d69cd1d26 h1:JK4VLNYbSn36QSbCnqALi2ySXdH0DfcMssT/zmLf4Ls=
github.com/pingcap/kvproto v0.0.0-20181105061835-1b5d69cd1d26/go.mod h1:0gwbe1F2iBIjuQ9AH0DbQhL+Dpr5GofU8fgYyXk+ykk=
github.com/pingcap/parser v0.0.0-20181214132045-732efe993f70 h1:18cirMLfudQucdZM5keSuhUFculJ2xOQb9hqKd4O8wQ=
github.com/pingcap/parser v0.0.0-20181214132045-732efe993f70/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA=
github.com/pingcap/parser v0.0.0-20181218071912-deacf026787e h1:jKibIs55HR7OMo62uhjA6Bfx3GK+rbHK4Gfd4/8aTzk=
github.com/pingcap/parser v0.0.0-20181218071912-deacf026787e/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 v0.0.0-20181112132202-4860a0d5de03 h1:xVuo5U+l6XAWHsb+xhkZ8zz3jerIwDfCHAO6kR2Kaog=
Expand Down
4 changes: 2 additions & 2 deletions infoschema/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ func (b *Builder) applyCreateTable(m *meta.Meta, dbInfo *model.DBInfo, tableID i
}
if alloc == nil {
schemaID := dbInfo.ID
alloc = autoid.NewAllocator(b.handle.store, tblInfo.GetDBID(schemaID))
alloc = autoid.NewAllocator(b.handle.store, tblInfo.GetDBID(schemaID), tblInfo.IsAutoIncColUnsigned())
}
tbl, err := tables.TableFromMeta(alloc, tblInfo)
if err != nil {
Expand Down Expand Up @@ -276,7 +276,7 @@ func (b *Builder) createSchemaTablesForDB(di *model.DBInfo) error {
b.is.schemaMap[di.Name.L] = schTbls
for _, t := range di.Tables {
schemaID := di.ID
alloc := autoid.NewAllocator(b.handle.store, t.GetDBID(schemaID))
alloc := autoid.NewAllocator(b.handle.store, t.GetDBID(schemaID), t.IsAutoIncColUnsigned())
var tbl table.Table
tbl, err := tables.TableFromMeta(alloc, t)
if err != nil {
Expand Down
145 changes: 121 additions & 24 deletions meta/autoid/autoid.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ type allocator struct {
end int64
store kv.Storage
// dbID is current database's ID.
dbID int64
dbID int64
isUnsigned bool
}

// GetStep is only used by tests
Expand Down Expand Up @@ -91,25 +92,65 @@ func (alloc *allocator) NextGlobalAutoID(tableID int64) (int64, error) {
return errors.Trace(err1)
})
metrics.AutoIDHistogram.WithLabelValues(metrics.GlobalAutoID, metrics.RetLabel(err)).Observe(time.Since(startTime).Seconds())
return autoID + 1, errors.Trace(err)
if alloc.isUnsigned {
return int64(uint64(autoID) + 1), err
}
return autoID + 1, err
}

// Rebase implements autoid.Allocator Rebase interface.
// The requiredBase is the minimum base value after Rebase.
// The real base may be greater than the required base.
func (alloc *allocator) Rebase(tableID, requiredBase int64, allocIDs bool) error {
if tableID == 0 {
return errInvalidTableID.GenWithStack("Invalid tableID")
func (alloc *allocator) rebase4Unsigned(tableID int64, requiredBase uint64, allocIDs bool) error {
// Satisfied by alloc.base, nothing to do.
if requiredBase <= uint64(alloc.base) {
return nil
}
// Satisfied by alloc.end, need to update alloc.base.
if requiredBase <= uint64(alloc.end) {
alloc.base = int64(requiredBase)
return nil
}
var newBase, newEnd uint64
startTime := time.Now()
err := kv.RunInNewTxn(alloc.store, true, func(txn kv.Transaction) error {
m := meta.NewMeta(txn)
currentEnd, err1 := m.GetAutoTableID(alloc.dbID, tableID)
if err1 != nil {
return errors.Trace(err1)
}
uCurrentEnd := uint64(currentEnd)
if allocIDs {
newBase = mathutil.MaxUint64(uCurrentEnd, requiredBase)
newEnd = mathutil.MinUint64(math.MaxUint64-uint64(step), newBase) + uint64(step)
} else {
if uCurrentEnd >= requiredBase {
newBase = uCurrentEnd
newEnd = uCurrentEnd
// Required base satisfied, we don't need to update KV.
return nil
}
// If we don't want to allocate IDs, for example when creating a table with a given base value,
// We need to make sure when other TiDB server allocates ID for the first time, requiredBase + 1
// will be allocated, so we need to increase the end to exactly the requiredBase.
newBase = requiredBase
newEnd = requiredBase
}
_, err1 = m.GenAutoTableID(alloc.dbID, tableID, int64(newEnd-uCurrentEnd))
return err1
})
metrics.AutoIDHistogram.WithLabelValues(metrics.TableAutoIDRebase, metrics.RetLabel(err)).Observe(time.Since(startTime).Seconds())
if err != nil {
return err
}
alloc.base, alloc.end = int64(newBase), int64(newEnd)
return nil
}

alloc.mu.Lock()
defer alloc.mu.Unlock()
func (alloc *allocator) rebase4Signed(tableID, requiredBase int64, allocIDs bool) error {
// Satisfied by alloc.base, nothing to do.
if requiredBase <= alloc.base {
// Satisfied by alloc.base, nothing to do.
return nil
}
// Satisfied by alloc.end, need to update alloc.base.
if requiredBase <= alloc.end {
// Satisfied by alloc.end, need to updata alloc.base.
alloc.base = requiredBase
return nil
}
Expand All @@ -123,7 +164,7 @@ func (alloc *allocator) Rebase(tableID, requiredBase int64, allocIDs bool) error
}
if allocIDs {
newBase = mathutil.MaxInt64(currentEnd, requiredBase)
newEnd = newBase + step
newEnd = mathutil.MinInt64(math.MaxInt64-step, newBase) + step
} else {
if currentEnd >= requiredBase {
newBase = currentEnd
Expand All @@ -138,23 +179,34 @@ func (alloc *allocator) Rebase(tableID, requiredBase int64, allocIDs bool) error
newEnd = requiredBase
}
_, err1 = m.GenAutoTableID(alloc.dbID, tableID, newEnd-currentEnd)
return errors.Trace(err1)
return err1
})
metrics.AutoIDHistogram.WithLabelValues(metrics.TableAutoIDRebase, metrics.RetLabel(err)).Observe(time.Since(startTime).Seconds())
if err != nil {
return errors.Trace(err)
return err
}
alloc.base, alloc.end = newBase, newEnd
return nil
}

// Alloc implements autoid.Allocator Alloc interface.
func (alloc *allocator) Alloc(tableID int64) (int64, error) {
// Rebase implements autoid.Allocator Rebase interface.
// The requiredBase is the minimum base value after Rebase.
// The real base may be greater than the required base.
func (alloc *allocator) Rebase(tableID, requiredBase int64, allocIDs bool) error {
if tableID == 0 {
return 0, errInvalidTableID.GenWithStack("Invalid tableID")
return errInvalidTableID.GenWithStack("Invalid tableID")
}

alloc.mu.Lock()
defer alloc.mu.Unlock()

if alloc.isUnsigned {
return alloc.rebase4Unsigned(tableID, uint64(requiredBase), allocIDs)
}
return alloc.rebase4Signed(tableID, requiredBase, allocIDs)
}

func (alloc *allocator) alloc4Unsigned(tableID int64) (int64, error) {
if alloc.base == alloc.end { // step
var newBase, newEnd int64
startTime := time.Now()
Expand All @@ -165,15 +217,46 @@ func (alloc *allocator) Alloc(tableID int64) (int64, error) {
if err1 != nil {
return errors.Trace(err1)
}
newEnd, err1 = m.GenAutoTableID(alloc.dbID, tableID, step)
tmpStep := int64(mathutil.MinUint64(math.MaxUint64-uint64(newBase), uint64(step)))
newEnd, err1 = m.GenAutoTableID(alloc.dbID, tableID, tmpStep)
return err1
})
metrics.AutoIDHistogram.WithLabelValues(metrics.TableAutoIDAlloc, metrics.RetLabel(err)).Observe(time.Since(startTime).Seconds())
if err != nil {
return 0, err
}
if uint64(newBase) == math.MaxUint64 {
return 0, ErrAutoincReadFailed
}
alloc.base, alloc.end = newBase, newEnd
}

alloc.base = int64(uint64(alloc.base) + 1)
log.Debugf("[kv] Alloc id %d, table ID:%d, from %p, database ID:%d", uint64(alloc.base), tableID, alloc, alloc.dbID)
return alloc.base, nil
}

func (alloc *allocator) alloc4Signed(tableID int64) (int64, error) {
if alloc.base == alloc.end { // step
var newBase, newEnd int64
startTime := time.Now()
err := kv.RunInNewTxn(alloc.store, true, func(txn kv.Transaction) error {
m := meta.NewMeta(txn)
var err1 error
newBase, err1 = m.GetAutoTableID(alloc.dbID, tableID)
if err1 != nil {
return errors.Trace(err1)
}
return nil
tmpStep := mathutil.MinInt64(math.MaxInt64-newBase, step)
newEnd, err1 = m.GenAutoTableID(alloc.dbID, tableID, tmpStep)
return err1
})
metrics.AutoIDHistogram.WithLabelValues(metrics.TableAutoIDAlloc, metrics.RetLabel(err)).Observe(time.Since(startTime).Seconds())
if err != nil {
return 0, errors.Trace(err)
return 0, err
}
if newBase == math.MaxInt64 {
return 0, ErrAutoincReadFailed
}
alloc.base, alloc.end = newBase, newEnd
}
Expand All @@ -183,6 +266,19 @@ func (alloc *allocator) Alloc(tableID int64) (int64, error) {
return alloc.base, nil
}

// Alloc implements autoid.Allocator Alloc interface.
func (alloc *allocator) Alloc(tableID int64) (int64, error) {
if tableID == 0 {
return 0, errInvalidTableID.GenWithStack("Invalid tableID")
}
alloc.mu.Lock()
defer alloc.mu.Unlock()
if alloc.isUnsigned {
return alloc.alloc4Unsigned(tableID)
}
return alloc.alloc4Signed(tableID)
}

var (
memID int64
memIDLock sync.Mutex
Expand Down Expand Up @@ -237,10 +333,11 @@ func (alloc *memoryAllocator) Alloc(tableID int64) (int64, error) {
}

// NewAllocator returns a new auto increment id generator on the store.
func NewAllocator(store kv.Storage, dbID int64) Allocator {
func NewAllocator(store kv.Storage, dbID int64, isUnsigned bool) Allocator {
return &allocator{
store: store,
dbID: dbID,
store: store,
dbID: dbID,
isUnsigned: isUnsigned,
}
}

Expand Down
Loading

0 comments on commit 7056bb0

Please sign in to comment.