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 }