github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/tables/txnentries/mergeblocks.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 txnentries
    16  
    17  import (
    18  	"sync"
    19  	"time"
    20  
    21  	"github.com/RoaringBitmap/roaring"
    22  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog"
    23  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    24  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/compute"
    25  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/handle"
    26  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif"
    27  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/model"
    28  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tasks"
    29  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/wal"
    30  )
    31  
    32  type mergeBlocksEntry struct {
    33  	sync.RWMutex
    34  	txn         txnif.AsyncTxn
    35  	relation    handle.Relation
    36  	droppedSegs []*catalog.SegmentEntry
    37  	deletes     []*roaring.Bitmap
    38  	createdSegs []*catalog.SegmentEntry
    39  	droppedBlks []*catalog.BlockEntry
    40  	createdBlks []*catalog.BlockEntry
    41  	mapping     []uint32
    42  	fromAddr    []uint32
    43  	toAddr      []uint32
    44  	scheduler   tasks.TaskScheduler
    45  	skippedBlks []int
    46  }
    47  
    48  func NewMergeBlocksEntry(
    49  	txn txnif.AsyncTxn,
    50  	relation handle.Relation,
    51  	droppedSegs, createdSegs []*catalog.SegmentEntry,
    52  	droppedBlks, createdBlks []*catalog.BlockEntry,
    53  	mapping, fromAddr, toAddr []uint32,
    54  	deletes []*roaring.Bitmap,
    55  	skipBlks []int,
    56  	scheduler tasks.TaskScheduler) *mergeBlocksEntry {
    57  	return &mergeBlocksEntry{
    58  		txn:         txn,
    59  		relation:    relation,
    60  		createdSegs: createdSegs,
    61  		droppedSegs: droppedSegs,
    62  		createdBlks: createdBlks,
    63  		droppedBlks: droppedBlks,
    64  		mapping:     mapping,
    65  		fromAddr:    fromAddr,
    66  		toAddr:      toAddr,
    67  		scheduler:   scheduler,
    68  		deletes:     deletes,
    69  		skippedBlks: skipBlks,
    70  	}
    71  }
    72  
    73  func (entry *mergeBlocksEntry) PrepareRollback() (err error) {
    74  	// TODO: remove block file? (should be scheduled and executed async)
    75  	return
    76  }
    77  func (entry *mergeBlocksEntry) ApplyRollback(index *wal.Index) (err error) {
    78  	//TODO::?
    79  	return
    80  }
    81  
    82  func (entry *mergeBlocksEntry) ApplyCommit(index *wal.Index) (err error) {
    83  	return
    84  }
    85  
    86  func (entry *mergeBlocksEntry) MakeCommand(csn uint32) (cmd txnif.TxnCmd, err error) {
    87  	droppedSegs := make([]*common.ID, 0)
    88  	for _, blk := range entry.droppedSegs {
    89  		id := blk.AsCommonID()
    90  		droppedSegs = append(droppedSegs, id)
    91  	}
    92  	createdSegs := make([]*common.ID, 0)
    93  	for _, blk := range entry.createdSegs {
    94  		id := blk.AsCommonID()
    95  		createdSegs = append(createdSegs, id)
    96  	}
    97  	droppedBlks := make([]*common.ID, 0)
    98  	for _, blk := range entry.droppedBlks {
    99  		id := blk.AsCommonID()
   100  		droppedBlks = append(droppedBlks, id)
   101  	}
   102  	createdBlks := make([]*common.ID, 0)
   103  	for _, blk := range entry.createdBlks {
   104  		createdBlks = append(createdBlks, blk.AsCommonID())
   105  	}
   106  	cmd = newMergeBlocksCmd(
   107  		entry.relation.ID(),
   108  		droppedSegs,
   109  		createdSegs,
   110  		droppedBlks,
   111  		createdBlks,
   112  		entry.mapping,
   113  		entry.fromAddr,
   114  		entry.toAddr,
   115  		entry.txn,
   116  		csn)
   117  	return
   118  }
   119  
   120  func (entry *mergeBlocksEntry) Set1PC()     {}
   121  func (entry *mergeBlocksEntry) Is1PC() bool { return false }
   122  func (entry *mergeBlocksEntry) resolveAddr(fromPos int, fromOffset uint32) (toPos int, toOffset uint32) {
   123  	totalFromOffset := entry.fromAddr[fromPos] + fromOffset
   124  	totalToOffset := entry.mapping[totalFromOffset]
   125  	left, right := 0, len(entry.toAddr)-1
   126  	for left <= right {
   127  		toPos = (left + right) / 2
   128  		if entry.toAddr[toPos] < totalToOffset {
   129  			left = toPos + 1
   130  		} else if entry.toAddr[toPos] > totalToOffset {
   131  			right = toPos - 1
   132  		} else {
   133  			break
   134  		}
   135  	}
   136  
   137  	// if toPos == 0 && entry.toAddr[toPos] < totalToOffset {
   138  	if entry.toAddr[toPos] > totalToOffset {
   139  		toPos = toPos - 1
   140  	}
   141  	toOffset = totalToOffset - entry.toAddr[toPos]
   142  	// logutil.Infof("mapping=%v", entry.mapping)
   143  	// logutil.Infof("fromPos=%d, fromOff=%d", fromPos, fromOffset)
   144  	// logutil.Infof("fromAddr=%v", entry.fromAddr)
   145  	// logutil.Infof("toAddr=%v", entry.toAddr)
   146  	// logutil.Infof("toPos=%d, toOffset=%d", toPos, toOffset)
   147  	return
   148  }
   149  
   150  func (entry *mergeBlocksEntry) isSkipped(fromPos int) bool {
   151  	for _, offset := range entry.skippedBlks {
   152  		if offset == fromPos {
   153  			return true
   154  		}
   155  	}
   156  	return false
   157  }
   158  
   159  func (entry *mergeBlocksEntry) transferBlockDeletes(
   160  	dropped *catalog.BlockEntry,
   161  	blks []handle.Block,
   162  	fromPos int,
   163  	skippedCnt int) (err error) {
   164  	id := dropped.AsCommonID()
   165  	page := model.NewTransferHashPage(id, time.Now())
   166  	var (
   167  		length uint32
   168  		view   *model.BlockView
   169  	)
   170  	if fromPos-skippedCnt+1 == len(entry.fromAddr) {
   171  		length = uint32(len(entry.mapping)) - entry.fromAddr[fromPos-skippedCnt]
   172  	} else {
   173  		length = entry.fromAddr[fromPos-skippedCnt+1] - entry.fromAddr[fromPos-skippedCnt]
   174  	}
   175  	for i := uint32(0); i < length; i++ {
   176  		if entry.deletes[fromPos] != nil && entry.deletes[fromPos].Contains(i) {
   177  			continue
   178  		}
   179  		newOffset := i
   180  		if entry.deletes[fromPos] != nil {
   181  			newOffset = i - uint32(entry.deletes[fromPos].Rank(i))
   182  		}
   183  		toPos, toRow := entry.resolveAddr(fromPos-skippedCnt, newOffset)
   184  		toId := entry.createdBlks[toPos].AsCommonID()
   185  		prefix := model.EncodeBlockKeyPrefix(toId.SegmentID, toId.BlockID)
   186  		rowid := model.EncodePhyAddrKeyWithPrefix(prefix, uint32(i))
   187  		page.Train(toRow, rowid)
   188  	}
   189  	_ = entry.scheduler.AddTransferPage(page)
   190  
   191  	dataBlock := dropped.GetBlockData()
   192  	if view, err = dataBlock.CollectChangesInRange(
   193  		entry.txn.GetStartTS(),
   194  		entry.txn.GetCommitTS()); err != nil || view == nil {
   195  		return
   196  	}
   197  
   198  	deletes := view.DeleteMask
   199  	for colIdx, column := range view.Columns {
   200  		view.DeleteMask = compute.ShuffleByDeletes(
   201  			deletes, entry.deletes[fromPos])
   202  		for row, v := range column.UpdateVals {
   203  			toPos, toRow := entry.resolveAddr(fromPos-skippedCnt, row)
   204  			if err = blks[toPos].Update(toRow, uint16(colIdx), v); err != nil {
   205  				return
   206  			}
   207  		}
   208  	}
   209  	view.DeleteMask = compute.ShuffleByDeletes(view.DeleteMask, entry.deletes[fromPos])
   210  	if view.DeleteMask != nil {
   211  		it := view.DeleteMask.Iterator()
   212  		for it.HasNext() {
   213  			row := it.Next()
   214  			toPos, toRow := entry.resolveAddr(fromPos-skippedCnt, row)
   215  			if err = blks[toPos].RangeDelete(toRow, toRow, handle.DT_MergeCompact); err != nil {
   216  				return
   217  			}
   218  		}
   219  	}
   220  	return
   221  }
   222  
   223  func (entry *mergeBlocksEntry) PrepareCommit() (err error) {
   224  	blks := make([]handle.Block, len(entry.createdBlks))
   225  	for i, meta := range entry.createdBlks {
   226  		id := meta.AsCommonID()
   227  		seg, err := entry.relation.GetSegment(id.SegmentID)
   228  		if err != nil {
   229  			return err
   230  		}
   231  		blk, err := seg.GetBlock(id.BlockID)
   232  		if err != nil {
   233  			return err
   234  		}
   235  		blks[i] = blk
   236  	}
   237  
   238  	skippedCnt := 0
   239  	ids := make([]*common.ID, 0)
   240  
   241  	for fromPos, dropped := range entry.droppedBlks {
   242  		if entry.isSkipped(fromPos) {
   243  			skippedCnt++
   244  			continue
   245  		}
   246  
   247  		if err = entry.transferBlockDeletes(
   248  			dropped,
   249  			blks,
   250  			fromPos,
   251  			skippedCnt); err != nil {
   252  			break
   253  		}
   254  		ids = append(ids, dropped.AsCommonID())
   255  	}
   256  	if err != nil {
   257  		for _, id := range ids {
   258  			_ = entry.scheduler.DeleteTransferPage(id)
   259  		}
   260  	}
   261  	return
   262  }