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  }