github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/db/testutil/funcs.go (about) 1 // Copyright 2021 Matrix Origin 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package testutil 16 17 import ( 18 "context" 19 "errors" 20 "sync" 21 "testing" 22 23 "github.com/matrixorigin/matrixone/pkg/container/types" 24 "github.com/matrixorigin/matrixone/pkg/logutil" 25 "github.com/matrixorigin/matrixone/pkg/objectio" 26 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/blockio" 27 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog" 28 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 29 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers" 30 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/db" 31 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/data" 32 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/handle" 33 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 34 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables/jobs" 35 "github.com/panjf2000/ants/v2" 36 "github.com/stretchr/testify/assert" 37 ) 38 39 func WithTestAllPKType(t *testing.T, tae *db.DB, test func(*testing.T, *db.DB, *catalog.Schema)) { 40 var wg sync.WaitGroup 41 pool, _ := ants.NewPool(100) 42 defer pool.Release() 43 for i := 0; i < 17; i++ { 44 schema := catalog.MockSchemaAll(18, i) 45 schema.BlockMaxRows = 10 46 schema.ObjectMaxBlocks = 2 47 wg.Add(1) 48 _ = pool.Submit(func() { 49 defer wg.Done() 50 test(t, tae, schema) 51 }) 52 } 53 wg.Wait() 54 } 55 56 func LenOfBats(bats []*containers.Batch) int { 57 rows := 0 58 for _, bat := range bats { 59 rows += bat.Length() 60 } 61 return rows 62 } 63 64 func PrintCheckpointStats(t *testing.T, tae *db.DB) { 65 t.Logf("GetCheckpointedLSN: %d", tae.Wal.GetCheckpointed()) 66 t.Logf("GetPenddingLSNCnt: %d", tae.Wal.GetPenddingCnt()) 67 t.Logf("GetCurrSeqNum: %d", tae.Wal.GetCurrSeqNum()) 68 } 69 70 func CreateDB(t *testing.T, e *db.DB, dbName string) { 71 txn, err := e.StartTxn(nil) 72 assert.NoError(t, err) 73 _, err = txn.CreateDatabase(dbName, "", "") 74 assert.NoError(t, err) 75 assert.NoError(t, txn.Commit(context.Background())) 76 } 77 78 func DropDB(t *testing.T, e *db.DB, dbName string) { 79 txn, err := e.StartTxn(nil) 80 assert.NoError(t, err) 81 _, err = txn.DropDatabase(dbName) 82 assert.NoError(t, err) 83 assert.NoError(t, txn.Commit(context.Background())) 84 } 85 86 func CreateRelation(t *testing.T, e *db.DB, dbName string, schema *catalog.Schema, createDB bool) (db handle.Database, rel handle.Relation) { 87 txn, db, rel := CreateRelationNoCommit(t, e, dbName, schema, createDB) 88 assert.NoError(t, txn.Commit(context.Background())) 89 return 90 } 91 92 func CreateRelationNoCommit(t *testing.T, e *db.DB, dbName string, schema *catalog.Schema, createDB bool) (txn txnif.AsyncTxn, db handle.Database, rel handle.Relation) { 93 txn, err := e.StartTxn(nil) 94 assert.NoError(t, err) 95 if createDB { 96 db, err = txn.CreateDatabase(dbName, "", "") 97 assert.NoError(t, err) 98 } else { 99 db, err = txn.GetDatabase(dbName) 100 assert.NoError(t, err) 101 } 102 rel, err = db.CreateRelation(schema) 103 assert.NoError(t, err) 104 return 105 } 106 107 func CreateRelationAndAppend( 108 t *testing.T, 109 tenantID uint32, 110 e *db.DB, 111 dbName string, 112 schema *catalog.Schema, 113 bat *containers.Batch, 114 createDB bool) (db handle.Database, rel handle.Relation) { 115 txn, err := e.StartTxn(nil) 116 txn.BindAccessInfo(tenantID, 0, 0) 117 assert.NoError(t, err) 118 if createDB { 119 db, err = txn.CreateDatabase(dbName, "", "") 120 assert.NoError(t, err) 121 } else { 122 db, err = txn.GetDatabase(dbName) 123 assert.NoError(t, err) 124 } 125 rel, err = db.CreateRelation(schema) 126 assert.NoError(t, err) 127 err = rel.Append(context.Background(), bat) 128 assert.NoError(t, err) 129 assert.Nil(t, txn.Commit(context.Background())) 130 return 131 } 132 133 func GetRelation(t *testing.T, tenantID uint32, e *db.DB, dbName, tblName string) (txn txnif.AsyncTxn, rel handle.Relation) { 134 txn, err := e.StartTxn(nil) 135 txn.BindAccessInfo(tenantID, 0, 0) 136 assert.NoError(t, err) 137 db, err := txn.GetDatabase(dbName) 138 assert.NoError(t, err) 139 rel, err = db.GetRelationByName(tblName) 140 assert.NoError(t, err) 141 return 142 } 143 144 func GetRelationWithTxn(t *testing.T, txn txnif.AsyncTxn, dbName, tblName string) (rel handle.Relation) { 145 db, err := txn.GetDatabase(dbName) 146 assert.NoError(t, err) 147 rel, err = db.GetRelationByName(tblName) 148 assert.NoError(t, err) 149 return 150 } 151 152 func GetDefaultRelation(t *testing.T, e *db.DB, name string) (txn txnif.AsyncTxn, rel handle.Relation) { 153 return GetRelation(t, 0, e, DefaultTestDB, name) 154 } 155 156 func GetOneObject(rel handle.Relation) handle.Object { 157 it := rel.MakeObjectIt() 158 return it.GetObject() 159 } 160 161 func GetOneBlockMeta(rel handle.Relation) *catalog.ObjectEntry { 162 it := rel.MakeObjectIt() 163 return it.GetObject().GetMeta().(*catalog.ObjectEntry) 164 } 165 166 func GetAllBlockMetas(rel handle.Relation) (metas []*catalog.ObjectEntry) { 167 it := rel.MakeObjectIt() 168 for ; it.Valid(); it.Next() { 169 blk := it.GetObject() 170 metas = append(metas, blk.GetMeta().(*catalog.ObjectEntry)) 171 } 172 return 173 } 174 175 func CheckAllColRowsByScan(t *testing.T, rel handle.Relation, expectRows int, applyDelete bool) { 176 schema := rel.Schema().(*catalog.Schema) 177 for _, def := range schema.ColDefs { 178 rows := GetColumnRowsByScan(t, rel, def.Idx, applyDelete) 179 assert.Equal(t, expectRows, rows) 180 } 181 } 182 183 func GetColumnRowsByScan(t *testing.T, rel handle.Relation, colIdx int, applyDelete bool) int { 184 rows := 0 185 ForEachColumnView(rel, colIdx, func(view *containers.ColumnView) (err error) { 186 if applyDelete { 187 view.ApplyDeletes() 188 } 189 rows += view.Length() 190 // t.Log(view.String()) 191 return 192 }) 193 return rows 194 } 195 196 func ForEachColumnView(rel handle.Relation, colIdx int, fn func(view *containers.ColumnView) error) { 197 ForEachObject(rel, func(blk handle.Object) (err error) { 198 blkCnt := blk.GetMeta().(*catalog.ObjectEntry).BlockCnt() 199 for i := 0; i < blkCnt; i++ { 200 view, err := blk.GetColumnDataById(context.Background(), uint16(i), colIdx, common.DefaultAllocator) 201 if view == nil { 202 logutil.Warnf("blk %v", blk.String()) 203 continue 204 } 205 if err != nil { 206 return err 207 } 208 defer view.Close() 209 err = fn(view) 210 if err != nil { 211 return err 212 } 213 } 214 return 215 }) 216 } 217 218 func ForEachObject(rel handle.Relation, fn func(obj handle.Object) error) { 219 it := rel.MakeObjectIt() 220 var err error 221 for it.Valid() { 222 obj := it.GetObject() 223 defer obj.Close() 224 if err = fn(obj); err != nil { 225 if errors.Is(err, handle.ErrIteratorEnd) { 226 return 227 } else { 228 panic(err) 229 } 230 } 231 it.Next() 232 } 233 } 234 235 func AppendFailClosure(t *testing.T, data *containers.Batch, name string, e *db.DB, wg *sync.WaitGroup) func() { 236 return func() { 237 if wg != nil { 238 defer wg.Done() 239 } 240 txn, _ := e.StartTxn(nil) 241 database, _ := txn.GetDatabase("db") 242 rel, _ := database.GetRelationByName(name) 243 err := rel.Append(context.Background(), data) 244 assert.NotNil(t, err) 245 assert.Nil(t, txn.Rollback(context.Background())) 246 } 247 } 248 249 func AppendClosure(t *testing.T, data *containers.Batch, name string, e *db.DB, wg *sync.WaitGroup) func() { 250 return func() { 251 if wg != nil { 252 defer wg.Done() 253 } 254 txn, _ := e.StartTxn(nil) 255 database, _ := txn.GetDatabase("db") 256 rel, _ := database.GetRelationByName(name) 257 err := rel.Append(context.Background(), data) 258 assert.Nil(t, err) 259 assert.Nil(t, txn.Commit(context.Background())) 260 } 261 } 262 263 func CompactBlocks(t *testing.T, tenantID uint32, e *db.DB, dbName string, schema *catalog.Schema, skipConflict bool) { 264 txn, rel := GetRelation(t, tenantID, e, dbName, schema.Name) 265 266 var metas []*catalog.ObjectEntry 267 it := rel.MakeObjectIt() 268 for it.Valid() { 269 blk := it.GetObject() 270 meta := blk.GetMeta().(*catalog.ObjectEntry) 271 metas = append(metas, meta) 272 it.Next() 273 } 274 _ = txn.Commit(context.Background()) 275 if len(metas) == 0 { 276 return 277 } 278 txn, _ = GetRelation(t, tenantID, e, dbName, schema.Name) 279 task, err := jobs.NewFlushTableTailTask(nil, txn, metas, e.Runtime, txn.GetStartTS()) 280 if skipConflict && err != nil { 281 _ = txn.Rollback(context.Background()) 282 return 283 } 284 assert.NoError(t, err) 285 err = task.OnExec(context.Background()) 286 if skipConflict { 287 if err != nil { 288 _ = txn.Rollback(context.Background()) 289 } else { 290 _ = txn.Commit(context.Background()) 291 } 292 } else { 293 assert.NoError(t, err) 294 assert.NoError(t, txn.Commit(context.Background())) 295 } 296 } 297 298 func MergeBlocks(t *testing.T, tenantID uint32, e *db.DB, dbName string, schema *catalog.Schema, skipConflict bool) { 299 txn, _ := e.StartTxn(nil) 300 txn.BindAccessInfo(tenantID, 0, 0) 301 db, _ := txn.GetDatabase(dbName) 302 rel, _ := db.GetRelationByName(schema.Name) 303 304 var objs []*catalog.ObjectEntry 305 objIt := rel.MakeObjectIt() 306 for objIt.Valid() { 307 obj := objIt.GetObject().GetMeta().(*catalog.ObjectEntry) 308 if !obj.IsAppendable() { 309 objs = append(objs, obj) 310 } 311 objIt.Next() 312 } 313 _ = txn.Commit(context.Background()) 314 metas := make([]*catalog.ObjectEntry, 0) 315 for _, obj := range objs { 316 txn, _ = e.StartTxn(nil) 317 txn.BindAccessInfo(tenantID, 0, 0) 318 db, _ = txn.GetDatabase(dbName) 319 rel, _ = db.GetRelationByName(schema.Name) 320 objHandle, err := rel.GetObject(&obj.ID) 321 if err != nil { 322 if skipConflict { 323 continue 324 } else { 325 assert.NoErrorf(t, err, "Txn Ts=%d", txn.GetStartTS()) 326 } 327 } 328 metas = append(metas, objHandle.GetMeta().(*catalog.ObjectEntry)) 329 } 330 task, err := jobs.NewMergeObjectsTask(nil, txn, metas, e.Runtime, 0) 331 if skipConflict && err != nil { 332 _ = txn.Rollback(context.Background()) 333 return 334 } 335 assert.NoError(t, err) 336 err = task.OnExec(context.Background()) 337 if skipConflict { 338 if err != nil { 339 _ = txn.Rollback(context.Background()) 340 } else { 341 _ = txn.Commit(context.Background()) 342 } 343 } else { 344 assert.NoError(t, err) 345 assert.NoError(t, txn.Commit(context.Background())) 346 } 347 } 348 349 func GetSingleSortKeyValue(bat *containers.Batch, schema *catalog.Schema, row int) (v any) { 350 v = bat.Vecs[schema.GetSingleSortKeyIdx()].Get(row) 351 return 352 } 353 354 func MockCNDeleteInS3( 355 fs *objectio.ObjectFS, 356 obj data.Object, 357 blkOffset uint16, 358 schema *catalog.Schema, 359 txn txnif.AsyncTxn, 360 deleteRows []uint32, 361 ) (location objectio.Location, err error) { 362 pkDef := schema.GetPrimaryKey() 363 view, err := obj.GetColumnDataById(context.Background(), txn, schema, blkOffset, pkDef.Idx, common.DefaultAllocator) 364 pkVec := containers.MakeVector(pkDef.Type, common.DefaultAllocator) 365 rowIDVec := containers.MakeVector(types.T_Rowid.ToType(), common.DefaultAllocator) 366 objID := &obj.GetMeta().(*catalog.ObjectEntry).ID 367 blkID := objectio.NewBlockidWithObjectID(objID, blkOffset) 368 if err != nil { 369 return 370 } 371 for _, row := range deleteRows { 372 pkVal := view.GetData().Get(int(row)) 373 pkVec.Append(pkVal, false) 374 rowID := objectio.NewRowid(blkID, row) 375 rowIDVec.Append(*rowID, false) 376 } 377 bat := containers.NewBatch() 378 bat.AddVector(catalog.AttrRowID, rowIDVec) 379 bat.AddVector("pk", pkVec) 380 name := objectio.MockObjectName() 381 writer, err := blockio.NewBlockWriterNew(fs.Service, name, 0, nil) 382 if err != nil { 383 return 384 } 385 _, err = writer.WriteTombstoneBatch(containers.ToCNBatch(bat)) 386 if err != nil { 387 return 388 } 389 blks, _, err := writer.Sync(context.Background()) 390 location = blockio.EncodeLocation(name, blks[0].GetExtent(), uint32(bat.Length()), blks[0].GetID()) 391 return 392 }