github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/tables/txnentries/flushTableTail.go (about)

     1  package txnentries
     2  
     3  // Copyright 2021 Matrix Origin
     4  //
     5  // Licensed under the Apache License, Version 2.0 (the "License");
     6  // you may not use this file except in compliance with the License.
     7  // You may obtain a copy of the License at
     8  //
     9  //      http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"fmt"
    21  	"io"
    22  	"time"
    23  
    24  	"github.com/matrixorigin/matrixone/pkg/container/types"
    25  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    26  	"github.com/matrixorigin/matrixone/pkg/logutil"
    27  	"github.com/matrixorigin/matrixone/pkg/objectio"
    28  	"github.com/matrixorigin/matrixone/pkg/pb/api"
    29  	v2 "github.com/matrixorigin/matrixone/pkg/util/metric/v2"
    30  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog"
    31  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    32  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers"
    33  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/db/dbutils"
    34  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/handle"
    35  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif"
    36  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/model"
    37  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tasks"
    38  )
    39  
    40  type flushTableTailEntry struct {
    41  	txn txnif.AsyncTxn
    42  
    43  	taskID     uint64
    44  	tableEntry *catalog.TableEntry
    45  
    46  	transMappings      *api.BlkTransferBooking
    47  	ablksMetas         []*catalog.ObjectEntry
    48  	delSrcMetas        []*catalog.ObjectEntry
    49  	ablksHandles       []handle.Object
    50  	delSrcHandles      []handle.Object
    51  	createdBlkHandles  handle.Object
    52  	createdDeletesFile string
    53  	createdMergeFile   string
    54  	dirtyLen           int
    55  	rt                 *dbutils.Runtime
    56  	dirtyEndTs         types.TS
    57  
    58  	// use TxnMgr.Now as collectTs to do the first collect deletes,
    59  	// which is a relief for the second try in the commit queue
    60  	collectTs types.TS
    61  	// we have to record the ACTUAL commit time of those deletes that happened
    62  	// in the flushing process, before packed them into the created object.
    63  	delTbls []*model.TransDels
    64  	// some statistics
    65  	pageIds              []*common.ID
    66  	transCntBeforeCommit int
    67  	nextRoundDirties     map[*catalog.ObjectEntry]struct{}
    68  }
    69  
    70  func NewFlushTableTailEntry(
    71  	txn txnif.AsyncTxn,
    72  	taskID uint64,
    73  	mapping *api.BlkTransferBooking,
    74  	tableEntry *catalog.TableEntry,
    75  	ablksMetas []*catalog.ObjectEntry,
    76  	nblksMetas []*catalog.ObjectEntry,
    77  	ablksHandles []handle.Object,
    78  	nblksHandles []handle.Object,
    79  	createdBlkHandles handle.Object,
    80  	createdDeletesFile string,
    81  	createdMergeFile string,
    82  	dirtyLen int,
    83  	rt *dbutils.Runtime,
    84  	dirtyEndTs types.TS,
    85  ) (*flushTableTailEntry, error) {
    86  
    87  	entry := &flushTableTailEntry{
    88  		txn:                txn,
    89  		taskID:             taskID,
    90  		transMappings:      mapping,
    91  		tableEntry:         tableEntry,
    92  		ablksMetas:         ablksMetas,
    93  		delSrcMetas:        nblksMetas,
    94  		ablksHandles:       ablksHandles,
    95  		delSrcHandles:      nblksHandles,
    96  		createdBlkHandles:  createdBlkHandles,
    97  		createdDeletesFile: createdDeletesFile,
    98  		createdMergeFile:   createdMergeFile,
    99  		dirtyLen:           dirtyLen,
   100  		rt:                 rt,
   101  		dirtyEndTs:         dirtyEndTs,
   102  	}
   103  
   104  	if entry.transMappings != nil {
   105  		if entry.createdBlkHandles != nil {
   106  			entry.delTbls = make([]*model.TransDels, entry.createdBlkHandles.GetMeta().(*catalog.ObjectEntry).BlockCnt())
   107  			entry.nextRoundDirties = make(map[*catalog.ObjectEntry]struct{})
   108  			// collect deletes phase 1
   109  			entry.collectTs = rt.Now()
   110  			var err error
   111  			entry.transCntBeforeCommit, err = entry.collectDelsAndTransfer(entry.txn.GetStartTS(), entry.collectTs)
   112  			if err != nil {
   113  				return nil, err
   114  			}
   115  		}
   116  		// prepare transfer pages
   117  		entry.addTransferPages()
   118  	}
   119  
   120  	return entry, nil
   121  }
   122  
   123  // add transfer pages for dropped aobjects
   124  func (entry *flushTableTailEntry) addTransferPages() {
   125  	isTransient := !entry.tableEntry.GetLastestSchemaLocked().HasPK()
   126  	for i, mcontainer := range entry.transMappings.Mappings {
   127  		m := mcontainer.M
   128  		if len(m) == 0 {
   129  			continue
   130  		}
   131  		id := entry.ablksHandles[i].Fingerprint()
   132  		entry.pageIds = append(entry.pageIds, id)
   133  		page := model.NewTransferHashPage(id, time.Now(), isTransient)
   134  		for srcRow, dst := range m {
   135  			blkid := objectio.NewBlockidWithObjectID(entry.createdBlkHandles.GetID(), uint16(dst.BlkIdx))
   136  			page.Train(uint32(srcRow), *objectio.NewRowid(blkid, uint32(dst.RowIdx)))
   137  		}
   138  		entry.rt.TransferTable.AddPage(page)
   139  	}
   140  }
   141  
   142  // collectDelsAndTransfer collects deletes in flush process and moves them to the created obj
   143  // ATTENTION !!! (from, to] !!!
   144  func (entry *flushTableTailEntry) collectDelsAndTransfer(from, to types.TS) (transCnt int, err error) {
   145  	if len(entry.ablksHandles) == 0 {
   146  		return
   147  	}
   148  	// if created blk handles is nil, all rows in ablks are deleted
   149  	if entry.createdBlkHandles == nil {
   150  		return
   151  	}
   152  	for i, blk := range entry.ablksMetas {
   153  		// For ablock, there is only one block in it.
   154  		// Checking the block mapping once is enough
   155  		mapping := entry.transMappings.Mappings[i].M
   156  		if len(mapping) == 0 {
   157  			// empty frozen aobjects, it can not has any more deletes
   158  			continue
   159  		}
   160  		dataBlock := blk.GetObjectData()
   161  		var bat *containers.Batch
   162  		bat, _, err = dataBlock.CollectDeleteInRange(
   163  			entry.txn.GetContext(),
   164  			from.Next(), // NOTE HERE
   165  			to,
   166  			false,
   167  			common.MergeAllocator,
   168  		)
   169  		if err != nil {
   170  			return
   171  		}
   172  		if bat == nil || bat.Length() == 0 {
   173  			continue
   174  		}
   175  		rowid := vector.MustFixedCol[types.Rowid](bat.GetVectorByName(catalog.PhyAddrColumnName).GetDownstreamVector())
   176  		ts := vector.MustFixedCol[types.TS](bat.GetVectorByName(catalog.AttrCommitTs).GetDownstreamVector())
   177  
   178  		count := len(rowid)
   179  		transCnt += count
   180  		for i := 0; i < count; i++ {
   181  			row := rowid[i].GetRowOffset()
   182  			destpos, ok := mapping[int32(row)]
   183  			if !ok {
   184  				panic(fmt.Sprintf("%s find no transfer mapping for row %d", blk.ID.String(), row))
   185  			}
   186  			if entry.delTbls[destpos.BlkIdx] == nil {
   187  				entry.delTbls[destpos.BlkIdx] = model.NewTransDels(entry.txn.GetPrepareTS())
   188  			}
   189  			entry.delTbls[destpos.BlkIdx].Mapping[int(destpos.RowIdx)] = ts[i]
   190  			if err = entry.createdBlkHandles.RangeDelete(
   191  				uint16(destpos.BlkIdx), uint32(destpos.RowIdx), uint32(destpos.RowIdx), handle.DT_MergeCompact, common.MergeAllocator,
   192  			); err != nil {
   193  				bat.Close()
   194  				return
   195  			}
   196  		}
   197  		bat.Close()
   198  		entry.nextRoundDirties[blk] = struct{}{}
   199  	}
   200  	return
   201  }
   202  
   203  // PrepareCommit check deletes between start ts and commit ts
   204  func (entry *flushTableTailEntry) PrepareCommit() error {
   205  	inst := time.Now()
   206  	defer func() {
   207  		v2.TaskCommitTableTailDurationHistogram.Observe(time.Since(inst).Seconds())
   208  	}()
   209  	if entry.transMappings == nil {
   210  		// no del table, no transfer
   211  		return nil
   212  	}
   213  	trans, err := entry.collectDelsAndTransfer(entry.collectTs, entry.txn.GetPrepareTS())
   214  	if err != nil {
   215  		return err
   216  	}
   217  
   218  	for i, delTbl := range entry.delTbls {
   219  		if delTbl != nil {
   220  			destid := objectio.NewBlockidWithObjectID(entry.createdBlkHandles.GetID(), uint16(i))
   221  			entry.rt.TransferDelsMap.SetDelsForBlk(*destid, delTbl)
   222  		}
   223  	}
   224  
   225  	if aconflictCnt, totalTrans := len(entry.nextRoundDirties), trans+entry.transCntBeforeCommit; aconflictCnt > 0 || totalTrans > 0 {
   226  		logutil.Infof(
   227  			"[FlushTabletail] task %d ww (%s .. %s): on %d ablk, transfer %v rows, %d in commit queue",
   228  			entry.taskID,
   229  			entry.txn.GetStartTS().ToString(),
   230  			entry.txn.GetPrepareTS().ToString(),
   231  			aconflictCnt,
   232  			totalTrans,
   233  			trans,
   234  		)
   235  	}
   236  	return nil
   237  }
   238  
   239  // PrepareRollback remove transfer page and written files
   240  func (entry *flushTableTailEntry) PrepareRollback() (err error) {
   241  	logutil.Warnf("[FlushTabletail] FT task %d rollback", entry.taskID)
   242  	// remove transfer page
   243  	for _, id := range entry.pageIds {
   244  		_ = entry.rt.TransferTable.DeletePage(id)
   245  	}
   246  
   247  	// why not clean TranDel?
   248  	// 1. There's little tiny chance for a txn to fail after PrepareCommit
   249  	// 2. If txn failed, no txn will see the transfered deletes,
   250  	//    so no one will consult the TransferDelsMap about the right commite time.
   251  	//    It's ok to leave the DelsMap fade away naturally.
   252  
   253  	// remove written file
   254  	fs := entry.rt.Fs.Service
   255  
   256  	// object for snapshot read of aobjects
   257  	ablkNames := make([]string, 0, len(entry.ablksMetas))
   258  	for _, blk := range entry.ablksMetas {
   259  		if !blk.HasPersistedData() {
   260  			logutil.Infof("[FlushTabletail] skip empty ablk %s when rollback", blk.ID.String())
   261  			continue
   262  		}
   263  		seg := blk.ID.Segment()
   264  		name := objectio.BuildObjectName(seg, 0).String()
   265  		ablkNames = append(ablkNames, name)
   266  	}
   267  
   268  	// for io task, dispatch by round robin, scope can be nil
   269  	entry.rt.Scheduler.ScheduleScopedFn(&tasks.Context{}, tasks.IOTask, nil, func() error {
   270  		// TODO: variable as timeout
   271  		ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
   272  		defer cancel()
   273  		for _, name := range ablkNames {
   274  			_ = fs.Delete(ctx, name)
   275  		}
   276  		if entry.createdDeletesFile != "" {
   277  			_ = fs.Delete(ctx, entry.createdDeletesFile)
   278  		}
   279  		if entry.createdMergeFile != "" {
   280  			_ = fs.Delete(ctx, entry.createdMergeFile)
   281  		}
   282  		return nil
   283  	})
   284  	return
   285  }
   286  
   287  // ApplyCommit Gc in memory deletes and update table compact status
   288  func (entry *flushTableTailEntry) ApplyCommit() (err error) {
   289  	for _, blk := range entry.ablksMetas {
   290  		_ = blk.GetObjectData().TryUpgrade()
   291  		blk.GetObjectData().UpgradeAllDeleteChain()
   292  	}
   293  
   294  	for _, blk := range entry.delSrcMetas {
   295  		blk.GetObjectData().UpgradeAllDeleteChain()
   296  	}
   297  
   298  	tbl := entry.tableEntry
   299  	tbl.Stats.Lock()
   300  	defer tbl.Stats.Unlock()
   301  	tbl.Stats.LastFlush = entry.dirtyEndTs
   302  	// no merge tasks touch the dirties, we are good to clean all
   303  	if entry.dirtyLen == len(tbl.DeletedDirties) {
   304  		tbl.DeletedDirties = tbl.DeletedDirties[:0]
   305  	} else {
   306  		// some merge tasks touch the dirties, we need to keep those new dirties
   307  		tbl.DeletedDirties = tbl.DeletedDirties[entry.dirtyLen:]
   308  	}
   309  	for k := range entry.nextRoundDirties {
   310  		tbl.DeletedDirties = append(tbl.DeletedDirties, k)
   311  	}
   312  	return
   313  }
   314  
   315  func (entry *flushTableTailEntry) ApplyRollback() (err error) {
   316  	return
   317  }
   318  
   319  func (entry *flushTableTailEntry) MakeCommand(csn uint32) (cmd txnif.TxnCmd, err error) {
   320  	return &flushTableTailCmd{}, nil
   321  }
   322  func (entry *flushTableTailEntry) IsAborted() bool { return false }
   323  func (entry *flushTableTailEntry) Set1PC()         {}
   324  func (entry *flushTableTailEntry) Is1PC() bool     { return false }
   325  
   326  ////////////////////////////////////////
   327  // flushTableTailCmd
   328  ////////////////////////////////////////
   329  
   330  type flushTableTailCmd struct{}
   331  
   332  func (cmd *flushTableTailCmd) GetType() uint16 { return IOET_WALTxnCommand_Compact }
   333  func (cmd *flushTableTailCmd) WriteTo(w io.Writer) (n int64, err error) {
   334  	typ := IOET_WALTxnCommand_FlushTableTail
   335  	if _, err = w.Write(types.EncodeUint16(&typ)); err != nil {
   336  		return
   337  	}
   338  	n = 2
   339  	ver := IOET_WALTxnCommand_FlushTableTail_CurrVer
   340  	if _, err = w.Write(types.EncodeUint16(&ver)); err != nil {
   341  		return
   342  	}
   343  	n = 2
   344  	return
   345  }
   346  func (cmd *flushTableTailCmd) MarshalBinary() (buf []byte, err error) {
   347  	var bbuf bytes.Buffer
   348  	if _, err = cmd.WriteTo(&bbuf); err != nil {
   349  		return
   350  	}
   351  	buf = bbuf.Bytes()
   352  	return
   353  }
   354  func (cmd *flushTableTailCmd) ReadFrom(r io.Reader) (n int64, err error) { return }
   355  func (cmd *flushTableTailCmd) UnmarshalBinary(buf []byte) (err error)    { return }
   356  func (cmd *flushTableTailCmd) Desc() string                              { return "CmdName=CPCT" }
   357  func (cmd *flushTableTailCmd) String() string                            { return "CmdName=CPCT" }
   358  func (cmd *flushTableTailCmd) VerboseString() string                     { return "CmdName=CPCT" }
   359  func (cmd *flushTableTailCmd) ApplyCommit()                              {}
   360  func (cmd *flushTableTailCmd) ApplyRollback()                            {}
   361  func (cmd *flushTableTailCmd) SetReplayTxn(txnif.AsyncTxn)               {}
   362  func (cmd *flushTableTailCmd) Close()                                    {}