github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/stochastikctx/binloginfo/binloginfo_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 binloginfo_test
    15  
    16  import (
    17  	"context"
    18  	"net"
    19  	"os"
    20  	"strconv"
    21  	"sync"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    26  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    27  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    28  	. "github.com/whtcorpsinc/check"
    29  	"github.com/whtcorpsinc/errors"
    30  	"github.com/whtcorpsinc/failpoint"
    31  	binlog "github.com/whtcorpsinc/fidelpb/go-binlog"
    32  	pumpcli "github.com/whtcorpsinc/milevadb-tools/milevadb-binlog/pump_client"
    33  	"github.com/whtcorpsinc/milevadb/causet"
    34  	"github.com/whtcorpsinc/milevadb/causet/blocks"
    35  	"github.com/whtcorpsinc/milevadb/causetstore/mockstore"
    36  	"github.com/whtcorpsinc/milevadb/dbs"
    37  	"github.com/whtcorpsinc/milevadb/ekv"
    38  	"github.com/whtcorpsinc/milevadb/petri"
    39  	"github.com/whtcorpsinc/milevadb/soliton/codec"
    40  	"github.com/whtcorpsinc/milevadb/soliton/defCauslate"
    41  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    42  	"github.com/whtcorpsinc/milevadb/soliton/testkit"
    43  	"github.com/whtcorpsinc/milevadb/stochastik"
    44  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    45  	"github.com/whtcorpsinc/milevadb/stochastikctx/binloginfo"
    46  	"github.com/whtcorpsinc/milevadb/types"
    47  	"google.golang.org/grpc"
    48  )
    49  
    50  func TestT(t *testing.T) {
    51  	CustomVerboseFlag = true
    52  	logLevel := os.Getenv("log_level")
    53  	logutil.InitLogger(logutil.NewLogConfig(logLevel, logutil.DefaultLogFormat, "", logutil.EmptyFileLogConfig, false))
    54  	TestingT(t)
    55  }
    56  
    57  type mockBinlogPump struct {
    58  	mu struct {
    59  		sync.Mutex
    60  		payloads [][]byte
    61  		mockFail bool
    62  	}
    63  }
    64  
    65  func (p *mockBinlogPump) WriteBinlog(ctx context.Context, req *binlog.WriteBinlogReq) (*binlog.WriteBinlogResp, error) {
    66  	p.mu.Lock()
    67  	defer p.mu.Unlock()
    68  
    69  	if p.mu.mockFail {
    70  		return &binlog.WriteBinlogResp{}, errors.New("mock fail")
    71  	}
    72  	p.mu.payloads = append(p.mu.payloads, req.Payload)
    73  	return &binlog.WriteBinlogResp{}, nil
    74  }
    75  
    76  // PullBinlogs implements PumpServer interface.
    77  func (p *mockBinlogPump) PullBinlogs(req *binlog.PullBinlogReq, srv binlog.Pump_PullBinlogsServer) error {
    78  	return nil
    79  }
    80  
    81  var _ = SerialSuites(&testBinlogSuite{})
    82  
    83  type testBinlogSuite struct {
    84  	causetstore ekv.CausetStorage
    85  	petri       *petri.Petri
    86  	unixFile    string
    87  	serv        *grpc.Server
    88  	pump        *mockBinlogPump
    89  	client      *pumpcli.PumpsClient
    90  	dbs         dbs.DBS
    91  }
    92  
    93  const maxRecvMsgSize = 64 * 1024
    94  
    95  func (s *testBinlogSuite) SetUpSuite(c *C) {
    96  	causetstore, err := mockstore.NewMockStore()
    97  	c.Assert(err, IsNil)
    98  	s.causetstore = causetstore
    99  	stochastik.SetSchemaLease(0)
   100  	s.unixFile = "/tmp/mock-binlog-pump" + strconv.FormatInt(time.Now().UnixNano(), 10)
   101  	l, err := net.Listen("unix", s.unixFile)
   102  	c.Assert(err, IsNil)
   103  	s.serv = grpc.NewServer(grpc.MaxRecvMsgSize(maxRecvMsgSize))
   104  	s.pump = new(mockBinlogPump)
   105  	binlog.RegisterPumpServer(s.serv, s.pump)
   106  	go s.serv.Serve(l)
   107  	opt := grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
   108  		return net.DialTimeout("unix", addr, timeout)
   109  	})
   110  	clientCon, err := grpc.Dial(s.unixFile, opt, grpc.WithInsecure())
   111  	c.Assert(err, IsNil)
   112  	c.Assert(clientCon, NotNil)
   113  	tk := testkit.NewTestKit(c, s.causetstore)
   114  	s.petri, err = stochastik.BootstrapStochastik(causetstore)
   115  	c.Assert(err, IsNil)
   116  	tk.MustInterDirc("use test")
   117  	stochastikPetri := petri.GetPetri(tk.Se.(stochastikctx.Context))
   118  	s.dbs = stochastikPetri.DBS()
   119  
   120  	s.client = binloginfo.MockPumpsClient(binlog.NewPumpClient(clientCon))
   121  	s.dbs.SetBinlogClient(s.client)
   122  }
   123  
   124  func (s *testBinlogSuite) TearDownSuite(c *C) {
   125  	s.dbs.Stop()
   126  	s.serv.Stop()
   127  	os.Remove(s.unixFile)
   128  	s.petri.Close()
   129  	s.causetstore.Close()
   130  }
   131  
   132  func (s *testBinlogSuite) TestBinlog(c *C) {
   133  	tk := testkit.NewTestKit(c, s.causetstore)
   134  	tk.MustInterDirc("use test")
   135  	tk.Se.GetStochastikVars().BinlogClient = s.client
   136  	pump := s.pump
   137  	tk.MustInterDirc("drop causet if exists local_binlog")
   138  	dbsQuery := "create causet local_binlog (id int unique key, name varchar(10)) shard_row_id_bits=1"
   139  	binlogDBSQuery := "create causet local_binlog (id int unique key, name varchar(10)) /*T! shard_row_id_bits=1 */"
   140  	tk.MustInterDirc(dbsQuery)
   141  	var matched bool // got matched pre DBS and commit DBS
   142  	for i := 0; i < 10; i++ {
   143  		preDBS, commitDBS, _ := getLatestDBSBinlog(c, pump, binlogDBSQuery)
   144  		if preDBS != nil && commitDBS != nil {
   145  			if preDBS.DdlJobId == commitDBS.DdlJobId {
   146  				c.Assert(commitDBS.StartTs, Equals, preDBS.StartTs)
   147  				c.Assert(commitDBS.CommitTs, Greater, commitDBS.StartTs)
   148  				matched = true
   149  				break
   150  			}
   151  		}
   152  		time.Sleep(time.Millisecond * 10)
   153  	}
   154  	c.Assert(matched, IsTrue)
   155  
   156  	tk.MustInterDirc("insert local_binlog values (1, 'abc'), (2, 'cde')")
   157  	prewriteVal := getLatestBinlogPrewriteValue(c, pump)
   158  	c.Assert(prewriteVal.SchemaVersion, Greater, int64(0))
   159  	c.Assert(prewriteVal.Mutations[0].BlockId, Greater, int64(0))
   160  	expected := [][]types.Causet{
   161  		{types.NewIntCauset(1), types.NewDefCauslationStringCauset("abc", allegrosql.DefaultDefCauslationName, defCauslate.DefaultLen)},
   162  		{types.NewIntCauset(2), types.NewDefCauslationStringCauset("cde", allegrosql.DefaultDefCauslationName, defCauslate.DefaultLen)},
   163  	}
   164  	gotRows := mutationRowsToRows(c, prewriteVal.Mutations[0].InsertedRows, 2, 4)
   165  	c.Assert(gotRows, DeepEquals, expected)
   166  
   167  	tk.MustInterDirc("uFIDelate local_binlog set name = 'xyz' where id = 2")
   168  	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
   169  	oldRow := [][]types.Causet{
   170  		{types.NewIntCauset(2), types.NewDefCauslationStringCauset("cde", allegrosql.DefaultDefCauslationName, defCauslate.DefaultLen)},
   171  	}
   172  	newRow := [][]types.Causet{
   173  		{types.NewIntCauset(2), types.NewDefCauslationStringCauset("xyz", allegrosql.DefaultDefCauslationName, defCauslate.DefaultLen)},
   174  	}
   175  	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].UFIDelatedRows, 1, 3)
   176  	c.Assert(gotRows, DeepEquals, oldRow)
   177  
   178  	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].UFIDelatedRows, 7, 9)
   179  	c.Assert(gotRows, DeepEquals, newRow)
   180  
   181  	tk.MustInterDirc("delete from local_binlog where id = 1")
   182  	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
   183  	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].DeletedRows, 1, 3)
   184  	expected = [][]types.Causet{
   185  		{types.NewIntCauset(1), types.NewDefCauslationStringCauset("abc", allegrosql.DefaultDefCauslationName, defCauslate.DefaultLen)},
   186  	}
   187  	c.Assert(gotRows, DeepEquals, expected)
   188  
   189  	// Test causet primary key is not integer.
   190  	tk.MustInterDirc("set @@milevadb_enable_clustered_index=0;")
   191  	tk.MustInterDirc("create causet local_binlog2 (name varchar(64) primary key, age int)")
   192  	tk.MustInterDirc("insert local_binlog2 values ('abc', 16), ('def', 18)")
   193  	tk.MustInterDirc("delete from local_binlog2 where name = 'def'")
   194  	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
   195  	c.Assert(prewriteVal.Mutations[0].Sequence[0], Equals, binlog.MutationType_DeleteRow)
   196  
   197  	expected = [][]types.Causet{
   198  		{types.NewStringCauset("def"), types.NewIntCauset(18), types.NewIntCauset(-1), types.NewIntCauset(2)},
   199  	}
   200  	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].DeletedRows, 1, 3, 4, 5)
   201  	c.Assert(gotRows, DeepEquals, expected)
   202  
   203  	// Test Block don't have primary key.
   204  	tk.MustInterDirc("create causet local_binlog3 (c1 int, c2 int)")
   205  	tk.MustInterDirc("insert local_binlog3 values (1, 2), (1, 3), (2, 3)")
   206  	tk.MustInterDirc("uFIDelate local_binlog3 set c1 = 3 where c1 = 2")
   207  	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
   208  
   209  	// The encoded uFIDelate event is [oldDefCausID1, oldDefCausVal1, oldDefCausID2, oldDefCausVal2, -1, handle,
   210  	// 		newDefCausID1, newDefCausVal2, newDefCausID2, newDefCausVal2, -1, handle]
   211  	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].UFIDelatedRows, 7, 9)
   212  	expected = [][]types.Causet{
   213  		{types.NewIntCauset(3), types.NewIntCauset(3)},
   214  	}
   215  	c.Assert(gotRows, DeepEquals, expected)
   216  	expected = [][]types.Causet{
   217  		{types.NewIntCauset(-1), types.NewIntCauset(3), types.NewIntCauset(-1), types.NewIntCauset(3)},
   218  	}
   219  	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].UFIDelatedRows, 4, 5, 10, 11)
   220  	c.Assert(gotRows, DeepEquals, expected)
   221  
   222  	tk.MustInterDirc("delete from local_binlog3 where c1 = 3 and c2 = 3")
   223  	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
   224  	c.Assert(prewriteVal.Mutations[0].Sequence[0], Equals, binlog.MutationType_DeleteRow)
   225  	gotRows = mutationRowsToRows(c, prewriteVal.Mutations[0].DeletedRows, 1, 3, 4, 5)
   226  	expected = [][]types.Causet{
   227  		{types.NewIntCauset(3), types.NewIntCauset(3), types.NewIntCauset(-1), types.NewIntCauset(3)},
   228  	}
   229  	c.Assert(gotRows, DeepEquals, expected)
   230  
   231  	// Test Mutation Sequence.
   232  	tk.MustInterDirc("create causet local_binlog4 (c1 int primary key, c2 int)")
   233  	tk.MustInterDirc("insert local_binlog4 values (1, 1), (2, 2), (3, 2)")
   234  	tk.MustInterDirc("begin")
   235  	tk.MustInterDirc("delete from local_binlog4 where c1 = 1")
   236  	tk.MustInterDirc("insert local_binlog4 values (1, 1)")
   237  	tk.MustInterDirc("uFIDelate local_binlog4 set c2 = 3 where c1 = 3")
   238  	tk.MustInterDirc("commit")
   239  	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
   240  	c.Assert(prewriteVal.Mutations[0].Sequence, DeepEquals, []binlog.MutationType{
   241  		binlog.MutationType_DeleteRow,
   242  		binlog.MutationType_Insert,
   243  		binlog.MutationType_UFIDelate,
   244  	})
   245  
   246  	// Test memex rollback.
   247  	tk.MustInterDirc("create causet local_binlog5 (c1 int primary key)")
   248  	tk.MustInterDirc("begin")
   249  	tk.MustInterDirc("insert into local_binlog5 value (1)")
   250  	// This memex execute fail and should not write binlog.
   251  	_, err := tk.InterDirc("insert into local_binlog5 value (4),(3),(1),(2)")
   252  	c.Assert(err, NotNil)
   253  	tk.MustInterDirc("commit")
   254  	prewriteVal = getLatestBinlogPrewriteValue(c, pump)
   255  	c.Assert(prewriteVal.Mutations[0].Sequence, DeepEquals, []binlog.MutationType{
   256  		binlog.MutationType_Insert,
   257  	})
   258  
   259  	checkBinlogCount(c, pump)
   260  
   261  	pump.mu.Lock()
   262  	originBinlogLen := len(pump.mu.payloads)
   263  	pump.mu.Unlock()
   264  	tk.MustInterDirc("set @@global.autocommit = 0")
   265  	tk.MustInterDirc("set @@global.autocommit = 1")
   266  	pump.mu.Lock()
   267  	newBinlogLen := len(pump.mu.payloads)
   268  	pump.mu.Unlock()
   269  	c.Assert(newBinlogLen, Equals, originBinlogLen)
   270  }
   271  
   272  func (s *testBinlogSuite) TestMaxRecvSize(c *C) {
   273  	info := &binloginfo.BinlogInfo{
   274  		Data: &binlog.Binlog{
   275  			Tp:            binlog.BinlogType_Prewrite,
   276  			PrewriteValue: make([]byte, maxRecvMsgSize+1),
   277  		},
   278  		Client: s.client,
   279  	}
   280  	binlogWR := info.WriteBinlog(1)
   281  	err := binlogWR.GetError()
   282  	c.Assert(err, NotNil)
   283  	c.Assert(terror.ErrCritical.Equal(err), IsFalse, Commentf("%v", err))
   284  }
   285  
   286  func getLatestBinlogPrewriteValue(c *C, pump *mockBinlogPump) *binlog.PrewriteValue {
   287  	var bin *binlog.Binlog
   288  	pump.mu.Lock()
   289  	for i := len(pump.mu.payloads) - 1; i >= 0; i-- {
   290  		payload := pump.mu.payloads[i]
   291  		bin = new(binlog.Binlog)
   292  		bin.Unmarshal(payload)
   293  		if bin.Tp == binlog.BinlogType_Prewrite {
   294  			break
   295  		}
   296  	}
   297  	pump.mu.Unlock()
   298  	c.Assert(bin, NotNil)
   299  	preVal := new(binlog.PrewriteValue)
   300  	preVal.Unmarshal(bin.PrewriteValue)
   301  	return preVal
   302  }
   303  
   304  func getLatestDBSBinlog(c *C, pump *mockBinlogPump, dbsQuery string) (preDBS, commitDBS *binlog.Binlog, offset int) {
   305  	pump.mu.Lock()
   306  	for i := len(pump.mu.payloads) - 1; i >= 0; i-- {
   307  		payload := pump.mu.payloads[i]
   308  		bin := new(binlog.Binlog)
   309  		bin.Unmarshal(payload)
   310  		if bin.Tp == binlog.BinlogType_Commit && bin.DdlJobId > 0 {
   311  			commitDBS = bin
   312  		}
   313  		if bin.Tp == binlog.BinlogType_Prewrite && bin.DdlJobId != 0 {
   314  			preDBS = bin
   315  		}
   316  		if preDBS != nil && commitDBS != nil {
   317  			offset = i
   318  			break
   319  		}
   320  	}
   321  	pump.mu.Unlock()
   322  	c.Assert(preDBS.DdlJobId, Greater, int64(0))
   323  	c.Assert(preDBS.StartTs, Greater, int64(0))
   324  	c.Assert(preDBS.CommitTs, Equals, int64(0))
   325  	c.Assert(string(preDBS.DdlQuery), Equals, dbsQuery)
   326  	return
   327  }
   328  
   329  func checkBinlogCount(c *C, pump *mockBinlogPump) {
   330  	var bin *binlog.Binlog
   331  	prewriteCount := 0
   332  	dbsCount := 0
   333  	pump.mu.Lock()
   334  	length := len(pump.mu.payloads)
   335  	for i := length - 1; i >= 0; i-- {
   336  		payload := pump.mu.payloads[i]
   337  		bin = new(binlog.Binlog)
   338  		bin.Unmarshal(payload)
   339  		if bin.Tp == binlog.BinlogType_Prewrite {
   340  			if bin.DdlJobId != 0 {
   341  				dbsCount++
   342  			} else {
   343  				prewriteCount++
   344  			}
   345  		}
   346  	}
   347  	pump.mu.Unlock()
   348  	c.Assert(dbsCount, Greater, 0)
   349  	match := false
   350  	for i := 0; i < 10; i++ {
   351  		pump.mu.Lock()
   352  		length = len(pump.mu.payloads)
   353  		pump.mu.Unlock()
   354  		if (prewriteCount+dbsCount)*2 == length {
   355  			match = true
   356  			break
   357  		}
   358  		time.Sleep(time.Millisecond * 10)
   359  	}
   360  	c.Assert(match, IsTrue)
   361  }
   362  
   363  func mutationRowsToRows(c *C, mutationRows [][]byte, defCausumnValueOffsets ...int) [][]types.Causet {
   364  	var rows = make([][]types.Causet, 0)
   365  	for _, mutationRow := range mutationRows {
   366  		datums, err := codec.Decode(mutationRow, 5)
   367  		c.Assert(err, IsNil)
   368  		for i := range datums {
   369  			if datums[i].HoTT() == types.HoTTBytes {
   370  				datums[i].SetBytesAsString(datums[i].GetBytes(), allegrosql.DefaultDefCauslationName, defCauslate.DefaultLen)
   371  			}
   372  		}
   373  		event := make([]types.Causet, 0, len(defCausumnValueOffsets))
   374  		for _, defCausOff := range defCausumnValueOffsets {
   375  			event = append(event, datums[defCausOff])
   376  		}
   377  		rows = append(rows, event)
   378  	}
   379  	return rows
   380  }
   381  
   382  func (s *testBinlogSuite) TestBinlogForSequence(c *C) {
   383  	c.Assert(failpoint.Enable("github.com/whtcorpsinc/milevadb/causetstore/einsteindb/mockSyncBinlogCommit", `return(true)`), IsNil)
   384  	defer func() {
   385  		c.Assert(failpoint.Disable("github.com/whtcorpsinc/milevadb/causetstore/einsteindb/mockSyncBinlogCommit"), IsNil)
   386  	}()
   387  	tk := testkit.NewTestKit(c, s.causetstore)
   388  	tk.MustInterDirc("use test")
   389  	s.pump.mu.Lock()
   390  	s.pump.mu.payloads = s.pump.mu.payloads[:0]
   391  	s.pump.mu.Unlock()
   392  	tk.Se.GetStochastikVars().BinlogClient = s.client
   393  
   394  	tk.MustInterDirc("drop sequence if exists seq")
   395  	// the default start = 1, increment = 1.
   396  	tk.MustInterDirc("create sequence seq cache 3")
   397  	// trigger the sequence cache allocation.
   398  	tk.MustQuery("select nextval(seq)").Check(testkit.Rows("1"))
   399  	sequenceBlock := testGetBlockByName(c, tk.Se, "test", "seq")
   400  	tc, ok := sequenceBlock.(*blocks.BlockCommon)
   401  	c.Assert(ok, Equals, true)
   402  	_, end, round := tc.GetSequenceCommon().GetSequenceBaseEndRound()
   403  	c.Assert(end, Equals, int64(3))
   404  	c.Assert(round, Equals, int64(0))
   405  
   406  	// Check the sequence binlog.
   407  	// Got matched pre DBS and commit DBS.
   408  	ok = mustGetDBSBinlog(s, "select setval(`test`.`seq`, 3)", c)
   409  	c.Assert(ok, IsTrue)
   410  
   411  	// Invalidate the current sequence cache.
   412  	tk.MustQuery("select setval(seq, 5)").Check(testkit.Rows("5"))
   413  	// trigger the next sequence cache allocation.
   414  	tk.MustQuery("select nextval(seq)").Check(testkit.Rows("6"))
   415  	_, end, round = tc.GetSequenceCommon().GetSequenceBaseEndRound()
   416  	c.Assert(end, Equals, int64(8))
   417  	c.Assert(round, Equals, int64(0))
   418  	ok = mustGetDBSBinlog(s, "select setval(`test`.`seq`, 8)", c)
   419  	c.Assert(ok, IsTrue)
   420  
   421  	tk.MustInterDirc("create database test2")
   422  	tk.MustInterDirc("use test2")
   423  	tk.MustInterDirc("drop sequence if exists seq2")
   424  	tk.MustInterDirc("create sequence seq2 start 1 increment -2 cache 3 minvalue -10 maxvalue 10 cycle")
   425  	// trigger the sequence cache allocation.
   426  	tk.MustQuery("select nextval(seq2)").Check(testkit.Rows("1"))
   427  	sequenceBlock = testGetBlockByName(c, tk.Se, "test2", "seq2")
   428  	tc, ok = sequenceBlock.(*blocks.BlockCommon)
   429  	c.Assert(ok, Equals, true)
   430  	_, end, round = tc.GetSequenceCommon().GetSequenceBaseEndRound()
   431  	c.Assert(end, Equals, int64(-3))
   432  	c.Assert(round, Equals, int64(0))
   433  	ok = mustGetDBSBinlog(s, "select setval(`test2`.`seq2`, -3)", c)
   434  	c.Assert(ok, IsTrue)
   435  
   436  	tk.MustQuery("select setval(seq2, -100)").Check(testkit.Rows("-100"))
   437  	// trigger the sequence cache allocation.
   438  	tk.MustQuery("select nextval(seq2)").Check(testkit.Rows("10"))
   439  	_, end, round = tc.GetSequenceCommon().GetSequenceBaseEndRound()
   440  	c.Assert(end, Equals, int64(6))
   441  	c.Assert(round, Equals, int64(1))
   442  	ok = mustGetDBSBinlog(s, "select setval(`test2`.`seq2`, 6)", c)
   443  	c.Assert(ok, IsTrue)
   444  
   445  	// Test dml txn is independent from sequence txn.
   446  	tk.MustInterDirc("drop sequence if exists seq")
   447  	tk.MustInterDirc("create sequence seq cache 3")
   448  	tk.MustInterDirc("drop causet if exists t")
   449  	tk.MustInterDirc("create causet t (a int default next value for seq)")
   450  	// sequence txn commit first then the dml txn.
   451  	tk.MustInterDirc("insert into t values(-1),(default),(-1),(default)")
   452  	// binlog list like [... dbs prewrite(offset), dbs commit, dml prewrite, dml commit]
   453  	_, _, offset := getLatestDBSBinlog(c, s.pump, "select setval(`test2`.`seq`, 3)")
   454  	s.pump.mu.Lock()
   455  	c.Assert(offset+3, Equals, len(s.pump.mu.payloads)-1)
   456  	s.pump.mu.Unlock()
   457  }
   458  
   459  // Sometimes this test doesn't clean up fail, let the function name begin with 'Z'
   460  // so it runs last and would not disrupt other tests.
   461  func (s *testBinlogSuite) TestZIgnoreError(c *C) {
   462  	tk := testkit.NewTestKit(c, s.causetstore)
   463  	tk.MustInterDirc("use test")
   464  	tk.Se.GetStochastikVars().BinlogClient = s.client
   465  	tk.MustInterDirc("drop causet if exists t")
   466  	tk.MustInterDirc("create causet t (id int)")
   467  
   468  	binloginfo.SetIgnoreError(true)
   469  	s.pump.mu.Lock()
   470  	s.pump.mu.mockFail = true
   471  	s.pump.mu.Unlock()
   472  
   473  	tk.MustInterDirc("insert into t values (1)")
   474  	tk.MustInterDirc("insert into t values (1)")
   475  
   476  	// Clean up.
   477  	s.pump.mu.Lock()
   478  	s.pump.mu.mockFail = false
   479  	s.pump.mu.Unlock()
   480  	binloginfo.DisableSkipBinlogFlag()
   481  	binloginfo.SetIgnoreError(false)
   482  }
   483  
   484  func (s *testBinlogSuite) TestPartitionedBlock(c *C) {
   485  	// This test checks partitioned causet write binlog with causet ID, rather than partition ID.
   486  	tk := testkit.NewTestKit(c, s.causetstore)
   487  	tk.MustInterDirc("use test")
   488  	tk.Se.GetStochastikVars().BinlogClient = s.client
   489  	tk.MustInterDirc("drop causet if exists t")
   490  	tk.MustInterDirc(`create causet t (id int) partition by range (id) (
   491  			partition p0 values less than (1),
   492  			partition p1 values less than (4),
   493  			partition p2 values less than (7),
   494  			partition p3 values less than (10))`)
   495  	tids := make([]int64, 0, 10)
   496  	for i := 0; i < 10; i++ {
   497  		tk.MustInterDirc("insert into t values (?)", i)
   498  		prewriteVal := getLatestBinlogPrewriteValue(c, s.pump)
   499  		tids = append(tids, prewriteVal.Mutations[0].BlockId)
   500  	}
   501  	c.Assert(len(tids), Equals, 10)
   502  	for i := 1; i < 10; i++ {
   503  		c.Assert(tids[i], Equals, tids[0])
   504  	}
   505  }
   506  
   507  func (s *testBinlogSuite) TestDeleteSchema(c *C) {
   508  	tk := testkit.NewTestKit(c, s.causetstore)
   509  	tk.MustInterDirc("use test")
   510  	tk.MustInterDirc("CREATE TABLE `b1` (`id` int(11) NOT NULL AUTO_INCREMENT, `job_id` varchar(50) NOT NULL, `split_job_id` varchar(30) DEFAULT NULL, PRIMARY KEY (`id`), KEY `b1` (`job_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;")
   511  	tk.MustInterDirc("CREATE TABLE `b2` (`id` int(11) NOT NULL AUTO_INCREMENT, `job_id` varchar(50) NOT NULL, `batch_class` varchar(20) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `bu` (`job_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4")
   512  	tk.MustInterDirc("insert into b2 (job_id, batch_class) values (2, 'TEST');")
   513  	tk.MustInterDirc("insert into b1 (job_id) values (2);")
   514  
   515  	// This test cover a bug that the final schemaReplicant and the binlog event inconsistent.
   516  	// The final schemaReplicant of this ALLEGROALLEGROSQL should be the schemaReplicant of causet b1, rather than the schemaReplicant of join result.
   517  	tk.MustInterDirc("delete from b1 where job_id in (select job_id from b2 where batch_class = 'TEST') or split_job_id in (select job_id from b2 where batch_class = 'TEST');")
   518  	tk.MustInterDirc("delete b1 from b2 right join b1 on b1.job_id = b2.job_id and batch_class = 'TEST';")
   519  }
   520  
   521  func (s *testBinlogSuite) TestAddSpecialComment(c *C) {
   522  	testCase := []struct {
   523  		input  string
   524  		result string
   525  	}{
   526  		{
   527  			"create causet t1 (id int ) shard_row_id_bits=2;",
   528  			"create causet t1 (id int ) /*T! shard_row_id_bits=2 */ ;",
   529  		},
   530  		{
   531  			"create causet t1 (id int ) shard_row_id_bits=2 pre_split_regions=2;",
   532  			"create causet t1 (id int ) /*T! shard_row_id_bits=2 pre_split_regions=2 */ ;",
   533  		},
   534  		{
   535  			"create causet t1 (id int ) shard_row_id_bits=2     pre_split_regions=2;",
   536  			"create causet t1 (id int ) /*T! shard_row_id_bits=2     pre_split_regions=2 */ ;",
   537  		},
   538  
   539  		{
   540  			"create causet t1 (id int ) shard_row_id_bits=2 engine=innodb pre_split_regions=2;",
   541  			"create causet t1 (id int ) /*T! shard_row_id_bits=2 pre_split_regions=2 */ engine=innodb ;",
   542  		},
   543  		{
   544  			"create causet t1 (id int ) pre_split_regions=2 shard_row_id_bits=2;",
   545  			"create causet t1 (id int ) /*T! shard_row_id_bits=2 pre_split_regions=2 */ ;",
   546  		},
   547  		{
   548  			"create causet t6 (id int ) shard_row_id_bits=2 shard_row_id_bits=3 pre_split_regions=2;",
   549  			"create causet t6 (id int ) /*T! shard_row_id_bits=2 shard_row_id_bits=3 pre_split_regions=2 */ ;",
   550  		},
   551  		{
   552  			"create causet t1 (id int primary key auto_random(2));",
   553  			"create causet t1 (id int primary key /*T![auto_rand] auto_random(2) */ );",
   554  		},
   555  		{
   556  			"create causet t1 (id int primary key auto_random);",
   557  			"create causet t1 (id int primary key /*T![auto_rand] auto_random */ );",
   558  		},
   559  		{
   560  			"create causet t1 (id int auto_random ( 4 ) primary key);",
   561  			"create causet t1 (id int /*T![auto_rand] auto_random ( 4 ) */ primary key);",
   562  		},
   563  		{
   564  			"create causet t1 (id int  auto_random  (   4    ) primary key);",
   565  			"create causet t1 (id int  /*T![auto_rand] auto_random  (   4    ) */ primary key);",
   566  		},
   567  		{
   568  			"create causet t1 (id int auto_random ( 3 ) primary key) auto_random_base = 100;",
   569  			"create causet t1 (id int /*T![auto_rand] auto_random ( 3 ) */ primary key) /*T![auto_rand_base] auto_random_base = 100 */ ;",
   570  		},
   571  		{
   572  			"create causet t1 (id int auto_random primary key) auto_random_base = 50;",
   573  			"create causet t1 (id int /*T![auto_rand] auto_random */ primary key) /*T![auto_rand_base] auto_random_base = 50 */ ;",
   574  		},
   575  		{
   576  			"create causet t1 (id int auto_increment key) auto_id_cache 100;",
   577  			"create causet t1 (id int auto_increment key) /*T![auto_id_cache] auto_id_cache 100 */ ;",
   578  		},
   579  		{
   580  			"create causet t1 (id int auto_increment unique) auto_id_cache 10;",
   581  			"create causet t1 (id int auto_increment unique) /*T![auto_id_cache] auto_id_cache 10 */ ;",
   582  		},
   583  		{
   584  			"create causet t1 (id int) auto_id_cache = 5;",
   585  			"create causet t1 (id int) /*T![auto_id_cache] auto_id_cache = 5 */ ;",
   586  		},
   587  		{
   588  			"create causet t1 (id int) auto_id_cache=5;",
   589  			"create causet t1 (id int) /*T![auto_id_cache] auto_id_cache=5 */ ;",
   590  		},
   591  		{
   592  			"create causet t1 (id int) /*T![auto_id_cache] auto_id_cache=5 */ ;",
   593  			"create causet t1 (id int) /*T![auto_id_cache] auto_id_cache=5 */ ;",
   594  		},
   595  	}
   596  	for _, ca := range testCase {
   597  		re := binloginfo.AddSpecialComment(ca.input)
   598  		c.Assert(re, Equals, ca.result)
   599  	}
   600  }
   601  
   602  func mustGetDBSBinlog(s *testBinlogSuite, dbsQuery string, c *C) (matched bool) {
   603  	for i := 0; i < 10; i++ {
   604  		preDBS, commitDBS, _ := getLatestDBSBinlog(c, s.pump, dbsQuery)
   605  		if preDBS != nil && commitDBS != nil {
   606  			if preDBS.DdlJobId == commitDBS.DdlJobId {
   607  				c.Assert(commitDBS.StartTs, Equals, preDBS.StartTs)
   608  				c.Assert(commitDBS.CommitTs, Greater, commitDBS.StartTs)
   609  				matched = true
   610  				break
   611  			}
   612  		}
   613  		time.Sleep(time.Millisecond * 30)
   614  	}
   615  	return
   616  }
   617  
   618  func testGetBlockByName(c *C, ctx stochastikctx.Context, EDB, causet string) causet.Block {
   619  	dom := petri.GetPetri(ctx)
   620  	// Make sure the causet schemaReplicant is the new schemaReplicant.
   621  	err := dom.Reload()
   622  	c.Assert(err, IsNil)
   623  	tbl, err := dom.SchemaReplicant().BlockByName(perceptron.NewCIStr(EDB), perceptron.NewCIStr(causet))
   624  	c.Assert(err, IsNil)
   625  	return tbl
   626  }