github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/dbs/memristed/meta/autoid/autoid_test.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package autoid_test
    15  
    16  import (
    17  	"fmt"
    18  	"math"
    19  	"math/rand"
    20  	"sync"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    25  	. "github.com/whtcorpsinc/check"
    26  	"github.com/whtcorpsinc/errors"
    27  	"github.com/whtcorpsinc/failpoint"
    28  	"github.com/whtcorpsinc/milevadb/causetstore/mockstore"
    29  	"github.com/whtcorpsinc/milevadb/ekv"
    30  	"github.com/whtcorpsinc/milevadb/spacetime"
    31  	"github.com/whtcorpsinc/milevadb/spacetime/autoid"
    32  )
    33  
    34  func TestT(t *testing.T) {
    35  	CustomVerboseFlag = true
    36  	TestingT(t)
    37  }
    38  
    39  var _ = SerialSuites(&testSuite{})
    40  
    41  type testSuite struct {
    42  }
    43  
    44  func (*testSuite) TestT(c *C) {
    45  	c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/spacetime/autoid/mockAutoIDChange", `return(true)`), IsNil)
    46  	defer func() {
    47  		c.Assert(failpoint.Disable("github.com/whtcorpsinc/milevadb/spacetime/autoid/mockAutoIDChange"), IsNil)
    48  	}()
    49  
    50  	causetstore, err := mockstore.NewMockStore()
    51  	c.Assert(err, IsNil)
    52  	defer causetstore.Close()
    53  
    54  	err = ekv.RunInNewTxn(causetstore, false, func(txn ekv.Transaction) error {
    55  		m := spacetime.NewMeta(txn)
    56  		err = m.CreateDatabase(&perceptron.DBInfo{ID: 1, Name: perceptron.NewCIStr("a")})
    57  		c.Assert(err, IsNil)
    58  		err = m.CreateBlockOrView(1, &perceptron.BlockInfo{ID: 1, Name: perceptron.NewCIStr("t")})
    59  		c.Assert(err, IsNil)
    60  		err = m.CreateBlockOrView(1, &perceptron.BlockInfo{ID: 2, Name: perceptron.NewCIStr("t1")})
    61  		c.Assert(err, IsNil)
    62  		err = m.CreateBlockOrView(1, &perceptron.BlockInfo{ID: 3, Name: perceptron.NewCIStr("t1")})
    63  		c.Assert(err, IsNil)
    64  		err = m.CreateBlockOrView(1, &perceptron.BlockInfo{ID: 4, Name: perceptron.NewCIStr("t2")})
    65  		c.Assert(err, IsNil)
    66  		err = m.CreateBlockOrView(1, &perceptron.BlockInfo{ID: 5, Name: perceptron.NewCIStr("t3")})
    67  		c.Assert(err, IsNil)
    68  		return nil
    69  	})
    70  	c.Assert(err, IsNil)
    71  
    72  	// Since the test here is applicable to any type of allocators, autoid.RowIDAllocType is chosen.
    73  	alloc := autoid.NewSlabPredictor(causetstore, 1, false, autoid.RowIDAllocType)
    74  	c.Assert(alloc, NotNil)
    75  
    76  	globalAutoID, err := alloc.NextGlobalAutoID(1)
    77  	c.Assert(err, IsNil)
    78  	c.Assert(globalAutoID, Equals, int64(1))
    79  	_, id, err := alloc.Alloc(1, 1, 1, 1)
    80  	c.Assert(err, IsNil)
    81  	c.Assert(id, Equals, int64(1))
    82  	_, id, err = alloc.Alloc(1, 1, 1, 1)
    83  	c.Assert(err, IsNil)
    84  	c.Assert(id, Equals, int64(2))
    85  	_, _, err = alloc.Alloc(0, 1, 1, 1)
    86  	c.Assert(err, NotNil)
    87  	globalAutoID, err = alloc.NextGlobalAutoID(1)
    88  	c.Assert(err, IsNil)
    89  	c.Assert(globalAutoID, Equals, autoid.GetStep()+1)
    90  
    91  	// rebase
    92  	err = alloc.Rebase(1, int64(1), true)
    93  	c.Assert(err, IsNil)
    94  	_, id, err = alloc.Alloc(1, 1, 1, 1)
    95  	c.Assert(err, IsNil)
    96  	c.Assert(id, Equals, int64(3))
    97  	err = alloc.Rebase(1, int64(3), true)
    98  	c.Assert(err, IsNil)
    99  	_, id, err = alloc.Alloc(1, 1, 1, 1)
   100  	c.Assert(err, IsNil)
   101  	c.Assert(id, Equals, int64(4))
   102  	err = alloc.Rebase(1, int64(10), true)
   103  	c.Assert(err, IsNil)
   104  	_, id, err = alloc.Alloc(1, 1, 1, 1)
   105  	c.Assert(err, IsNil)
   106  	c.Assert(id, Equals, int64(11))
   107  	err = alloc.Rebase(1, int64(3010), true)
   108  	c.Assert(err, IsNil)
   109  	_, id, err = alloc.Alloc(1, 1, 1, 1)
   110  	c.Assert(err, IsNil)
   111  	c.Assert(id, Equals, int64(3011))
   112  
   113  	alloc = autoid.NewSlabPredictor(causetstore, 1, false, autoid.RowIDAllocType)
   114  	c.Assert(alloc, NotNil)
   115  	_, id, err = alloc.Alloc(1, 1, 1, 1)
   116  	c.Assert(err, IsNil)
   117  	c.Assert(id, Equals, autoid.GetStep()+1)
   118  
   119  	alloc = autoid.NewSlabPredictor(causetstore, 1, false, autoid.RowIDAllocType)
   120  	c.Assert(alloc, NotNil)
   121  	err = alloc.Rebase(2, int64(1), false)
   122  	c.Assert(err, IsNil)
   123  	_, id, err = alloc.Alloc(2, 1, 1, 1)
   124  	c.Assert(err, IsNil)
   125  	c.Assert(id, Equals, int64(2))
   126  
   127  	alloc = autoid.NewSlabPredictor(causetstore, 1, false, autoid.RowIDAllocType)
   128  	c.Assert(alloc, NotNil)
   129  	err = alloc.Rebase(3, int64(3210), false)
   130  	c.Assert(err, IsNil)
   131  	alloc = autoid.NewSlabPredictor(causetstore, 1, false, autoid.RowIDAllocType)
   132  	c.Assert(alloc, NotNil)
   133  	err = alloc.Rebase(3, int64(3000), false)
   134  	c.Assert(err, IsNil)
   135  	_, id, err = alloc.Alloc(3, 1, 1, 1)
   136  	c.Assert(err, IsNil)
   137  	c.Assert(id, Equals, int64(3211))
   138  	err = alloc.Rebase(3, int64(6543), false)
   139  	c.Assert(err, IsNil)
   140  	_, id, err = alloc.Alloc(3, 1, 1, 1)
   141  	c.Assert(err, IsNil)
   142  	c.Assert(id, Equals, int64(6544))
   143  
   144  	// Test the MaxInt64 is the upper bound of `alloc` function but not `rebase`.
   145  	err = alloc.Rebase(3, int64(math.MaxInt64-1), true)
   146  	c.Assert(err, IsNil)
   147  	_, _, err = alloc.Alloc(3, 1, 1, 1)
   148  	c.Assert(alloc, NotNil)
   149  	err = alloc.Rebase(3, int64(math.MaxInt64), true)
   150  	c.Assert(err, IsNil)
   151  
   152  	// alloc N for signed
   153  	alloc = autoid.NewSlabPredictor(causetstore, 1, false, autoid.RowIDAllocType)
   154  	c.Assert(alloc, NotNil)
   155  	globalAutoID, err = alloc.NextGlobalAutoID(4)
   156  	c.Assert(err, IsNil)
   157  	c.Assert(globalAutoID, Equals, int64(1))
   158  	min, max, err := alloc.Alloc(4, 1, 1, 1)
   159  	c.Assert(err, IsNil)
   160  	c.Assert(max-min, Equals, int64(1))
   161  	c.Assert(min+1, Equals, int64(1))
   162  
   163  	min, max, err = alloc.Alloc(4, 2, 1, 1)
   164  	c.Assert(err, IsNil)
   165  	c.Assert(max-min, Equals, int64(2))
   166  	c.Assert(min+1, Equals, int64(2))
   167  	c.Assert(max, Equals, int64(3))
   168  
   169  	min, max, err = alloc.Alloc(4, 100, 1, 1)
   170  	c.Assert(err, IsNil)
   171  	c.Assert(max-min, Equals, int64(100))
   172  	expected := int64(4)
   173  	for i := min + 1; i <= max; i++ {
   174  		c.Assert(i, Equals, expected)
   175  		expected++
   176  	}
   177  
   178  	err = alloc.Rebase(4, int64(1000), false)
   179  	c.Assert(err, IsNil)
   180  	min, max, err = alloc.Alloc(4, 3, 1, 1)
   181  	c.Assert(err, IsNil)
   182  	c.Assert(max-min, Equals, int64(3))
   183  	c.Assert(min+1, Equals, int64(1001))
   184  	c.Assert(min+2, Equals, int64(1002))
   185  	c.Assert(max, Equals, int64(1003))
   186  
   187  	lastRemainOne := alloc.End()
   188  	err = alloc.Rebase(4, alloc.End()-2, false)
   189  	c.Assert(err, IsNil)
   190  	min, max, err = alloc.Alloc(4, 5, 1, 1)
   191  	c.Assert(err, IsNil)
   192  	c.Assert(max-min, Equals, int64(5))
   193  	c.Assert(min+1, Greater, lastRemainOne)
   194  
   195  	// Test for increment & offset for signed.
   196  	alloc = autoid.NewSlabPredictor(causetstore, 1, false, autoid.RowIDAllocType)
   197  	c.Assert(alloc, NotNil)
   198  
   199  	increment := int64(2)
   200  	offset := int64(100)
   201  	c.Assert(err, IsNil)
   202  	c.Assert(globalAutoID, Equals, int64(1))
   203  	min, max, err = alloc.Alloc(5, 1, increment, offset)
   204  	c.Assert(err, IsNil)
   205  	c.Assert(min, Equals, int64(99))
   206  	c.Assert(max, Equals, int64(100))
   207  
   208  	min, max, err = alloc.Alloc(5, 2, increment, offset)
   209  	c.Assert(err, IsNil)
   210  	c.Assert(max-min, Equals, int64(4))
   211  	c.Assert(max-min, Equals, autoid.CalcNeededBatchSize(100, 2, increment, offset, false))
   212  	c.Assert(min, Equals, int64(100))
   213  	c.Assert(max, Equals, int64(104))
   214  
   215  	increment = int64(5)
   216  	min, max, err = alloc.Alloc(5, 3, increment, offset)
   217  	c.Assert(err, IsNil)
   218  	c.Assert(max-min, Equals, int64(11))
   219  	c.Assert(max-min, Equals, autoid.CalcNeededBatchSize(104, 3, increment, offset, false))
   220  	c.Assert(min, Equals, int64(104))
   221  	c.Assert(max, Equals, int64(115))
   222  	firstID := autoid.SeekToFirstAutoIDSigned(104, increment, offset)
   223  	c.Assert(firstID, Equals, int64(105))
   224  
   225  	increment = int64(15)
   226  	min, max, err = alloc.Alloc(5, 2, increment, offset)
   227  	c.Assert(err, IsNil)
   228  	c.Assert(max-min, Equals, int64(30))
   229  	c.Assert(max-min, Equals, autoid.CalcNeededBatchSize(115, 2, increment, offset, false))
   230  	c.Assert(min, Equals, int64(115))
   231  	c.Assert(max, Equals, int64(145))
   232  	firstID = autoid.SeekToFirstAutoIDSigned(115, increment, offset)
   233  	c.Assert(firstID, Equals, int64(130))
   234  
   235  	offset = int64(200)
   236  	min, max, err = alloc.Alloc(5, 2, increment, offset)
   237  	c.Assert(err, IsNil)
   238  	c.Assert(max-min, Equals, int64(16))
   239  	// offset-1 > base will cause alloc rebase to offset-1.
   240  	c.Assert(max-min, Equals, autoid.CalcNeededBatchSize(offset-1, 2, increment, offset, false))
   241  	c.Assert(min, Equals, int64(199))
   242  	c.Assert(max, Equals, int64(215))
   243  	firstID = autoid.SeekToFirstAutoIDSigned(offset-1, increment, offset)
   244  	c.Assert(firstID, Equals, int64(200))
   245  }
   246  
   247  func (*testSuite) TestUnsignedAutoid(c *C) {
   248  	c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/spacetime/autoid/mockAutoIDChange", `return(true)`), IsNil)
   249  	defer func() {
   250  		c.Assert(failpoint.Disable("github.com/whtcorpsinc/milevadb/spacetime/autoid/mockAutoIDChange"), IsNil)
   251  	}()
   252  
   253  	causetstore, err := mockstore.NewMockStore()
   254  	c.Assert(err, IsNil)
   255  	defer causetstore.Close()
   256  
   257  	err = ekv.RunInNewTxn(causetstore, false, func(txn ekv.Transaction) error {
   258  		m := spacetime.NewMeta(txn)
   259  		err = m.CreateDatabase(&perceptron.DBInfo{ID: 1, Name: perceptron.NewCIStr("a")})
   260  		c.Assert(err, IsNil)
   261  		err = m.CreateBlockOrView(1, &perceptron.BlockInfo{ID: 1, Name: perceptron.NewCIStr("t")})
   262  		c.Assert(err, IsNil)
   263  		err = m.CreateBlockOrView(1, &perceptron.BlockInfo{ID: 2, Name: perceptron.NewCIStr("t1")})
   264  		c.Assert(err, IsNil)
   265  		err = m.CreateBlockOrView(1, &perceptron.BlockInfo{ID: 3, Name: perceptron.NewCIStr("t1")})
   266  		c.Assert(err, IsNil)
   267  		err = m.CreateBlockOrView(1, &perceptron.BlockInfo{ID: 4, Name: perceptron.NewCIStr("t2")})
   268  		c.Assert(err, IsNil)
   269  		err = m.CreateBlockOrView(1, &perceptron.BlockInfo{ID: 5, Name: perceptron.NewCIStr("t3")})
   270  		c.Assert(err, IsNil)
   271  		return nil
   272  	})
   273  	c.Assert(err, IsNil)
   274  
   275  	alloc := autoid.NewSlabPredictor(causetstore, 1, true, autoid.RowIDAllocType)
   276  	c.Assert(alloc, NotNil)
   277  
   278  	globalAutoID, err := alloc.NextGlobalAutoID(1)
   279  	c.Assert(err, IsNil)
   280  	c.Assert(globalAutoID, Equals, int64(1))
   281  	_, id, err := alloc.Alloc(1, 1, 1, 1)
   282  	c.Assert(err, IsNil)
   283  	c.Assert(id, Equals, int64(1))
   284  	_, id, err = alloc.Alloc(1, 1, 1, 1)
   285  	c.Assert(err, IsNil)
   286  	c.Assert(id, Equals, int64(2))
   287  	_, _, err = alloc.Alloc(0, 1, 1, 1)
   288  	c.Assert(err, NotNil)
   289  	globalAutoID, err = alloc.NextGlobalAutoID(1)
   290  	c.Assert(err, IsNil)
   291  	c.Assert(globalAutoID, Equals, autoid.GetStep()+1)
   292  
   293  	// rebase
   294  	err = alloc.Rebase(1, int64(1), true)
   295  	c.Assert(err, IsNil)
   296  	_, id, err = alloc.Alloc(1, 1, 1, 1)
   297  	c.Assert(err, IsNil)
   298  	c.Assert(id, Equals, int64(3))
   299  	err = alloc.Rebase(1, int64(3), true)
   300  	c.Assert(err, IsNil)
   301  	_, id, err = alloc.Alloc(1, 1, 1, 1)
   302  	c.Assert(err, IsNil)
   303  	c.Assert(id, Equals, int64(4))
   304  	err = alloc.Rebase(1, int64(10), true)
   305  	c.Assert(err, IsNil)
   306  	_, id, err = alloc.Alloc(1, 1, 1, 1)
   307  	c.Assert(err, IsNil)
   308  	c.Assert(id, Equals, int64(11))
   309  	err = alloc.Rebase(1, int64(3010), true)
   310  	c.Assert(err, IsNil)
   311  	_, id, err = alloc.Alloc(1, 1, 1, 1)
   312  	c.Assert(err, IsNil)
   313  	c.Assert(id, Equals, int64(3011))
   314  
   315  	alloc = autoid.NewSlabPredictor(causetstore, 1, true, autoid.RowIDAllocType)
   316  	c.Assert(alloc, NotNil)
   317  	_, id, err = alloc.Alloc(1, 1, 1, 1)
   318  	c.Assert(err, IsNil)
   319  	c.Assert(id, Equals, autoid.GetStep()+1)
   320  
   321  	alloc = autoid.NewSlabPredictor(causetstore, 1, true, autoid.RowIDAllocType)
   322  	c.Assert(alloc, NotNil)
   323  	err = alloc.Rebase(2, int64(1), false)
   324  	c.Assert(err, IsNil)
   325  	_, id, err = alloc.Alloc(2, 1, 1, 1)
   326  	c.Assert(err, IsNil)
   327  	c.Assert(id, Equals, int64(2))
   328  
   329  	alloc = autoid.NewSlabPredictor(causetstore, 1, true, autoid.RowIDAllocType)
   330  	c.Assert(alloc, NotNil)
   331  	err = alloc.Rebase(3, int64(3210), false)
   332  	c.Assert(err, IsNil)
   333  	alloc = autoid.NewSlabPredictor(causetstore, 1, true, autoid.RowIDAllocType)
   334  	c.Assert(alloc, NotNil)
   335  	err = alloc.Rebase(3, int64(3000), false)
   336  	c.Assert(err, IsNil)
   337  	_, id, err = alloc.Alloc(3, 1, 1, 1)
   338  	c.Assert(err, IsNil)
   339  	c.Assert(id, Equals, int64(3211))
   340  	err = alloc.Rebase(3, int64(6543), false)
   341  	c.Assert(err, IsNil)
   342  	_, id, err = alloc.Alloc(3, 1, 1, 1)
   343  	c.Assert(err, IsNil)
   344  	c.Assert(id, Equals, int64(6544))
   345  
   346  	// Test the MaxUint64 is the upper bound of `alloc` func but not `rebase`.
   347  	var n uint64 = math.MaxUint64 - 1
   348  	un := int64(n)
   349  	err = alloc.Rebase(3, un, true)
   350  	c.Assert(err, IsNil)
   351  	_, _, err = alloc.Alloc(3, 1, 1, 1)
   352  	c.Assert(err, NotNil)
   353  	un = int64(n + 1)
   354  	err = alloc.Rebase(3, un, true)
   355  	c.Assert(err, IsNil)
   356  
   357  	// alloc N for unsigned
   358  	alloc = autoid.NewSlabPredictor(causetstore, 1, true, autoid.RowIDAllocType)
   359  	c.Assert(alloc, NotNil)
   360  	globalAutoID, err = alloc.NextGlobalAutoID(4)
   361  	c.Assert(err, IsNil)
   362  	c.Assert(globalAutoID, Equals, int64(1))
   363  
   364  	min, max, err := alloc.Alloc(4, 2, 1, 1)
   365  	c.Assert(err, IsNil)
   366  	c.Assert(max-min, Equals, int64(2))
   367  	c.Assert(min+1, Equals, int64(1))
   368  	c.Assert(max, Equals, int64(2))
   369  
   370  	err = alloc.Rebase(4, int64(500), true)
   371  	c.Assert(err, IsNil)
   372  	min, max, err = alloc.Alloc(4, 2, 1, 1)
   373  	c.Assert(err, IsNil)
   374  	c.Assert(max-min, Equals, int64(2))
   375  	c.Assert(min+1, Equals, int64(501))
   376  	c.Assert(max, Equals, int64(502))
   377  
   378  	lastRemainOne := alloc.End()
   379  	err = alloc.Rebase(4, alloc.End()-2, false)
   380  	c.Assert(err, IsNil)
   381  	min, max, err = alloc.Alloc(4, 5, 1, 1)
   382  	c.Assert(err, IsNil)
   383  	c.Assert(max-min, Equals, int64(5))
   384  	c.Assert(min+1, Greater, lastRemainOne)
   385  
   386  	// Test increment & offset for unsigned. Using AutoRandomType to avoid valid range check for increment and offset.
   387  	alloc = autoid.NewSlabPredictor(causetstore, 1, true, autoid.AutoRandomType)
   388  	c.Assert(alloc, NotNil)
   389  	c.Assert(err, IsNil)
   390  	c.Assert(globalAutoID, Equals, int64(1))
   391  
   392  	increment := int64(2)
   393  	n = math.MaxUint64 - 100
   394  	offset := int64(n)
   395  
   396  	min, max, err = alloc.Alloc(5, 2, increment, offset)
   397  	c.Assert(err, IsNil)
   398  	c.Assert(uint64(min), Equals, uint64(math.MaxUint64-101))
   399  	c.Assert(uint64(max), Equals, uint64(math.MaxUint64-98))
   400  
   401  	c.Assert(max-min, Equals, autoid.CalcNeededBatchSize(int64(uint64(offset)-1), 2, increment, offset, true))
   402  	firstID := autoid.SeekToFirstAutoIDUnSigned(uint64(min), uint64(increment), uint64(offset))
   403  	c.Assert(firstID, Equals, uint64(math.MaxUint64-100))
   404  
   405  }
   406  
   407  // TestConcurrentAlloc is used for the test that
   408  // multiple allocators allocate ID with the same causet ID concurrently.
   409  func (*testSuite) TestConcurrentAlloc(c *C) {
   410  	causetstore, err := mockstore.NewMockStore()
   411  	c.Assert(err, IsNil)
   412  	defer causetstore.Close()
   413  	autoid.SetStep(100)
   414  	defer func() {
   415  		autoid.SetStep(5000)
   416  	}()
   417  
   418  	dbID := int64(2)
   419  	tblID := int64(100)
   420  	err = ekv.RunInNewTxn(causetstore, false, func(txn ekv.Transaction) error {
   421  		m := spacetime.NewMeta(txn)
   422  		err = m.CreateDatabase(&perceptron.DBInfo{ID: dbID, Name: perceptron.NewCIStr("a")})
   423  		c.Assert(err, IsNil)
   424  		err = m.CreateBlockOrView(dbID, &perceptron.BlockInfo{ID: tblID, Name: perceptron.NewCIStr("t")})
   425  		c.Assert(err, IsNil)
   426  		return nil
   427  	})
   428  	c.Assert(err, IsNil)
   429  
   430  	var mu sync.Mutex
   431  	wg := sync.WaitGroup{}
   432  	m := map[int64]struct{}{}
   433  	count := 10
   434  	errCh := make(chan error, count)
   435  
   436  	allocIDs := func() {
   437  		alloc := autoid.NewSlabPredictor(causetstore, dbID, false, autoid.RowIDAllocType)
   438  		for j := 0; j < int(autoid.GetStep())+5; j++ {
   439  			_, id, err1 := alloc.Alloc(tblID, 1, 1, 1)
   440  			if err1 != nil {
   441  				errCh <- err1
   442  				break
   443  			}
   444  
   445  			mu.Lock()
   446  			if _, ok := m[id]; ok {
   447  				errCh <- fmt.Errorf("duplicate id:%v", id)
   448  				mu.Unlock()
   449  				break
   450  			}
   451  			m[id] = struct{}{}
   452  			mu.Unlock()
   453  
   454  			//test Alloc N
   455  			N := rand.Uint64() % 100
   456  			min, max, err1 := alloc.Alloc(tblID, N, 1, 1)
   457  			if err1 != nil {
   458  				errCh <- err1
   459  				break
   460  			}
   461  
   462  			errFlag := false
   463  			mu.Lock()
   464  			for i := min + 1; i <= max; i++ {
   465  				if _, ok := m[i]; ok {
   466  					errCh <- fmt.Errorf("duplicate id:%v", i)
   467  					errFlag = true
   468  					mu.Unlock()
   469  					break
   470  				}
   471  				m[i] = struct{}{}
   472  			}
   473  			if errFlag {
   474  				break
   475  			}
   476  			mu.Unlock()
   477  		}
   478  	}
   479  	for i := 0; i < count; i++ {
   480  		wg.Add(1)
   481  		go func(num int) {
   482  			defer wg.Done()
   483  			time.Sleep(time.Duration(num%10) * time.Microsecond)
   484  			allocIDs()
   485  		}(i)
   486  	}
   487  	wg.Wait()
   488  
   489  	close(errCh)
   490  	err = <-errCh
   491  	c.Assert(err, IsNil)
   492  }
   493  
   494  // TestRollbackAlloc tests that when the allocation transaction commit failed,
   495  // the local variable base and end doesn't change.
   496  func (*testSuite) TestRollbackAlloc(c *C) {
   497  	causetstore, err := mockstore.NewMockStore()
   498  	c.Assert(err, IsNil)
   499  	defer causetstore.Close()
   500  	dbID := int64(1)
   501  	tblID := int64(2)
   502  	err = ekv.RunInNewTxn(causetstore, false, func(txn ekv.Transaction) error {
   503  		m := spacetime.NewMeta(txn)
   504  		err = m.CreateDatabase(&perceptron.DBInfo{ID: dbID, Name: perceptron.NewCIStr("a")})
   505  		c.Assert(err, IsNil)
   506  		err = m.CreateBlockOrView(dbID, &perceptron.BlockInfo{ID: tblID, Name: perceptron.NewCIStr("t")})
   507  		c.Assert(err, IsNil)
   508  		return nil
   509  	})
   510  	c.Assert(err, IsNil)
   511  
   512  	injectConf := new(ekv.InjectionConfig)
   513  	injectConf.SetCommitError(errors.New("injected"))
   514  	injectedStore := ekv.NewInjectedStore(causetstore, injectConf)
   515  	alloc := autoid.NewSlabPredictor(injectedStore, 1, false, autoid.RowIDAllocType)
   516  	_, _, err = alloc.Alloc(2, 1, 1, 1)
   517  	c.Assert(err, NotNil)
   518  	c.Assert(alloc.Base(), Equals, int64(0))
   519  	c.Assert(alloc.End(), Equals, int64(0))
   520  
   521  	err = alloc.Rebase(2, 100, true)
   522  	c.Assert(err, NotNil)
   523  	c.Assert(alloc.Base(), Equals, int64(0))
   524  	c.Assert(alloc.End(), Equals, int64(0))
   525  }
   526  
   527  // TestNextStep tests generate next auto id step.
   528  func (*testSuite) TestNextStep(c *C) {
   529  	nextStep := autoid.NextStep(2000000, 1*time.Nanosecond)
   530  	c.Assert(nextStep, Equals, int64(2000000))
   531  	nextStep = autoid.NextStep(678910, 10*time.Second)
   532  	c.Assert(nextStep, Equals, int64(678910))
   533  	nextStep = autoid.NextStep(50000, 10*time.Minute)
   534  	c.Assert(nextStep, Equals, int64(30000))
   535  }
   536  
   537  func BenchmarkSlabPredictor_Alloc(b *testing.B) {
   538  	b.StopTimer()
   539  	causetstore, err := mockstore.NewMockStore()
   540  	if err != nil {
   541  		return
   542  	}
   543  	defer causetstore.Close()
   544  	dbID := int64(1)
   545  	tblID := int64(2)
   546  	err = ekv.RunInNewTxn(causetstore, false, func(txn ekv.Transaction) error {
   547  		m := spacetime.NewMeta(txn)
   548  		err = m.CreateDatabase(&perceptron.DBInfo{ID: dbID, Name: perceptron.NewCIStr("a")})
   549  		if err != nil {
   550  			return err
   551  		}
   552  		err = m.CreateBlockOrView(dbID, &perceptron.BlockInfo{ID: tblID, Name: perceptron.NewCIStr("t")})
   553  		if err != nil {
   554  			return err
   555  		}
   556  		return nil
   557  	})
   558  	if err != nil {
   559  		return
   560  	}
   561  	alloc := autoid.NewSlabPredictor(causetstore, 1, false, autoid.RowIDAllocType)
   562  	b.StartTimer()
   563  	for i := 0; i < b.N; i++ {
   564  		alloc.Alloc(2, 1, 1, 1)
   565  	}
   566  }
   567  
   568  func BenchmarkSlabPredictor_SequenceAlloc(b *testing.B) {
   569  	b.StopTimer()
   570  	causetstore, err := mockstore.NewMockStore()
   571  	if err != nil {
   572  		return
   573  	}
   574  	defer causetstore.Close()
   575  	var seq *perceptron.SequenceInfo
   576  	var sequenceBase int64
   577  	err = ekv.RunInNewTxn(causetstore, false, func(txn ekv.Transaction) error {
   578  		m := spacetime.NewMeta(txn)
   579  		err = m.CreateDatabase(&perceptron.DBInfo{ID: 1, Name: perceptron.NewCIStr("a")})
   580  		if err != nil {
   581  			return err
   582  		}
   583  		seq = &perceptron.SequenceInfo{
   584  			Start:      1,
   585  			Cycle:      true,
   586  			Cache:      false,
   587  			MinValue:   -10,
   588  			MaxValue:   math.MaxInt64,
   589  			Increment:  2,
   590  			CacheValue: 2000000,
   591  		}
   592  		seqBlock := &perceptron.BlockInfo{
   593  			ID:       1,
   594  			Name:     perceptron.NewCIStr("seq"),
   595  			Sequence: seq,
   596  		}
   597  		sequenceBase = seq.Start - 1
   598  		err = m.CreateSequenceAndSetSeqValue(1, seqBlock, sequenceBase)
   599  		return err
   600  	})
   601  	if err != nil {
   602  		return
   603  	}
   604  	alloc := autoid.NewSequenceSlabPredictor(causetstore, 1, seq)
   605  	b.StartTimer()
   606  	for i := 0; i < b.N; i++ {
   607  		_, _, _, err := alloc.AllocSeqCache(1)
   608  		if err != nil {
   609  			fmt.Println("err")
   610  		}
   611  	}
   612  }
   613  
   614  func BenchmarkSlabPredictor_Seek(b *testing.B) {
   615  	base := int64(21421948021)
   616  	offset := int64(-351354365326)
   617  	increment := int64(3)
   618  	b.StartTimer()
   619  	for i := 0; i < b.N; i++ {
   620  		autoid.CalcSequenceBatchSize(base, 3, increment, offset, math.MinInt64, math.MaxInt64)
   621  	}
   622  }
   623  
   624  func (*testSuite) TestSequenceAutoid(c *C) {
   625  	causetstore, err := mockstore.NewMockStore()
   626  	c.Assert(err, IsNil)
   627  	defer causetstore.Close()
   628  
   629  	var seq *perceptron.SequenceInfo
   630  	var sequenceBase int64
   631  	err = ekv.RunInNewTxn(causetstore, false, func(txn ekv.Transaction) error {
   632  		m := spacetime.NewMeta(txn)
   633  		err = m.CreateDatabase(&perceptron.DBInfo{ID: 1, Name: perceptron.NewCIStr("a")})
   634  		c.Assert(err, IsNil)
   635  		seq = &perceptron.SequenceInfo{
   636  			Start:      1,
   637  			Cycle:      true,
   638  			Cache:      true,
   639  			MinValue:   -10,
   640  			MaxValue:   10,
   641  			Increment:  2,
   642  			CacheValue: 3,
   643  		}
   644  		seqBlock := &perceptron.BlockInfo{
   645  			ID:       1,
   646  			Name:     perceptron.NewCIStr("seq"),
   647  			Sequence: seq,
   648  		}
   649  		sequenceBase = seq.Start - 1
   650  		err = m.CreateSequenceAndSetSeqValue(1, seqBlock, sequenceBase)
   651  		c.Assert(err, IsNil)
   652  		return nil
   653  	})
   654  	c.Assert(err, IsNil)
   655  
   656  	alloc := autoid.NewSequenceSlabPredictor(causetstore, 1, seq)
   657  	c.Assert(alloc, NotNil)
   658  
   659  	// allocate sequence cache.
   660  	base, end, round, err := alloc.AllocSeqCache(1)
   661  	c.Assert(err, IsNil)
   662  	c.Assert(base, Equals, int64(0))
   663  	c.Assert(end, Equals, int64(5))
   664  	c.Assert(round, Equals, int64(0))
   665  
   666  	// test the sequence batch size.
   667  	offset := seq.Start
   668  	size, err := autoid.CalcSequenceBatchSize(sequenceBase, seq.CacheValue, seq.Increment, offset, seq.MinValue, seq.MaxValue)
   669  	c.Assert(err, IsNil)
   670  	c.Assert(size, Equals, end-base)
   671  
   672  	// simulate the next value allocation.
   673  	nextVal, ok := autoid.SeekToFirstSequenceValue(base, seq.Increment, offset, base, end)
   674  	c.Assert(ok, Equals, true)
   675  	c.Assert(nextVal, Equals, int64(1))
   676  	base = nextVal
   677  
   678  	nextVal, ok = autoid.SeekToFirstSequenceValue(base, seq.Increment, offset, base, end)
   679  	c.Assert(ok, Equals, true)
   680  	c.Assert(nextVal, Equals, int64(3))
   681  	base = nextVal
   682  
   683  	nextVal, ok = autoid.SeekToFirstSequenceValue(base, seq.Increment, offset, base, end)
   684  	c.Assert(ok, Equals, true)
   685  	c.Assert(nextVal, Equals, int64(5))
   686  
   687  	base, end, round, err = alloc.AllocSeqCache(1)
   688  	c.Assert(err, IsNil)
   689  	c.Assert(base, Equals, int64(5))
   690  	c.Assert(end, Equals, int64(10))
   691  	c.Assert(round, Equals, int64(0))
   692  
   693  	// test the sequence batch size.
   694  	size, err = autoid.CalcSequenceBatchSize(sequenceBase, seq.CacheValue, seq.Increment, offset, seq.MinValue, seq.MaxValue)
   695  	c.Assert(err, IsNil)
   696  	c.Assert(size, Equals, end-base)
   697  
   698  	nextVal, ok = autoid.SeekToFirstSequenceValue(base, seq.Increment, offset, base, end)
   699  	c.Assert(ok, Equals, true)
   700  	c.Assert(nextVal, Equals, int64(7))
   701  	base = nextVal
   702  
   703  	nextVal, ok = autoid.SeekToFirstSequenceValue(base, seq.Increment, offset, base, end)
   704  	c.Assert(ok, Equals, true)
   705  	c.Assert(nextVal, Equals, int64(9))
   706  	base = nextVal
   707  
   708  	_, ok = autoid.SeekToFirstSequenceValue(base, seq.Increment, offset, base, end)
   709  	// the rest in cache in not enough for next value.
   710  	c.Assert(ok, Equals, false)
   711  
   712  	base, end, round, err = alloc.AllocSeqCache(1)
   713  	c.Assert(err, IsNil)
   714  	c.Assert(base, Equals, int64(-11))
   715  	c.Assert(end, Equals, int64(-6))
   716  	// the round is already in cycle.
   717  	c.Assert(round, Equals, int64(1))
   718  
   719  	// test the sequence batch size.
   720  	size, err = autoid.CalcSequenceBatchSize(sequenceBase, seq.CacheValue, seq.Increment, offset, seq.MinValue, seq.MaxValue)
   721  	c.Assert(err, IsNil)
   722  	c.Assert(size, Equals, end-base)
   723  
   724  	offset = seq.MinValue
   725  	nextVal, ok = autoid.SeekToFirstSequenceValue(base, seq.Increment, offset, base, end)
   726  	c.Assert(ok, Equals, true)
   727  	c.Assert(nextVal, Equals, int64(-10))
   728  	base = nextVal
   729  
   730  	nextVal, ok = autoid.SeekToFirstSequenceValue(base, seq.Increment, offset, base, end)
   731  	c.Assert(ok, Equals, true)
   732  	c.Assert(nextVal, Equals, int64(-8))
   733  	base = nextVal
   734  
   735  	nextVal, ok = autoid.SeekToFirstSequenceValue(base, seq.Increment, offset, base, end)
   736  	c.Assert(ok, Equals, true)
   737  	c.Assert(nextVal, Equals, int64(-6))
   738  	base = nextVal
   739  
   740  	_, ok = autoid.SeekToFirstSequenceValue(base, seq.Increment, offset, base, end)
   741  	// the cache is already empty.
   742  	c.Assert(ok, Equals, false)
   743  }
   744  
   745  func (*testSuite) TestConcurrentAllocSequence(c *C) {
   746  	causetstore, err := mockstore.NewMockStore()
   747  	c.Assert(err, IsNil)
   748  	defer causetstore.Close()
   749  
   750  	var seq *perceptron.SequenceInfo
   751  	var sequenceBase int64
   752  	err = ekv.RunInNewTxn(causetstore, false, func(txn ekv.Transaction) error {
   753  		m := spacetime.NewMeta(txn)
   754  		err1 := m.CreateDatabase(&perceptron.DBInfo{ID: 2, Name: perceptron.NewCIStr("a")})
   755  		c.Assert(err1, IsNil)
   756  		seq = &perceptron.SequenceInfo{
   757  			Start:      100,
   758  			Cycle:      false,
   759  			Cache:      true,
   760  			MinValue:   -100,
   761  			MaxValue:   100,
   762  			Increment:  -2,
   763  			CacheValue: 3,
   764  		}
   765  		seqBlock := &perceptron.BlockInfo{
   766  			ID:       2,
   767  			Name:     perceptron.NewCIStr("seq"),
   768  			Sequence: seq,
   769  		}
   770  		if seq.Increment >= 0 {
   771  			sequenceBase = seq.Start - 1
   772  		} else {
   773  			sequenceBase = seq.Start + 1
   774  		}
   775  		err1 = m.CreateSequenceAndSetSeqValue(2, seqBlock, sequenceBase)
   776  		c.Assert(err1, IsNil)
   777  		return nil
   778  	})
   779  	c.Assert(err, IsNil)
   780  
   781  	var mu sync.Mutex
   782  	wg := sync.WaitGroup{}
   783  	m := map[int64]struct{}{}
   784  	count := 10
   785  	errCh := make(chan error, count)
   786  
   787  	allocSequence := func() {
   788  		alloc := autoid.NewSequenceSlabPredictor(causetstore, 2, seq)
   789  		for j := 0; j < 3; j++ {
   790  			base, end, _, err1 := alloc.AllocSeqCache(2)
   791  			if err1 != nil {
   792  				errCh <- err1
   793  				break
   794  			}
   795  
   796  			errFlag := false
   797  			mu.Lock()
   798  			// sequence is negative-growth here.
   799  			for i := base - 1; i >= end; i-- {
   800  				if _, ok := m[i]; ok {
   801  					errCh <- fmt.Errorf("duplicate id:%v", i)
   802  					errFlag = true
   803  					mu.Unlock()
   804  					break
   805  				}
   806  				m[i] = struct{}{}
   807  			}
   808  			if errFlag {
   809  				break
   810  			}
   811  			mu.Unlock()
   812  		}
   813  	}
   814  	for i := 0; i < count; i++ {
   815  		wg.Add(1)
   816  		go func(num int) {
   817  			time.Sleep(time.Duration(num%10) * time.Microsecond)
   818  			allocSequence()
   819  			wg.Done()
   820  		}(i)
   821  	}
   822  	wg.Wait()
   823  
   824  	close(errCh)
   825  	err = <-errCh
   826  	c.Assert(err, IsNil)
   827  }
   828  
   829  // Fix a computation logic bug in allocator computation.
   830  func (*testSuite) TestAllocComputationIssue(c *C) {
   831  	c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/spacetime/autoid/mockAutoIDCustomize", `return(true)`), IsNil)
   832  	defer func() {
   833  		c.Assert(failpoint.Disable("github.com/whtcorpsinc/milevadb/spacetime/autoid/mockAutoIDCustomize"), IsNil)
   834  	}()
   835  
   836  	causetstore, err := mockstore.NewMockStore()
   837  	c.Assert(err, IsNil)
   838  	defer causetstore.Close()
   839  
   840  	err = ekv.RunInNewTxn(causetstore, false, func(txn ekv.Transaction) error {
   841  		m := spacetime.NewMeta(txn)
   842  		err = m.CreateDatabase(&perceptron.DBInfo{ID: 1, Name: perceptron.NewCIStr("a")})
   843  		c.Assert(err, IsNil)
   844  		err = m.CreateBlockOrView(1, &perceptron.BlockInfo{ID: 1, Name: perceptron.NewCIStr("t")})
   845  		c.Assert(err, IsNil)
   846  		err = m.CreateBlockOrView(1, &perceptron.BlockInfo{ID: 2, Name: perceptron.NewCIStr("t1")})
   847  		c.Assert(err, IsNil)
   848  		return nil
   849  	})
   850  	c.Assert(err, IsNil)
   851  
   852  	// Since the test here is applicable to any type of allocators, autoid.RowIDAllocType is chosen.
   853  	unsignedAlloc := autoid.NewSlabPredictor(causetstore, 1, true, autoid.RowIDAllocType)
   854  	c.Assert(unsignedAlloc, NotNil)
   855  	signedAlloc := autoid.NewSlabPredictor(causetstore, 1, false, autoid.RowIDAllocType)
   856  	c.Assert(signedAlloc, NotNil)
   857  
   858  	// the next valid two value must be 13 & 16, batch size = 6.
   859  	err = unsignedAlloc.Rebase(1, 10, false)
   860  	c.Assert(err, IsNil)
   861  	// the next valid two value must be 10 & 13, batch size = 6.
   862  	err = signedAlloc.Rebase(2, 7, false)
   863  	c.Assert(err, IsNil)
   864  	// Simulate the rest cache is not enough for next batch, assuming 10 & 13, batch size = 4.
   865  	autoid.TestModifyBaseAndEndInjection(unsignedAlloc, 9, 9)
   866  	// Simulate the rest cache is not enough for next batch, assuming 10 & 13, batch size = 4.
   867  	autoid.TestModifyBaseAndEndInjection(signedAlloc, 4, 6)
   868  
   869  	// Here will recompute the new allocator batch size base on new base = 10, which will get 6.
   870  	min, max, err := unsignedAlloc.Alloc(1, 2, 3, 1)
   871  	c.Assert(err, IsNil)
   872  	c.Assert(min, Equals, int64(10))
   873  	c.Assert(max, Equals, int64(16))
   874  	min, max, err = signedAlloc.Alloc(2, 2, 3, 1)
   875  	c.Assert(err, IsNil)
   876  	c.Assert(min, Equals, int64(7))
   877  	c.Assert(max, Equals, int64(13))
   878  }