github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/table_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 dbs
    15  
    16  import (
    17  	"bytes"
    18  	"context"
    19  	"fmt"
    20  
    21  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    22  	"github.com/whtcorpsinc/BerolinaSQL/auth"
    23  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    24  	. "github.com/whtcorpsinc/check"
    25  	"github.com/whtcorpsinc/errors"
    26  	"github.com/whtcorpsinc/milevadb/causet"
    27  	"github.com/whtcorpsinc/milevadb/ekv"
    28  	"github.com/whtcorpsinc/milevadb/spacetime"
    29  	"github.com/whtcorpsinc/milevadb/spacetime/autoid"
    30  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    31  	"github.com/whtcorpsinc/milevadb/types"
    32  )
    33  
    34  var _ = Suite(&testTableSuite{})
    35  
    36  type testTableSuite struct {
    37  	causetstore ekv.CausetStorage
    38  	dbInfo      *perceptron.DBInfo
    39  
    40  	d *dbs
    41  }
    42  
    43  func testTableInfoWith2IndexOnFirstDeferredCauset(c *C, d *dbs, name string, num int) *perceptron.TableInfo {
    44  	normalInfo := testTableInfo(c, d, name, num)
    45  	idxs := make([]*perceptron.IndexInfo, 0, 2)
    46  	for i := range idxs {
    47  		idx := &perceptron.IndexInfo{
    48  			Name:            perceptron.NewCIStr(fmt.Sprintf("i%d", i+1)),
    49  			State:           perceptron.StatePublic,
    50  			DeferredCausets: []*perceptron.IndexDeferredCauset{{Name: perceptron.NewCIStr("c1")}},
    51  		}
    52  		idxs = append(idxs, idx)
    53  	}
    54  	normalInfo.Indices = idxs
    55  	normalInfo.DeferredCausets[0].FieldType.Flen = 11
    56  	return normalInfo
    57  }
    58  
    59  // testTableInfo creates a test causet with num int columns and with no index.
    60  func testTableInfo(c *C, d *dbs, name string, num int) *perceptron.TableInfo {
    61  	tblInfo := &perceptron.TableInfo{
    62  		Name: perceptron.NewCIStr(name),
    63  	}
    64  	genIDs, err := d.genGlobalIDs(1)
    65  	c.Assert(err, IsNil)
    66  	tblInfo.ID = genIDs[0]
    67  
    68  	defcaus := make([]*perceptron.DeferredCausetInfo, num)
    69  	for i := range defcaus {
    70  		col := &perceptron.DeferredCausetInfo{
    71  			Name:         perceptron.NewCIStr(fmt.Sprintf("c%d", i+1)),
    72  			Offset:       i,
    73  			DefaultValue: i + 1,
    74  			State:        perceptron.StatePublic,
    75  		}
    76  
    77  		col.FieldType = *types.NewFieldType(allegrosql.TypeLong)
    78  		col.ID = allocateDeferredCausetID(tblInfo)
    79  		defcaus[i] = col
    80  	}
    81  	tblInfo.DeferredCausets = defcaus
    82  	tblInfo.Charset = "utf8"
    83  	tblInfo.DefCauslate = "utf8_bin"
    84  	return tblInfo
    85  }
    86  
    87  // testTableInfoWithPartition creates a test causet with num int columns and with no index.
    88  func testTableInfoWithPartition(c *C, d *dbs, name string, num int) *perceptron.TableInfo {
    89  	tblInfo := testTableInfo(c, d, name, num)
    90  	genIDs, err := d.genGlobalIDs(1)
    91  	c.Assert(err, IsNil)
    92  	pid := genIDs[0]
    93  	tblInfo.Partition = &perceptron.PartitionInfo{
    94  		Type:   perceptron.PartitionTypeRange,
    95  		Expr:   tblInfo.DeferredCausets[0].Name.L,
    96  		Enable: true,
    97  		Definitions: []perceptron.PartitionDefinition{{
    98  			ID:       pid,
    99  			Name:     perceptron.NewCIStr("p0"),
   100  			LessThan: []string{"maxvalue"},
   101  		}},
   102  	}
   103  
   104  	return tblInfo
   105  }
   106  
   107  // testTableInfoWithPartitionLessThan creates a test causet with num int columns and one partition specified with lessthan.
   108  func testTableInfoWithPartitionLessThan(c *C, d *dbs, name string, num int, lessthan string) *perceptron.TableInfo {
   109  	tblInfo := testTableInfoWithPartition(c, d, name, num)
   110  	tblInfo.Partition.Definitions[0].LessThan = []string{lessthan}
   111  	return tblInfo
   112  }
   113  
   114  func testAddedNewTablePartitionInfo(c *C, d *dbs, tblInfo *perceptron.TableInfo, partName, lessthan string) *perceptron.PartitionInfo {
   115  	genIDs, err := d.genGlobalIDs(1)
   116  	c.Assert(err, IsNil)
   117  	pid := genIDs[0]
   118  	// the new added partition should change the partition state to state none at the beginning.
   119  	return &perceptron.PartitionInfo{
   120  		Type:   perceptron.PartitionTypeRange,
   121  		Expr:   tblInfo.DeferredCausets[0].Name.L,
   122  		Enable: true,
   123  		Definitions: []perceptron.PartitionDefinition{{
   124  			ID:       pid,
   125  			Name:     perceptron.NewCIStr(partName),
   126  			LessThan: []string{lessthan},
   127  		}},
   128  	}
   129  }
   130  
   131  // testViewInfo creates a test view with num int columns.
   132  func testViewInfo(c *C, d *dbs, name string, num int) *perceptron.TableInfo {
   133  	tblInfo := &perceptron.TableInfo{
   134  		Name: perceptron.NewCIStr(name),
   135  	}
   136  	genIDs, err := d.genGlobalIDs(1)
   137  	c.Assert(err, IsNil)
   138  	tblInfo.ID = genIDs[0]
   139  
   140  	defcaus := make([]*perceptron.DeferredCausetInfo, num)
   141  	viewDefCauss := make([]perceptron.CIStr, num)
   142  
   143  	var stmtBuffer bytes.Buffer
   144  	stmtBuffer.WriteString("SELECT ")
   145  	for i := range defcaus {
   146  		col := &perceptron.DeferredCausetInfo{
   147  			Name:   perceptron.NewCIStr(fmt.Sprintf("c%d", i+1)),
   148  			Offset: i,
   149  			State:  perceptron.StatePublic,
   150  		}
   151  
   152  		col.ID = allocateDeferredCausetID(tblInfo)
   153  		defcaus[i] = col
   154  		viewDefCauss[i] = col.Name
   155  		stmtBuffer.WriteString(defcaus[i].Name.L + ",")
   156  	}
   157  	stmtBuffer.WriteString("1 FROM t")
   158  
   159  	view := perceptron.ViewInfo{DefCauss: viewDefCauss, Security: perceptron.SecurityDefiner, Algorithm: perceptron.AlgorithmMerge,
   160  		SelectStmt: stmtBuffer.String(), CheckOption: perceptron.CheckOptionCascaded, Definer: &auth.UserIdentity{CurrentUser: true}}
   161  
   162  	tblInfo.View = &view
   163  	tblInfo.DeferredCausets = defcaus
   164  
   165  	return tblInfo
   166  }
   167  
   168  func testCreateTable(c *C, ctx stochastikctx.Context, d *dbs, dbInfo *perceptron.DBInfo, tblInfo *perceptron.TableInfo) *perceptron.Job {
   169  	job := &perceptron.Job{
   170  		SchemaID:   dbInfo.ID,
   171  		TableID:    tblInfo.ID,
   172  		Type:       perceptron.CausetActionCreateTable,
   173  		BinlogInfo: &perceptron.HistoryInfo{},
   174  		Args:       []interface{}{tblInfo},
   175  	}
   176  	err := d.doDBSJob(ctx, job)
   177  	c.Assert(err, IsNil)
   178  
   179  	v := getSchemaVer(c, ctx)
   180  	tblInfo.State = perceptron.StatePublic
   181  	checkHistoryJobArgs(c, ctx, job.ID, &historyJobArgs{ver: v, tbl: tblInfo})
   182  	tblInfo.State = perceptron.StateNone
   183  	return job
   184  }
   185  
   186  func testCreateView(c *C, ctx stochastikctx.Context, d *dbs, dbInfo *perceptron.DBInfo, tblInfo *perceptron.TableInfo) *perceptron.Job {
   187  	job := &perceptron.Job{
   188  		SchemaID:   dbInfo.ID,
   189  		TableID:    tblInfo.ID,
   190  		Type:       perceptron.CausetActionCreateView,
   191  		BinlogInfo: &perceptron.HistoryInfo{},
   192  		Args:       []interface{}{tblInfo, false, 0},
   193  	}
   194  
   195  	c.Assert(tblInfo.IsView(), IsTrue)
   196  	err := d.doDBSJob(ctx, job)
   197  	c.Assert(err, IsNil)
   198  
   199  	v := getSchemaVer(c, ctx)
   200  	tblInfo.State = perceptron.StatePublic
   201  	checkHistoryJobArgs(c, ctx, job.ID, &historyJobArgs{ver: v, tbl: tblInfo})
   202  	tblInfo.State = perceptron.StateNone
   203  	return job
   204  }
   205  
   206  func testRenameTable(c *C, ctx stochastikctx.Context, d *dbs, newSchemaID, oldSchemaID int64, tblInfo *perceptron.TableInfo) *perceptron.Job {
   207  	job := &perceptron.Job{
   208  		SchemaID:   newSchemaID,
   209  		TableID:    tblInfo.ID,
   210  		Type:       perceptron.CausetActionRenameTable,
   211  		BinlogInfo: &perceptron.HistoryInfo{},
   212  		Args:       []interface{}{oldSchemaID, tblInfo.Name},
   213  	}
   214  	err := d.doDBSJob(ctx, job)
   215  	c.Assert(err, IsNil)
   216  
   217  	v := getSchemaVer(c, ctx)
   218  	tblInfo.State = perceptron.StatePublic
   219  	checkHistoryJobArgs(c, ctx, job.ID, &historyJobArgs{ver: v, tbl: tblInfo})
   220  	tblInfo.State = perceptron.StateNone
   221  	return job
   222  }
   223  
   224  func testLockTable(c *C, ctx stochastikctx.Context, d *dbs, newSchemaID int64, tblInfo *perceptron.TableInfo, lockTp perceptron.TableLockType) *perceptron.Job {
   225  	arg := &lockTablesArg{
   226  		LockTables: []perceptron.TableLockTpInfo{{SchemaID: newSchemaID, TableID: tblInfo.ID, Tp: lockTp}},
   227  		StochastikInfo: perceptron.StochastikInfo{
   228  			ServerID:     d.GetID(),
   229  			StochastikID: ctx.GetStochastikVars().ConnectionID,
   230  		},
   231  	}
   232  	job := &perceptron.Job{
   233  		SchemaID:   newSchemaID,
   234  		TableID:    tblInfo.ID,
   235  		Type:       perceptron.CausetActionLockTable,
   236  		BinlogInfo: &perceptron.HistoryInfo{},
   237  		Args:       []interface{}{arg},
   238  	}
   239  	err := d.doDBSJob(ctx, job)
   240  	c.Assert(err, IsNil)
   241  
   242  	v := getSchemaVer(c, ctx)
   243  	checkHistoryJobArgs(c, ctx, job.ID, &historyJobArgs{ver: v})
   244  	return job
   245  }
   246  
   247  func checkTableLockedTest(c *C, d *dbs, dbInfo *perceptron.DBInfo, tblInfo *perceptron.TableInfo, serverID string, stochastikID uint64, lockTp perceptron.TableLockType) {
   248  	err := ekv.RunInNewTxn(d.causetstore, false, func(txn ekv.Transaction) error {
   249  		t := spacetime.NewMeta(txn)
   250  		info, err := t.GetTable(dbInfo.ID, tblInfo.ID)
   251  		c.Assert(err, IsNil)
   252  
   253  		c.Assert(info, NotNil)
   254  		c.Assert(info.Lock, NotNil)
   255  		c.Assert(len(info.Lock.Stochastiks) == 1, IsTrue)
   256  		c.Assert(info.Lock.Stochastiks[0].ServerID, Equals, serverID)
   257  		c.Assert(info.Lock.Stochastiks[0].StochastikID, Equals, stochastikID)
   258  		c.Assert(info.Lock.Tp, Equals, lockTp)
   259  		c.Assert(info.Lock.State, Equals, perceptron.TableLockStatePublic)
   260  		return nil
   261  	})
   262  	c.Assert(err, IsNil)
   263  }
   264  
   265  func testDropTable(c *C, ctx stochastikctx.Context, d *dbs, dbInfo *perceptron.DBInfo, tblInfo *perceptron.TableInfo) *perceptron.Job {
   266  	job := &perceptron.Job{
   267  		SchemaID:   dbInfo.ID,
   268  		TableID:    tblInfo.ID,
   269  		Type:       perceptron.CausetActionDropTable,
   270  		BinlogInfo: &perceptron.HistoryInfo{},
   271  	}
   272  	err := d.doDBSJob(ctx, job)
   273  	c.Assert(err, IsNil)
   274  
   275  	v := getSchemaVer(c, ctx)
   276  	checkHistoryJobArgs(c, ctx, job.ID, &historyJobArgs{ver: v, tbl: tblInfo})
   277  	return job
   278  }
   279  
   280  func testTruncateTable(c *C, ctx stochastikctx.Context, d *dbs, dbInfo *perceptron.DBInfo, tblInfo *perceptron.TableInfo) *perceptron.Job {
   281  	genIDs, err := d.genGlobalIDs(1)
   282  	c.Assert(err, IsNil)
   283  	newTableID := genIDs[0]
   284  	job := &perceptron.Job{
   285  		SchemaID:   dbInfo.ID,
   286  		TableID:    tblInfo.ID,
   287  		Type:       perceptron.CausetActionTruncateTable,
   288  		BinlogInfo: &perceptron.HistoryInfo{},
   289  		Args:       []interface{}{newTableID},
   290  	}
   291  	err = d.doDBSJob(ctx, job)
   292  	c.Assert(err, IsNil)
   293  
   294  	v := getSchemaVer(c, ctx)
   295  	tblInfo.ID = newTableID
   296  	checkHistoryJobArgs(c, ctx, job.ID, &historyJobArgs{ver: v, tbl: tblInfo})
   297  	return job
   298  }
   299  
   300  func testCheckTableState(c *C, d *dbs, dbInfo *perceptron.DBInfo, tblInfo *perceptron.TableInfo, state perceptron.SchemaState) {
   301  	err := ekv.RunInNewTxn(d.causetstore, false, func(txn ekv.Transaction) error {
   302  		t := spacetime.NewMeta(txn)
   303  		info, err := t.GetTable(dbInfo.ID, tblInfo.ID)
   304  		c.Assert(err, IsNil)
   305  
   306  		if state == perceptron.StateNone {
   307  			c.Assert(info, IsNil)
   308  			return nil
   309  		}
   310  
   311  		c.Assert(info.Name, DeepEquals, tblInfo.Name)
   312  		c.Assert(info.State, Equals, state)
   313  		return nil
   314  	})
   315  	c.Assert(err, IsNil)
   316  }
   317  
   318  func testGetTable(c *C, d *dbs, schemaID int64, blockID int64) causet.Block {
   319  	tbl, err := testGetTableWithError(d, schemaID, blockID)
   320  	c.Assert(err, IsNil)
   321  	return tbl
   322  }
   323  
   324  func testGetTableWithError(d *dbs, schemaID, blockID int64) (causet.Block, error) {
   325  	var tblInfo *perceptron.TableInfo
   326  	err := ekv.RunInNewTxn(d.causetstore, false, func(txn ekv.Transaction) error {
   327  		t := spacetime.NewMeta(txn)
   328  		var err1 error
   329  		tblInfo, err1 = t.GetTable(schemaID, blockID)
   330  		if err1 != nil {
   331  			return errors.Trace(err1)
   332  		}
   333  		return nil
   334  	})
   335  	if err != nil {
   336  		return nil, errors.Trace(err)
   337  	}
   338  	if tblInfo == nil {
   339  		return nil, errors.New("causet not found")
   340  	}
   341  	alloc := autoid.NewSlabPredictor(d.causetstore, schemaID, false, autoid.RowIDAllocType)
   342  	tbl, err := causet.TableFromMeta(autoid.NewSlabPredictors(alloc), tblInfo)
   343  	if err != nil {
   344  		return nil, errors.Trace(err)
   345  	}
   346  	return tbl, nil
   347  }
   348  
   349  func (s *testTableSuite) SetUpSuite(c *C) {
   350  	s.causetstore = testCreateStore(c, "test_block")
   351  	s.d = testNewDBSAndStart(
   352  		context.Background(),
   353  		c,
   354  		WithStore(s.causetstore),
   355  		WithLease(testLease),
   356  	)
   357  
   358  	s.dbInfo = testSchemaInfo(c, s.d, "test")
   359  	testCreateSchema(c, testNewContext(s.d), s.d, s.dbInfo)
   360  }
   361  
   362  func (s *testTableSuite) TearDownSuite(c *C) {
   363  	testDropSchema(c, testNewContext(s.d), s.d, s.dbInfo)
   364  	s.d.Stop()
   365  	s.causetstore.Close()
   366  }
   367  
   368  func (s *testTableSuite) TestTable(c *C) {
   369  	d := s.d
   370  
   371  	ctx := testNewContext(d)
   372  
   373  	tblInfo := testTableInfo(c, d, "t", 3)
   374  	job := testCreateTable(c, ctx, d, s.dbInfo, tblInfo)
   375  	testCheckTableState(c, d, s.dbInfo, tblInfo, perceptron.StatePublic)
   376  	testCheckJobDone(c, d, job, true)
   377  
   378  	// Create an existing causet.
   379  	newTblInfo := testTableInfo(c, d, "t", 3)
   380  	doDBSJobErr(c, s.dbInfo.ID, newTblInfo.ID, perceptron.CausetActionCreateTable, []interface{}{newTblInfo}, ctx, d)
   381  
   382  	count := 2000
   383  	tbl := testGetTable(c, d, s.dbInfo.ID, tblInfo.ID)
   384  	for i := 1; i <= count; i++ {
   385  		_, err := tbl.AddRecord(ctx, types.MakeCausets(i, i, i))
   386  		c.Assert(err, IsNil)
   387  	}
   388  
   389  	job = testDropTable(c, ctx, d, s.dbInfo, tblInfo)
   390  	testCheckJobDone(c, d, job, false)
   391  
   392  	// for truncate causet
   393  	tblInfo = testTableInfo(c, d, "tt", 3)
   394  	job = testCreateTable(c, ctx, d, s.dbInfo, tblInfo)
   395  	testCheckTableState(c, d, s.dbInfo, tblInfo, perceptron.StatePublic)
   396  	testCheckJobDone(c, d, job, true)
   397  	job = testTruncateTable(c, ctx, d, s.dbInfo, tblInfo)
   398  	testCheckTableState(c, d, s.dbInfo, tblInfo, perceptron.StatePublic)
   399  	testCheckJobDone(c, d, job, true)
   400  
   401  	// for rename causet
   402  	dbInfo1 := testSchemaInfo(c, s.d, "test_rename_block")
   403  	testCreateSchema(c, testNewContext(s.d), s.d, dbInfo1)
   404  	job = testRenameTable(c, ctx, d, dbInfo1.ID, s.dbInfo.ID, tblInfo)
   405  	testCheckTableState(c, d, dbInfo1, tblInfo, perceptron.StatePublic)
   406  	testCheckJobDone(c, d, job, true)
   407  
   408  	job = testLockTable(c, ctx, d, dbInfo1.ID, tblInfo, perceptron.TableLockWrite)
   409  	testCheckTableState(c, d, dbInfo1, tblInfo, perceptron.StatePublic)
   410  	testCheckJobDone(c, d, job, true)
   411  	checkTableLockedTest(c, d, dbInfo1, tblInfo, d.GetID(), ctx.GetStochastikVars().ConnectionID, perceptron.TableLockWrite)
   412  }