github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/db/base_test.go (about)

     1  // Copyright 2022 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 db
    16  
    17  import (
    18  	"errors"
    19  	"sync"
    20  	"testing"
    21  	"time"
    22  
    23  	checkpoint2 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/db/checkpoint"
    24  
    25  	"github.com/matrixorigin/matrixone/pkg/container/types"
    26  	"github.com/matrixorigin/matrixone/pkg/logutil"
    27  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog"
    28  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers"
    29  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/handle"
    30  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif"
    31  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/model"
    32  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/options"
    33  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables/jobs"
    34  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/testutils"
    35  	"github.com/panjf2000/ants/v2"
    36  	"github.com/stretchr/testify/assert"
    37  )
    38  
    39  const (
    40  	ModuleName    = "TAEDB"
    41  	defaultTestDB = "db"
    42  )
    43  
    44  func init() {
    45  	// workaround sca check
    46  	_ = tryAppendClosure
    47  	_ = dropDB
    48  }
    49  
    50  type testEngine struct {
    51  	*DB
    52  	t        *testing.T
    53  	schema   *catalog.Schema
    54  	tenantID uint32 // for almost tests, userID and roleID is not important
    55  }
    56  
    57  func newTestEngine(t *testing.T, opts *options.Options) *testEngine {
    58  	db := initDB(t, opts)
    59  	return &testEngine{
    60  		DB: db,
    61  		t:  t,
    62  	}
    63  }
    64  
    65  func (e *testEngine) bindSchema(schema *catalog.Schema) { e.schema = schema }
    66  
    67  func (e *testEngine) bindTenantID(tenantID uint32) { e.tenantID = tenantID }
    68  
    69  func (e *testEngine) restart() {
    70  	_ = e.DB.Close()
    71  	var err error
    72  	e.DB, err = Open(e.Dir, e.Opts)
    73  	// only ut executes this checker
    74  	e.DB.DiskCleaner.AddChecker(
    75  		func(item any) bool {
    76  			min := e.DB.TxnMgr.MinTSForTest()
    77  			checkpoint := item.(*checkpoint2.CheckpointEntry)
    78  			//logutil.Infof("min: %v, checkpoint: %v", min.ToString(), checkpoint.GetStart().ToString())
    79  			return !checkpoint.GetEnd().GreaterEq(min)
    80  		})
    81  	assert.NoError(e.t, err)
    82  }
    83  
    84  func (e *testEngine) Close() error {
    85  	return e.DB.Close()
    86  }
    87  
    88  func (e *testEngine) createRelAndAppend(bat *containers.Batch, createDB bool) (handle.Database, handle.Relation) {
    89  	return createRelationAndAppend(e.t, e.tenantID, e.DB, defaultTestDB, e.schema, bat, createDB)
    90  }
    91  
    92  // func (e *testEngine) getRows() int {
    93  // 	txn, rel := e.getRelation()
    94  // 	rows := rel.Rows()
    95  // 	assert.NoError(e.t, txn.Commit())
    96  // 	return int(rows)
    97  // }
    98  
    99  func (e *testEngine) checkRowsByScan(exp int, applyDelete bool) {
   100  	txn, rel := e.getRelation()
   101  	checkAllColRowsByScan(e.t, rel, exp, applyDelete)
   102  	assert.NoError(e.t, txn.Commit())
   103  }
   104  func (e *testEngine) dropRelation(t *testing.T) {
   105  	txn, err := e.StartTxn(nil)
   106  	assert.NoError(t, err)
   107  	db, err := txn.GetDatabase(defaultTestDB)
   108  	assert.NoError(t, err)
   109  	_, err = db.DropRelationByName(e.schema.Name)
   110  	assert.NoError(t, err)
   111  	assert.NoError(t, txn.Commit())
   112  }
   113  func (e *testEngine) getRelation() (txn txnif.AsyncTxn, rel handle.Relation) {
   114  	return getRelation(e.t, e.tenantID, e.DB, defaultTestDB, e.schema.Name)
   115  }
   116  func (e *testEngine) getRelationWithTxn(txn txnif.AsyncTxn) (rel handle.Relation) {
   117  	return getRelationWithTxn(e.t, txn, defaultTestDB, e.schema.Name)
   118  }
   119  
   120  func (e *testEngine) compactBlocks(skipConflict bool) {
   121  	compactBlocks(e.t, e.tenantID, e.DB, defaultTestDB, e.schema, skipConflict)
   122  }
   123  
   124  func (e *testEngine) mergeBlocks(skipConflict bool) {
   125  	mergeBlocks(e.t, e.tenantID, e.DB, defaultTestDB, e.schema, skipConflict)
   126  }
   127  
   128  func (e *testEngine) getDB(name string) (txn txnif.AsyncTxn, db handle.Database) {
   129  	txn, err := e.DB.StartTxn(nil)
   130  	txn.BindAccessInfo(e.tenantID, 0, 0)
   131  	assert.NoError(e.t, err)
   132  	db, err = txn.GetDatabase(name)
   133  	assert.NoError(e.t, err)
   134  	return
   135  }
   136  
   137  func (e *testEngine) getTestDB() (txn txnif.AsyncTxn, db handle.Database) {
   138  	return e.getDB(defaultTestDB)
   139  }
   140  
   141  func (e *testEngine) DoAppend(bat *containers.Batch) {
   142  	txn, rel := e.getRelation()
   143  	err := rel.Append(bat)
   144  	assert.NoError(e.t, err)
   145  	assert.NoError(e.t, txn.Commit())
   146  }
   147  
   148  func (e *testEngine) doAppendWithTxn(bat *containers.Batch, txn txnif.AsyncTxn, skipConflict bool) (err error) {
   149  	rel := e.getRelationWithTxn(txn)
   150  	err = rel.Append(bat)
   151  	if !skipConflict {
   152  		assert.NoError(e.t, err)
   153  	}
   154  	return
   155  }
   156  
   157  func (e *testEngine) tryAppend(bat *containers.Batch) {
   158  	txn, err := e.DB.StartTxn(nil)
   159  	txn.BindAccessInfo(e.tenantID, 0, 0)
   160  	assert.NoError(e.t, err)
   161  	db, err := txn.GetDatabase(defaultTestDB)
   162  	assert.NoError(e.t, err)
   163  	rel, err := db.GetRelationByName(e.schema.Name)
   164  	if err != nil {
   165  		_ = txn.Rollback()
   166  		return
   167  	}
   168  
   169  	err = rel.Append(bat)
   170  	if err != nil {
   171  		_ = txn.Rollback()
   172  		return
   173  	}
   174  	_ = txn.Commit()
   175  }
   176  func (e *testEngine) deleteAll(skipConflict bool) error {
   177  	txn, rel := e.getRelation()
   178  	it := rel.MakeBlockIt()
   179  	for it.Valid() {
   180  		blk := it.GetBlock()
   181  		view, err := blk.GetColumnDataByName(catalog.PhyAddrColumnName, nil)
   182  		assert.NoError(e.t, err)
   183  		defer view.Close()
   184  		view.ApplyDeletes()
   185  		err = rel.DeleteByPhyAddrKeys(view.GetData())
   186  		assert.NoError(e.t, err)
   187  		it.Next()
   188  	}
   189  	// checkAllColRowsByScan(e.t, rel, 0, true)
   190  	err := txn.Commit()
   191  	if !skipConflict {
   192  		checkAllColRowsByScan(e.t, rel, 0, true)
   193  		assert.NoError(e.t, err)
   194  	}
   195  	return err
   196  }
   197  
   198  func (e *testEngine) truncate() {
   199  	txn, db := e.getTestDB()
   200  	_, err := db.TruncateByName(e.schema.Name)
   201  	assert.NoError(e.t, err)
   202  	assert.NoError(e.t, txn.Commit())
   203  }
   204  func (e *testEngine) globalCheckpoint(
   205  	endTs types.TS,
   206  	versionInterval time.Duration,
   207  	enableAndCleanBGCheckpoint bool,
   208  ) error {
   209  	if enableAndCleanBGCheckpoint {
   210  		e.DB.BGCheckpointRunner.DisableCheckpoint()
   211  		defer e.DB.BGCheckpointRunner.EnableCheckpoint()
   212  		e.DB.BGCheckpointRunner.CleanPenddingCheckpoint()
   213  	}
   214  	if e.DB.BGCheckpointRunner.GetPenddingIncrementalCount() == 0 {
   215  		testutils.WaitExpect(4000, func() bool {
   216  			flushed := e.DB.BGCheckpointRunner.IsAllChangesFlushed(types.TS{}, endTs, false)
   217  			return flushed
   218  		})
   219  		flushed := e.DB.BGCheckpointRunner.IsAllChangesFlushed(types.TS{}, endTs, true)
   220  		assert.True(e.t, flushed)
   221  	}
   222  	err := e.DB.BGCheckpointRunner.ForceGlobalCheckpoint(endTs, versionInterval)
   223  	assert.NoError(e.t, err)
   224  	return nil
   225  }
   226  
   227  func (e *testEngine) incrementalCheckpoint(
   228  	end types.TS,
   229  	enableAndCleanBGCheckpoint bool,
   230  	waitFlush bool,
   231  	truncate bool,
   232  ) error {
   233  	if enableAndCleanBGCheckpoint {
   234  		e.DB.BGCheckpointRunner.DisableCheckpoint()
   235  		defer e.DB.BGCheckpointRunner.EnableCheckpoint()
   236  		e.DB.BGCheckpointRunner.CleanPenddingCheckpoint()
   237  	}
   238  	if waitFlush {
   239  		testutils.WaitExpect(4000, func() bool {
   240  			flushed := e.DB.BGCheckpointRunner.IsAllChangesFlushed(types.TS{}, end, false)
   241  			return flushed
   242  		})
   243  		flushed := e.DB.BGCheckpointRunner.IsAllChangesFlushed(types.TS{}, end, true)
   244  		assert.True(e.t, flushed)
   245  	}
   246  	err := e.DB.BGCheckpointRunner.ForceIncrementalCheckpoint(end)
   247  	assert.NoError(e.t, err)
   248  	if truncate {
   249  		lsn := e.DB.BGCheckpointRunner.MaxLSNInRange(end)
   250  		entry, err := e.DB.Wal.RangeCheckpoint(1, lsn)
   251  		assert.NoError(e.t, err)
   252  		assert.NoError(e.t, entry.WaitDone())
   253  		testutils.WaitExpect(1000, func() bool {
   254  			return e.Scheduler.GetPenddingLSNCnt() == 0
   255  		})
   256  	}
   257  	return nil
   258  }
   259  func initDB(t *testing.T, opts *options.Options) *DB {
   260  	dir := testutils.InitTestEnv(ModuleName, t)
   261  	db, _ := Open(dir, opts)
   262  	// only ut executes this checker
   263  	db.DiskCleaner.AddChecker(
   264  		func(item any) bool {
   265  			min := db.TxnMgr.MinTSForTest()
   266  			checkpoint := item.(*checkpoint2.CheckpointEntry)
   267  			//logutil.Infof("min: %v, checkpoint: %v", min.ToString(), checkpoint.GetStart().ToString())
   268  			return !checkpoint.GetEnd().GreaterEq(min)
   269  		})
   270  	return db
   271  }
   272  
   273  func withTestAllPKType(t *testing.T, tae *DB, test func(*testing.T, *DB, *catalog.Schema)) {
   274  	var wg sync.WaitGroup
   275  	pool, _ := ants.NewPool(100)
   276  	defer pool.Release()
   277  	for i := 0; i < 17; i++ {
   278  		schema := catalog.MockSchemaAll(18, i)
   279  		schema.BlockMaxRows = 10
   280  		schema.SegmentMaxBlocks = 2
   281  		wg.Add(1)
   282  		_ = pool.Submit(func() {
   283  			defer wg.Done()
   284  			test(t, tae, schema)
   285  		})
   286  	}
   287  	wg.Wait()
   288  }
   289  
   290  func lenOfBats(bats []*containers.Batch) int {
   291  	rows := 0
   292  	for _, bat := range bats {
   293  		rows += bat.Length()
   294  	}
   295  	return rows
   296  }
   297  
   298  func printCheckpointStats(t *testing.T, tae *DB) {
   299  	t.Logf("GetCheckpointedLSN: %d", tae.Wal.GetCheckpointed())
   300  	t.Logf("GetPenddingLSNCnt: %d", tae.Wal.GetPenddingCnt())
   301  	t.Logf("GetCurrSeqNum: %d", tae.Wal.GetCurrSeqNum())
   302  }
   303  
   304  func createDB(t *testing.T, e *DB, dbName string) {
   305  	txn, err := e.StartTxn(nil)
   306  	assert.NoError(t, err)
   307  	_, err = txn.CreateDatabase(dbName, "")
   308  	assert.NoError(t, err)
   309  	assert.NoError(t, txn.Commit())
   310  }
   311  
   312  func dropDB(t *testing.T, e *DB, dbName string) {
   313  	txn, err := e.StartTxn(nil)
   314  	assert.NoError(t, err)
   315  	_, err = txn.DropDatabase(dbName)
   316  	assert.NoError(t, err)
   317  	assert.NoError(t, txn.Commit())
   318  }
   319  
   320  func dropRelation(t *testing.T, e *DB, dbName, name string) {
   321  	txn, err := e.StartTxn(nil)
   322  	assert.NoError(t, err)
   323  	db, err := txn.GetDatabase(dbName)
   324  	assert.NoError(t, err)
   325  	_, err = db.DropRelationByName(name)
   326  	assert.NoError(t, err)
   327  	assert.NoError(t, txn.Commit())
   328  }
   329  
   330  func createRelation(t *testing.T, e *DB, dbName string, schema *catalog.Schema, createDB bool) (db handle.Database, rel handle.Relation) {
   331  	txn, db, rel := createRelationNoCommit(t, e, dbName, schema, createDB)
   332  	assert.NoError(t, txn.Commit())
   333  	return
   334  }
   335  
   336  func createRelationNoCommit(t *testing.T, e *DB, dbName string, schema *catalog.Schema, createDB bool) (txn txnif.AsyncTxn, db handle.Database, rel handle.Relation) {
   337  	txn, err := e.StartTxn(nil)
   338  	assert.NoError(t, err)
   339  	if createDB {
   340  		db, err = txn.CreateDatabase(dbName, "")
   341  		assert.NoError(t, err)
   342  	} else {
   343  		db, err = txn.GetDatabase(dbName)
   344  		assert.NoError(t, err)
   345  	}
   346  	rel, err = db.CreateRelation(schema)
   347  	assert.NoError(t, err)
   348  	return
   349  }
   350  
   351  func createRelationAndAppend(
   352  	t *testing.T,
   353  	tenantID uint32,
   354  	e *DB,
   355  	dbName string,
   356  	schema *catalog.Schema,
   357  	bat *containers.Batch,
   358  	createDB bool) (db handle.Database, rel handle.Relation) {
   359  	txn, err := e.StartTxn(nil)
   360  	txn.BindAccessInfo(tenantID, 0, 0)
   361  	assert.NoError(t, err)
   362  	if createDB {
   363  		db, err = txn.CreateDatabase(dbName, "")
   364  		assert.NoError(t, err)
   365  	} else {
   366  		db, err = txn.GetDatabase(dbName)
   367  		assert.NoError(t, err)
   368  	}
   369  	rel, err = db.CreateRelation(schema)
   370  	assert.NoError(t, err)
   371  	err = rel.Append(bat)
   372  	assert.NoError(t, err)
   373  	assert.Nil(t, txn.Commit())
   374  	return
   375  }
   376  
   377  func getRelation(t *testing.T, tenantID uint32, e *DB, dbName, tblName string) (txn txnif.AsyncTxn, rel handle.Relation) {
   378  	txn, err := e.StartTxn(nil)
   379  	txn.BindAccessInfo(tenantID, 0, 0)
   380  	assert.NoError(t, err)
   381  	db, err := txn.GetDatabase(dbName)
   382  	assert.NoError(t, err)
   383  	rel, err = db.GetRelationByName(tblName)
   384  	assert.NoError(t, err)
   385  	return
   386  }
   387  
   388  func getRelationWithTxn(t *testing.T, txn txnif.AsyncTxn, dbName, tblName string) (rel handle.Relation) {
   389  	db, err := txn.GetDatabase(dbName)
   390  	assert.NoError(t, err)
   391  	rel, err = db.GetRelationByName(tblName)
   392  	assert.NoError(t, err)
   393  	return
   394  }
   395  
   396  func getDefaultRelation(t *testing.T, e *DB, name string) (txn txnif.AsyncTxn, rel handle.Relation) {
   397  	return getRelation(t, 0, e, defaultTestDB, name)
   398  }
   399  
   400  func getOneBlock(rel handle.Relation) handle.Block {
   401  	it := rel.MakeBlockIt()
   402  	return it.GetBlock()
   403  }
   404  
   405  func getOneBlockMeta(rel handle.Relation) *catalog.BlockEntry {
   406  	it := rel.MakeBlockIt()
   407  	return it.GetBlock().GetMeta().(*catalog.BlockEntry)
   408  }
   409  
   410  func checkAllColRowsByScan(t *testing.T, rel handle.Relation, expectRows int, applyDelete bool) {
   411  	schema := rel.GetMeta().(*catalog.TableEntry).GetSchema()
   412  	for _, def := range schema.ColDefs {
   413  		rows := getColumnRowsByScan(t, rel, def.Idx, applyDelete)
   414  		assert.Equal(t, expectRows, rows)
   415  	}
   416  }
   417  
   418  func getColumnRowsByScan(t *testing.T, rel handle.Relation, colIdx int, applyDelete bool) int {
   419  	rows := 0
   420  	forEachColumnView(rel, colIdx, func(view *model.ColumnView) (err error) {
   421  		if applyDelete {
   422  			view.ApplyDeletes()
   423  		}
   424  		rows += view.Length()
   425  		// t.Log(view.String())
   426  		return
   427  	})
   428  	return rows
   429  }
   430  
   431  func forEachColumnView(rel handle.Relation, colIdx int, fn func(view *model.ColumnView) error) {
   432  	forEachBlock(rel, func(blk handle.Block) (err error) {
   433  		view, err := blk.GetColumnDataById(colIdx, nil)
   434  		if view == nil {
   435  			logutil.Warnf("blk %v", blk.String())
   436  			return
   437  		}
   438  		if err != nil {
   439  			return
   440  		}
   441  		defer view.Close()
   442  		err = fn(view)
   443  		return
   444  	})
   445  }
   446  
   447  func forEachBlock(rel handle.Relation, fn func(blk handle.Block) error) {
   448  	it := rel.MakeBlockIt()
   449  	var err error
   450  	for it.Valid() {
   451  		if err = fn(it.GetBlock()); err != nil {
   452  			if errors.Is(err, handle.ErrIteratorEnd) {
   453  				return
   454  			} else {
   455  				panic(err)
   456  			}
   457  		}
   458  		it.Next()
   459  	}
   460  }
   461  
   462  func forEachSegment(rel handle.Relation, fn func(seg handle.Segment) error) {
   463  	it := rel.MakeSegmentIt()
   464  	var err error
   465  	for it.Valid() {
   466  		if err = fn(it.GetSegment()); err != nil {
   467  			if errors.Is(err, handle.ErrIteratorEnd) {
   468  				return
   469  			} else {
   470  				panic(err)
   471  			}
   472  		}
   473  		it.Next()
   474  	}
   475  }
   476  
   477  func appendFailClosure(t *testing.T, data *containers.Batch, name string, e *DB, wg *sync.WaitGroup) func() {
   478  	return func() {
   479  		if wg != nil {
   480  			defer wg.Done()
   481  		}
   482  		txn, _ := e.StartTxn(nil)
   483  		database, _ := txn.GetDatabase("db")
   484  		rel, _ := database.GetRelationByName(name)
   485  		err := rel.Append(data)
   486  		assert.NotNil(t, err)
   487  		assert.Nil(t, txn.Rollback())
   488  	}
   489  }
   490  
   491  func appendClosure(t *testing.T, data *containers.Batch, name string, e *DB, wg *sync.WaitGroup) func() {
   492  	return func() {
   493  		if wg != nil {
   494  			defer wg.Done()
   495  		}
   496  		txn, _ := e.StartTxn(nil)
   497  		database, _ := txn.GetDatabase("db")
   498  		rel, _ := database.GetRelationByName(name)
   499  		err := rel.Append(data)
   500  		assert.Nil(t, err)
   501  		assert.Nil(t, txn.Commit())
   502  	}
   503  }
   504  
   505  func tryAppendClosure(t *testing.T, data *containers.Batch, name string, e *DB, wg *sync.WaitGroup) func() {
   506  	return func() {
   507  		if wg != nil {
   508  			defer wg.Done()
   509  		}
   510  		txn, _ := e.StartTxn(nil)
   511  		database, _ := txn.GetDatabase("db")
   512  		rel, err := database.GetRelationByName(name)
   513  		if err != nil {
   514  			_ = txn.Rollback()
   515  			return
   516  		}
   517  		if err = rel.Append(data); err != nil {
   518  			_ = txn.Rollback()
   519  			return
   520  		}
   521  		_ = txn.Commit()
   522  	}
   523  }
   524  
   525  func compactBlocks(t *testing.T, tenantID uint32, e *DB, dbName string, schema *catalog.Schema, skipConflict bool) {
   526  	txn, rel := getRelation(t, tenantID, e, dbName, schema.Name)
   527  
   528  	var metas []*catalog.BlockEntry
   529  	it := rel.MakeBlockIt()
   530  	for it.Valid() {
   531  		blk := it.GetBlock()
   532  		meta := blk.GetMeta().(*catalog.BlockEntry)
   533  		if blk.Rows() < int(schema.BlockMaxRows) {
   534  			it.Next()
   535  			continue
   536  		}
   537  		metas = append(metas, meta)
   538  		it.Next()
   539  	}
   540  	_ = txn.Commit()
   541  	for _, meta := range metas {
   542  		txn, _ := getRelation(t, tenantID, e, dbName, schema.Name)
   543  		task, err := jobs.NewCompactBlockTask(nil, txn, meta, e.Scheduler)
   544  		if skipConflict && err != nil {
   545  			_ = txn.Rollback()
   546  			continue
   547  		}
   548  		assert.NoError(t, err)
   549  		err = task.OnExec()
   550  		if skipConflict {
   551  			if err != nil {
   552  				_ = txn.Rollback()
   553  			} else {
   554  				_ = txn.Commit()
   555  			}
   556  		} else {
   557  			assert.NoError(t, err)
   558  			assert.NoError(t, txn.Commit())
   559  		}
   560  	}
   561  }
   562  
   563  func mergeBlocks(t *testing.T, tenantID uint32, e *DB, dbName string, schema *catalog.Schema, skipConflict bool) {
   564  	txn, _ := e.StartTxn(nil)
   565  	txn.BindAccessInfo(tenantID, 0, 0)
   566  	db, _ := txn.GetDatabase(dbName)
   567  	rel, _ := db.GetRelationByName(schema.Name)
   568  
   569  	var segs []*catalog.SegmentEntry
   570  	segIt := rel.MakeSegmentIt()
   571  	for segIt.Valid() {
   572  		seg := segIt.GetSegment().GetMeta().(*catalog.SegmentEntry)
   573  		if seg.GetAppendableBlockCnt() == int(seg.GetTable().GetSchema().SegmentMaxBlocks) {
   574  			segs = append(segs, seg)
   575  		}
   576  		segIt.Next()
   577  	}
   578  	_ = txn.Commit()
   579  	for _, seg := range segs {
   580  		txn, _ = e.StartTxn(nil)
   581  		txn.BindAccessInfo(tenantID, 0, 0)
   582  		db, _ = txn.GetDatabase(dbName)
   583  		rel, _ = db.GetRelationByName(schema.Name)
   584  		segHandle, err := rel.GetSegment(seg.ID)
   585  		if err != nil {
   586  			if skipConflict {
   587  				_ = txn.Rollback()
   588  				continue
   589  			}
   590  			assert.NoErrorf(t, err, "Txn Ts=%d", txn.GetStartTS())
   591  		}
   592  		var metas []*catalog.BlockEntry
   593  		it := segHandle.MakeBlockIt()
   594  		for it.Valid() {
   595  			meta := it.GetBlock().GetMeta().(*catalog.BlockEntry)
   596  			metas = append(metas, meta)
   597  			it.Next()
   598  		}
   599  		segsToMerge := []*catalog.SegmentEntry{segHandle.GetMeta().(*catalog.SegmentEntry)}
   600  		task, err := jobs.NewMergeBlocksTask(nil, txn, metas, segsToMerge, nil, e.Scheduler)
   601  		if skipConflict && err != nil {
   602  			_ = txn.Rollback()
   603  			continue
   604  		}
   605  		assert.NoError(t, err)
   606  		err = task.OnExec()
   607  		if skipConflict {
   608  			if err != nil {
   609  				_ = txn.Rollback()
   610  			} else {
   611  				_ = txn.Commit()
   612  			}
   613  		} else {
   614  			assert.NoError(t, err)
   615  			assert.NoError(t, txn.Commit())
   616  		}
   617  	}
   618  }
   619  
   620  /*func compactSegs(t *testing.T, e *DB, schema *catalog.Schema) {
   621  	txn, rel := getDefaultRelation(t, e, schema.Name)
   622  	segs := make([]*catalog.SegmentEntry, 0)
   623  	it := rel.MakeSegmentIt()
   624  	for it.Valid() {
   625  		seg := it.GetSegment().GetMeta().(*catalog.SegmentEntry)
   626  		segs = append(segs, seg)
   627  		it.Next()
   628  	}
   629  	for _, segMeta := range segs {
   630  		seg := segMeta.GetSegmentData()
   631  		factory, taskType, scopes, err := seg.BuildCompactionTaskFactory()
   632  		assert.NoError(t, err)
   633  		if factory == nil {
   634  			continue
   635  		}
   636  		task, err := e.Scheduler.ScheduleMultiScopedTxnTask(tasks.WaitableCtx, taskType, scopes, factory)
   637  		assert.NoError(t, err)
   638  		err = task.WaitDone()
   639  		assert.NoError(t, err)
   640  	}
   641  	assert.NoError(t, txn.Commit())
   642  }*/
   643  
   644  func getSingleSortKeyValue(bat *containers.Batch, schema *catalog.Schema, row int) (v any) {
   645  	v = bat.Vecs[schema.GetSingleSortKeyIdx()].Get(row)
   646  	return
   647  }