github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/disttae/merge.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 disttae
    16  
    17  import (
    18  	"context"
    19  	"strings"
    20  
    21  	"github.com/matrixorigin/matrixone/pkg/catalog"
    22  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    23  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    24  	"github.com/matrixorigin/matrixone/pkg/container/nulls"
    25  	"github.com/matrixorigin/matrixone/pkg/container/types"
    26  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    27  	"github.com/matrixorigin/matrixone/pkg/fileservice"
    28  	"github.com/matrixorigin/matrixone/pkg/logutil"
    29  	"github.com/matrixorigin/matrixone/pkg/objectio"
    30  	"github.com/matrixorigin/matrixone/pkg/pb/api"
    31  	"github.com/matrixorigin/matrixone/pkg/vm/engine/disttae/logtailreplay"
    32  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/blockio"
    33  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/mergesort"
    34  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/options"
    35  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    36  )
    37  
    38  type cnMergeTask struct {
    39  	host *txnTable
    40  	// txn
    41  	snapshot types.TS // start ts, fixed
    42  	state    *logtailreplay.PartitionState
    43  	proc     *process.Process
    44  
    45  	// schema
    46  	version     uint32       // version
    47  	colseqnums  []uint16     // no rowid column
    48  	coltypes    []types.Type // no rowid column
    49  	colattrs    []string     // no rowid column
    50  	sortkeyPos  int          // (composite) primary key, cluster by etc. -1 meas no sort key
    51  	sortkeyIsPK bool
    52  
    53  	doTransfer bool
    54  
    55  	// targets
    56  	targets []logtailreplay.ObjectInfo
    57  
    58  	// commit things
    59  	commitEntry *api.MergeCommitEntry
    60  
    61  	// auxiliaries
    62  	fs fileservice.FileService
    63  
    64  	blkCnts  []int
    65  	blkIters []*StatsBlkIter
    66  
    67  	targetObjSize uint32
    68  }
    69  
    70  func newCNMergeTask(
    71  	ctx context.Context,
    72  	tbl *txnTable,
    73  	snapshot types.TS,
    74  	state *logtailreplay.PartitionState,
    75  	sortkeyPos int,
    76  	sortkeyIsPK bool,
    77  	targets []logtailreplay.ObjectInfo,
    78  	targetObjSize uint32,
    79  ) (*cnMergeTask, error) {
    80  	proc := tbl.proc.Load()
    81  	attrs := make([]string, 0, len(tbl.seqnums))
    82  	for i := 0; i < len(tbl.tableDef.Cols)-1; i++ {
    83  		attrs = append(attrs, tbl.tableDef.Cols[i].Name)
    84  	}
    85  	fs := proc.FileService
    86  
    87  	blkCnts := make([]int, len(targets))
    88  	blkIters := make([]*StatsBlkIter, len(targets))
    89  	for i, objInfo := range targets {
    90  		objInfo := objInfo
    91  		blkCnts[i] = int(objInfo.BlkCnt())
    92  
    93  		loc := objInfo.ObjectLocation()
    94  		meta, err := objectio.FastLoadObjectMeta(ctx, &loc, false, fs)
    95  		if err != nil {
    96  			return nil, err
    97  		}
    98  
    99  		blkIters[i] = NewStatsBlkIter(&objInfo.ObjectStats, meta.MustDataMeta())
   100  	}
   101  
   102  	return &cnMergeTask{
   103  		host:        tbl,
   104  		snapshot:    snapshot,
   105  		state:       state,
   106  		proc:        proc,
   107  		version:     tbl.version,
   108  		colseqnums:  tbl.seqnums,
   109  		coltypes:    tbl.typs,
   110  		colattrs:    attrs,
   111  		sortkeyPos:  sortkeyPos,
   112  		sortkeyIsPK: sortkeyIsPK,
   113  		targets:     targets,
   114  		fs:          fs,
   115  		blkCnts:     blkCnts,
   116  		blkIters:    blkIters,
   117  
   118  		targetObjSize: targetObjSize,
   119  		doTransfer:    !strings.Contains(tbl.comment, catalog.MO_COMMENT_NO_DEL_HINT),
   120  	}, nil
   121  }
   122  
   123  func (t *cnMergeTask) DoTransfer() bool {
   124  	return t.doTransfer
   125  }
   126  func (t *cnMergeTask) GetObjectCnt() int {
   127  	return len(t.targets)
   128  }
   129  
   130  func (t *cnMergeTask) GetBlkCnts() []int {
   131  	return t.blkCnts
   132  }
   133  
   134  func (t *cnMergeTask) GetAccBlkCnts() []int {
   135  	accCnt := make([]int, 0, len(t.targets))
   136  	acc := 0
   137  	for _, objInfo := range t.targets {
   138  		accCnt = append(accCnt, acc)
   139  		acc += int(objInfo.BlkCnt())
   140  	}
   141  	return accCnt
   142  }
   143  
   144  func (t *cnMergeTask) GetBlockMaxRows() uint32 {
   145  	return options.DefaultBlockMaxRows
   146  }
   147  
   148  func (t *cnMergeTask) GetObjectMaxBlocks() uint16 {
   149  	return options.DefaultBlocksPerObject
   150  }
   151  
   152  func (t *cnMergeTask) GetTargetObjSize() uint32 {
   153  	return t.targetObjSize
   154  }
   155  
   156  func (t *cnMergeTask) GetSortKeyType() types.Type {
   157  	if t.sortkeyPos >= 0 {
   158  		return t.coltypes[t.sortkeyPos]
   159  	}
   160  	return types.Type{}
   161  }
   162  
   163  func (t *cnMergeTask) LoadNextBatch(ctx context.Context, objIdx uint32) (*batch.Batch, *nulls.Nulls, func(), error) {
   164  	iter := t.blkIters[objIdx]
   165  	if iter.Next() {
   166  		blk := iter.Entry()
   167  		// update delta location
   168  		obj := t.targets[objIdx]
   169  		blk.Sorted = obj.Sorted
   170  		blk.EntryState = obj.EntryState
   171  		blk.CommitTs = obj.CommitTS
   172  		if obj.HasDeltaLoc {
   173  			deltaLoc, commitTs, ok := t.state.GetBockDeltaLoc(blk.BlockID)
   174  			if ok {
   175  				blk.DeltaLoc = deltaLoc
   176  				blk.CommitTs = commitTs
   177  			}
   178  		}
   179  		return t.readblock(ctx, &blk)
   180  	}
   181  	return nil, nil, nil, mergesort.ErrNoMoreBlocks
   182  }
   183  
   184  func (t *cnMergeTask) GetCommitEntry() *api.MergeCommitEntry {
   185  	if t.commitEntry == nil {
   186  		return t.prepareCommitEntry()
   187  	}
   188  	return t.commitEntry
   189  }
   190  
   191  // impl DisposableVecPool
   192  func (t *cnMergeTask) GetVector(typ *types.Type) (*vector.Vector, func()) {
   193  	v := t.proc.GetVector(*typ)
   194  	return v, func() { t.proc.PutVector(v) }
   195  }
   196  
   197  func (t *cnMergeTask) GetMPool() *mpool.MPool {
   198  	return t.proc.GetMPool()
   199  }
   200  
   201  func (t *cnMergeTask) HostHintName() string { return "CN" }
   202  
   203  func (t *cnMergeTask) PrepareData(ctx context.Context) ([]*batch.Batch, []*nulls.Nulls, func(), error) {
   204  	r, release, d, e := t.readAllData(ctx)
   205  	return r, d, release, e
   206  }
   207  
   208  func (t *cnMergeTask) GetTotalSize() uint32 {
   209  	totalSize := uint32(0)
   210  	for _, obj := range t.targets {
   211  		totalSize += obj.OriginSize()
   212  	}
   213  	return totalSize
   214  }
   215  
   216  func (t *cnMergeTask) GetTotalRowCnt() uint32 {
   217  	totalRowCnt := uint32(0)
   218  	for _, obj := range t.targets {
   219  		totalRowCnt += obj.Rows()
   220  	}
   221  	return totalRowCnt
   222  }
   223  
   224  func (t *cnMergeTask) prepareCommitEntry() *api.MergeCommitEntry {
   225  	commitEntry := &api.MergeCommitEntry{}
   226  	commitEntry.DbId = t.host.db.databaseId
   227  	commitEntry.TblId = t.host.tableId
   228  	commitEntry.TableName = t.host.tableName
   229  	commitEntry.StartTs = t.snapshot.ToTimestamp()
   230  	for _, o := range t.targets {
   231  		commitEntry.MergedObjs = append(commitEntry.MergedObjs, o.ObjectStats.Clone().Marshal())
   232  	}
   233  	t.commitEntry = commitEntry
   234  	// leave mapping to ReadMergeAndWrite
   235  	return commitEntry
   236  }
   237  
   238  func (t *cnMergeTask) PrepareNewWriter() *blockio.BlockWriter {
   239  	return mergesort.GetNewWriter(t.fs, t.version, t.colseqnums, t.sortkeyPos, t.sortkeyIsPK)
   240  }
   241  
   242  func (t *cnMergeTask) readAllData(ctx context.Context) ([]*batch.Batch, func(), []*nulls.Nulls, error) {
   243  	var cnt uint32
   244  	for _, t := range t.targets {
   245  		cnt += t.BlkCnt()
   246  	}
   247  	blkBatches := make([]*batch.Batch, 0, cnt)
   248  	blkDels := make([]*nulls.Nulls, 0, cnt)
   249  	releases := make([]func(), 0, cnt)
   250  
   251  	release := func() {
   252  		for _, r := range releases {
   253  			r()
   254  		}
   255  	}
   256  
   257  	for _, obj := range t.targets {
   258  		loc := obj.ObjectLocation()
   259  		meta, err := objectio.FastLoadObjectMeta(ctx, &loc, false, t.fs)
   260  		if err != nil {
   261  			release()
   262  			return nil, nil, nil, err
   263  		}
   264  
   265  		// read all blocks data in an object
   266  		var innerErr error
   267  		readBlock := func(blk objectio.BlockInfo, _ objectio.BlockObject) bool {
   268  			// update delta location
   269  			blk.Sorted = obj.Sorted
   270  			blk.EntryState = obj.EntryState
   271  			blk.CommitTs = obj.CommitTS
   272  			if obj.HasDeltaLoc {
   273  				deltaLoc, commitTs, ok := t.state.GetBockDeltaLoc(blk.BlockID)
   274  				if ok {
   275  					blk.DeltaLoc = deltaLoc
   276  					blk.CommitTs = commitTs
   277  				}
   278  			}
   279  			bat, delmask, releasef, err := t.readblock(ctx, &blk)
   280  			if err != nil {
   281  				innerErr = err
   282  				return false
   283  			}
   284  
   285  			blkBatches = append(blkBatches, bat)
   286  			releases = append(releases, releasef)
   287  			blkDels = append(blkDels, delmask)
   288  			return true
   289  		}
   290  		ForeachBlkInObjStatsList(false, meta.MustDataMeta(), readBlock, obj.ObjectStats)
   291  		// if err is found, bail out
   292  		if innerErr != nil {
   293  			release()
   294  			return nil, nil, nil, innerErr
   295  		}
   296  	}
   297  
   298  	return blkBatches, release, blkDels, nil
   299  }
   300  
   301  // readblock reads block data. there is no rowid column, no ablk
   302  func (t *cnMergeTask) readblock(ctx context.Context, info *objectio.BlockInfo) (bat *batch.Batch, dels *nulls.Nulls, release func(), err error) {
   303  	// read data
   304  	bat, release, err = blockio.LoadColumns(ctx, t.colseqnums, t.coltypes, t.fs, info.MetaLocation(), t.proc.GetMPool(), fileservice.Policy(0))
   305  	if err != nil {
   306  		return
   307  	}
   308  
   309  	// read tombstone on disk
   310  	if !info.DeltaLocation().IsEmpty() {
   311  		obat, byCN, delRelease, err2 := blockio.ReadBlockDelete(ctx, info.DeltaLocation(), t.fs)
   312  		if err2 != nil {
   313  			err = err2
   314  			return
   315  		}
   316  		defer delRelease()
   317  		if byCN {
   318  			dels = blockio.EvalDeleteRowsByTimestampForDeletesPersistedByCN(obat, t.snapshot, info.CommitTs)
   319  		} else {
   320  			dels = blockio.EvalDeleteRowsByTimestamp(obat, t.snapshot, &info.BlockID)
   321  		}
   322  	}
   323  
   324  	if dels == nil {
   325  		dels = nulls.NewWithSize(128)
   326  	}
   327  	deltalocDel := dels.Count()
   328  	// read tombstone in memory
   329  	iter := t.state.NewRowsIter(t.snapshot, &info.BlockID, true)
   330  	for iter.Next() {
   331  		entry := iter.Entry()
   332  		_, offset := entry.RowID.Decode()
   333  		dels.Add(uint64(offset))
   334  	}
   335  	iter.Close()
   336  	if dels.Count() > 0 {
   337  		logutil.Infof("mergeblocks read block %v, %d deleted(%d from disk)", info.BlockID.ShortStringEx(), dels.Count(), deltalocDel)
   338  	}
   339  
   340  	bat.SetAttributes(t.colattrs)
   341  	return
   342  }