github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/tables/jobs/compactblk.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 jobs
    16  
    17  import (
    18  	"fmt"
    19  	"time"
    20  
    21  	"github.com/matrixorigin/matrixone/pkg/container/types"
    22  
    23  	"github.com/RoaringBitmap/roaring"
    24  	"github.com/matrixorigin/matrixone/pkg/logutil"
    25  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog"
    26  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    27  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers"
    28  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/dataio/blockio"
    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/mergesort"
    32  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/model"
    33  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables/txnentries"
    34  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tasks"
    35  )
    36  
    37  var CompactBlockTaskFactory = func(meta *catalog.BlockEntry, scheduler tasks.TaskScheduler) tasks.TxnTaskFactory {
    38  	return func(ctx *tasks.Context, txn txnif.AsyncTxn) (tasks.Task, error) {
    39  		return NewCompactBlockTask(ctx, txn, meta, scheduler)
    40  	}
    41  }
    42  
    43  type compactBlockTask struct {
    44  	*tasks.BaseTask
    45  	txn       txnif.AsyncTxn
    46  	compacted handle.Block
    47  	created   handle.Block
    48  	meta      *catalog.BlockEntry
    49  	scheduler tasks.TaskScheduler
    50  	scopes    []common.ID
    51  	mapping   []uint32
    52  	deletes   *roaring.Bitmap
    53  }
    54  
    55  func NewCompactBlockTask(
    56  	ctx *tasks.Context,
    57  	txn txnif.AsyncTxn,
    58  	meta *catalog.BlockEntry,
    59  	scheduler tasks.TaskScheduler) (task *compactBlockTask, err error) {
    60  	task = &compactBlockTask{
    61  		txn:       txn,
    62  		meta:      meta,
    63  		scheduler: scheduler,
    64  	}
    65  	dbId := meta.GetSegment().GetTable().GetDB().GetID()
    66  	database, err := txn.UnsafeGetDatabase(dbId)
    67  	if err != nil {
    68  		return
    69  	}
    70  	tableId := meta.GetSegment().GetTable().GetID()
    71  	rel, err := database.UnsafeGetRelation(tableId)
    72  	if err != nil {
    73  		return
    74  	}
    75  	seg, err := rel.GetSegment(meta.GetSegment().GetID())
    76  	if err != nil {
    77  		return
    78  	}
    79  	task.compacted, err = seg.GetBlock(meta.GetID())
    80  	if err != nil {
    81  		return
    82  	}
    83  	task.scopes = append(task.scopes, *task.compacted.Fingerprint())
    84  	task.BaseTask = tasks.NewBaseTask(task, tasks.DataCompactionTask, ctx)
    85  	return
    86  }
    87  
    88  func (task *compactBlockTask) Scopes() []common.ID { return task.scopes }
    89  
    90  func (task *compactBlockTask) PrepareData() (preparer *model.PreparedCompactedBlockData, empty bool, err error) {
    91  	preparer = model.NewPreparedCompactedBlockData()
    92  	preparer.Columns = containers.NewBatch()
    93  
    94  	schema := task.meta.GetSchema()
    95  	var view *model.ColumnView
    96  	for _, def := range schema.ColDefs {
    97  		if def.IsPhyAddr() {
    98  			continue
    99  		}
   100  		view, err = task.compacted.GetColumnDataById(def.Idx, nil)
   101  		if err != nil {
   102  			return
   103  		}
   104  		task.deletes = view.DeleteMask
   105  		view.ApplyDeletes()
   106  		vec := view.Orphan()
   107  		if vec.Length() == 0 {
   108  			empty = true
   109  			vec.Close()
   110  			return
   111  		}
   112  		preparer.Columns.AddVector(def.Name, vec)
   113  	}
   114  	// Sort only if sort key is defined
   115  	if schema.HasSortKey() {
   116  		idx := schema.GetSingleSortKeyIdx()
   117  		preparer.SortKey = preparer.Columns.Vecs[idx]
   118  		if task.mapping, err = mergesort.SortBlockColumns(preparer.Columns.Vecs, idx); err != nil {
   119  			return preparer, false, err
   120  		}
   121  	}
   122  	return
   123  }
   124  
   125  func (task *compactBlockTask) GetNewBlock() handle.Block { return task.created }
   126  func (task *compactBlockTask) Name() string {
   127  	return fmt.Sprintf("[%d]compact", task.ID())
   128  }
   129  
   130  func (task *compactBlockTask) Execute() (err error) {
   131  	logutil.Info("[Start]", common.OperationField(task.Name()),
   132  		common.OperandField(task.meta.Repr()))
   133  	now := time.Now()
   134  	seg := task.compacted.GetSegment()
   135  	// Prepare a block placeholder
   136  	oldBMeta := task.compacted.GetMeta().(*catalog.BlockEntry)
   137  	// data, sortCol, closer, err := task.PrepareData(newMeta.MakeKey())
   138  	preparer, empty, err := task.PrepareData()
   139  	if err != nil {
   140  		return
   141  	}
   142  	defer preparer.Close()
   143  	if err = seg.SoftDeleteBlock(task.compacted.Fingerprint().BlockID); err != nil {
   144  		return err
   145  	}
   146  	oldBlkData := oldBMeta.GetBlockData()
   147  	var deletes *containers.Batch
   148  	if !oldBMeta.IsAppendable() {
   149  		deletes, err = oldBlkData.CollectDeleteInRange(types.TS{}, task.txn.GetStartTS(), true)
   150  		if err != nil {
   151  			return
   152  		}
   153  		if deletes != nil {
   154  			defer deletes.Close()
   155  		}
   156  	}
   157  
   158  	if !empty {
   159  		task.createAndFlushNewBlock(seg, preparer, deletes)
   160  	}
   161  
   162  	table := task.meta.GetSegment().GetTable()
   163  	// write ablock
   164  	if oldBMeta.IsAppendable() {
   165  		var data *containers.Batch
   166  		data, err = oldBlkData.CollectAppendInRange(types.TS{}, task.txn.GetStartTS(), true)
   167  		if err != nil {
   168  			return
   169  		}
   170  		defer data.Close()
   171  		deletes, err = oldBlkData.CollectDeleteInRange(types.TS{}, task.txn.GetStartTS(), true)
   172  		if err != nil {
   173  			return
   174  		}
   175  		if deletes != nil {
   176  			defer deletes.Close()
   177  		}
   178  		ablockTask := NewFlushBlkTask(
   179  			tasks.WaitableCtx,
   180  			oldBlkData.GetFs(),
   181  			task.txn.GetStartTS(),
   182  			oldBMeta,
   183  			data,
   184  			deletes,
   185  		)
   186  		if err = task.scheduler.Schedule(ablockTask); err != nil {
   187  			return
   188  		}
   189  		if err = ablockTask.WaitDone(); err != nil {
   190  			return
   191  		}
   192  		var metaLocABlk string
   193  		metaLocABlk, err = blockio.EncodeMetaLocWithObject(
   194  			ablockTask.blocks[0].GetExtent(),
   195  			uint32(data.Length()),
   196  			ablockTask.blocks)
   197  		if err != nil {
   198  			return
   199  		}
   200  		if err = task.compacted.UpdateMetaLoc(metaLocABlk); err != nil {
   201  			return err
   202  		}
   203  		if deletes != nil {
   204  			var deltaLoc string
   205  			deltaLoc, err = blockio.EncodeMetaLocWithObject(
   206  				ablockTask.blocks[1].GetExtent(),
   207  				uint32(deletes.Length()),
   208  				ablockTask.blocks)
   209  			if err != nil {
   210  				return
   211  			}
   212  			if err = task.compacted.UpdateDeltaLoc(deltaLoc); err != nil {
   213  				return err
   214  			}
   215  		}
   216  		// if err = oldBlkData.ReplayIndex(); err != nil {
   217  		// 	return err
   218  		// }
   219  	}
   220  	if !table.GetSchema().HasSortKey() && task.created != nil {
   221  		n := task.created.Rows()
   222  		task.mapping = make([]uint32, n)
   223  		for i := 0; i < n; i++ {
   224  			task.mapping[i] = uint32(i)
   225  		}
   226  	}
   227  	txnEntry := txnentries.NewCompactBlockEntry(
   228  		task.txn,
   229  		task.compacted,
   230  		task.created,
   231  		task.scheduler,
   232  		task.mapping,
   233  		task.deletes)
   234  
   235  	if err = task.txn.LogTxnEntry(
   236  		table.GetDB().ID,
   237  		table.ID,
   238  		txnEntry,
   239  		[]*common.ID{task.compacted.Fingerprint()}); err != nil {
   240  		return
   241  	}
   242  	createdStr := "nil"
   243  	if task.created != nil {
   244  		createdStr = task.created.Fingerprint().BlockString()
   245  	}
   246  	logutil.Info("[Done]",
   247  		common.AnyField("txn-start-ts", task.txn.GetStartTS().ToString()),
   248  		common.OperationField(task.Name()),
   249  		common.AnyField("compacted", task.meta.Repr()),
   250  		common.AnyField("created", createdStr),
   251  		common.DurationField(time.Since(now)))
   252  	return
   253  }
   254  
   255  func (task *compactBlockTask) createAndFlushNewBlock(
   256  	seg handle.Segment,
   257  	preparer *model.PreparedCompactedBlockData,
   258  	deletes *containers.Batch,
   259  ) (newBlk handle.Block, err error) {
   260  	newBlk, err = seg.CreateNonAppendableBlock()
   261  	if err != nil {
   262  		return
   263  	}
   264  	task.created = newBlk
   265  	newMeta := newBlk.GetMeta().(*catalog.BlockEntry)
   266  	newBlkData := newMeta.GetBlockData()
   267  	ioTask := NewFlushBlkTask(
   268  		tasks.WaitableCtx,
   269  		newBlkData.GetFs(),
   270  		task.txn.GetStartTS(),
   271  		newMeta,
   272  		preparer.Columns,
   273  		deletes)
   274  	if err = task.scheduler.Schedule(ioTask); err != nil {
   275  		return
   276  	}
   277  	if err = ioTask.WaitDone(); err != nil {
   278  		return
   279  	}
   280  	metaLoc, err := blockio.EncodeMetaLocWithObject(
   281  		ioTask.blocks[0].GetExtent(),
   282  		uint32(preparer.Columns.Length()),
   283  		ioTask.blocks)
   284  	if err != nil {
   285  		return
   286  	}
   287  	if err = newBlk.UpdateMetaLoc(metaLoc); err != nil {
   288  		return
   289  	}
   290  	if deletes != nil {
   291  		var deltaLoc string
   292  		deltaLoc, err = blockio.EncodeMetaLocWithObject(
   293  			ioTask.blocks[1].GetExtent(),
   294  			uint32(deletes.Length()),
   295  			ioTask.blocks)
   296  		if err != nil {
   297  			return
   298  		}
   299  		if err = task.compacted.UpdateDeltaLoc(deltaLoc); err != nil {
   300  			return
   301  		}
   302  	}
   303  	if err = newBlkData.Init(); err != nil {
   304  		return
   305  	}
   306  	return
   307  }