github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/tables/aobj.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 tables
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"sync"
    21  	"sync/atomic"
    22  
    23  	"github.com/RoaringBitmap/roaring"
    24  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    25  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    26  	"github.com/matrixorigin/matrixone/pkg/container/types"
    27  	"github.com/matrixorigin/matrixone/pkg/logutil"
    28  	"github.com/matrixorigin/matrixone/pkg/objectio"
    29  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog"
    30  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    31  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers"
    32  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/db/dbutils"
    33  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/data"
    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/index"
    37  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tables/updates"
    38  )
    39  
    40  type aobject struct {
    41  	*baseObject
    42  	frozen     atomic.Bool
    43  	freezelock sync.Mutex
    44  }
    45  
    46  func newAObject(
    47  	meta *catalog.ObjectEntry,
    48  	rt *dbutils.Runtime,
    49  ) *aobject {
    50  	obj := &aobject{}
    51  	obj.baseObject = newBaseObject(obj, meta, rt)
    52  	if obj.meta.HasDropCommitted() {
    53  		pnode := newPersistedNode(obj.baseObject)
    54  		node := NewNode(pnode)
    55  		node.Ref()
    56  		obj.node.Store(node)
    57  		obj.FreezeAppend()
    58  	} else {
    59  		mnode := newMemoryNode(obj.baseObject)
    60  		node := NewNode(mnode)
    61  		node.Ref()
    62  		obj.node.Store(node)
    63  	}
    64  	return obj
    65  }
    66  
    67  func (obj *aobject) FreezeAppend() {
    68  	obj.frozen.Store(true)
    69  }
    70  
    71  func (obj *aobject) IsAppendFrozen() bool {
    72  	return obj.frozen.Load()
    73  }
    74  
    75  func (obj *aobject) IsAppendable() bool {
    76  	if obj.IsAppendFrozen() {
    77  		return false
    78  	}
    79  	node := obj.PinNode()
    80  	defer node.Unref()
    81  	if node.IsPersisted() {
    82  		return false
    83  	}
    84  	rows, _ := node.Rows()
    85  	return rows < obj.meta.GetSchema().BlockMaxRows
    86  }
    87  
    88  func (obj *aobject) PrepareCompactInfo() (result bool, reason string) {
    89  	if n := obj.RefCount(); n > 0 {
    90  		reason = fmt.Sprintf("entering refcount %d", n)
    91  		return
    92  	}
    93  	obj.FreezeAppend()
    94  	if !obj.meta.PrepareCompact() || !obj.appendMVCC.PrepareCompact() {
    95  		if !obj.meta.PrepareCompact() {
    96  			reason = "meta preparecomp false"
    97  		} else {
    98  			reason = "mvcc preparecomp false"
    99  		}
   100  		return
   101  	}
   102  
   103  	if n := obj.RefCount(); n != 0 {
   104  		reason = fmt.Sprintf("ending refcount %d", n)
   105  		return
   106  	}
   107  	return obj.RefCount() == 0, reason
   108  }
   109  
   110  func (obj *aobject) PrepareCompact() bool {
   111  	if obj.RefCount() > 0 {
   112  		return false
   113  	}
   114  
   115  	// see more notes in flushtabletail.go
   116  	obj.freezelock.Lock()
   117  	obj.FreezeAppend()
   118  	obj.freezelock.Unlock()
   119  
   120  	obj.meta.RLock()
   121  	defer obj.meta.RUnlock()
   122  	droppedCommitted := obj.meta.HasDropCommittedLocked()
   123  
   124  	if droppedCommitted {
   125  		if !obj.meta.PrepareCompactLocked() {
   126  			return false
   127  		}
   128  	} else {
   129  		if !obj.meta.PrepareCompactLocked() ||
   130  			!obj.appendMVCC.PrepareCompactLocked() /* all appends are committed */ {
   131  			return false
   132  		}
   133  	}
   134  	return obj.RefCount() == 0
   135  }
   136  
   137  func (obj *aobject) Pin() *common.PinnedItem[*aobject] {
   138  	obj.Ref()
   139  	return &common.PinnedItem[*aobject]{
   140  		Val: obj,
   141  	}
   142  }
   143  
   144  func (obj *aobject) GetColumnDataByIds(
   145  	ctx context.Context,
   146  	txn txnif.AsyncTxn,
   147  	readSchema any,
   148  	_ uint16,
   149  	colIdxes []int,
   150  	mp *mpool.MPool,
   151  ) (view *containers.BlockView, err error) {
   152  	return obj.resolveColumnDatas(
   153  		ctx,
   154  		txn,
   155  		readSchema.(*catalog.Schema),
   156  		colIdxes,
   157  		false,
   158  		mp,
   159  	)
   160  }
   161  
   162  func (obj *aobject) GetColumnDataById(
   163  	ctx context.Context,
   164  	txn txnif.AsyncTxn,
   165  	readSchema any,
   166  	_ uint16,
   167  	col int,
   168  	mp *mpool.MPool,
   169  ) (view *containers.ColumnView, err error) {
   170  	return obj.resolveColumnData(
   171  		ctx,
   172  		txn,
   173  		readSchema.(*catalog.Schema),
   174  		col,
   175  		false,
   176  		mp,
   177  	)
   178  }
   179  
   180  func (obj *aobject) resolveColumnDatas(
   181  	ctx context.Context,
   182  	txn txnif.TxnReader,
   183  	readSchema *catalog.Schema,
   184  	colIdxes []int,
   185  	skipDeletes bool,
   186  	mp *mpool.MPool,
   187  ) (view *containers.BlockView, err error) {
   188  	node := obj.PinNode()
   189  	defer node.Unref()
   190  
   191  	if !node.IsPersisted() {
   192  		return node.MustMNode().resolveInMemoryColumnDatas(
   193  			ctx,
   194  			txn, readSchema, colIdxes, skipDeletes, mp,
   195  		)
   196  	} else {
   197  		return obj.ResolvePersistedColumnDatas(
   198  			ctx,
   199  			txn,
   200  			readSchema,
   201  			0,
   202  			colIdxes,
   203  			skipDeletes,
   204  			mp,
   205  		)
   206  	}
   207  }
   208  
   209  // check if all rows are committed before the specified ts
   210  // here we assume that the ts is greater equal than the block's
   211  // create ts and less than the block's delete ts
   212  // it is a coarse-grained check
   213  func (obj *aobject) CoarseCheckAllRowsCommittedBefore(ts types.TS) bool {
   214  	// if the block is not frozen, always return false
   215  	if !obj.IsAppendFrozen() {
   216  		return false
   217  	}
   218  
   219  	node := obj.PinNode()
   220  	defer node.Unref()
   221  
   222  	// if the block is in memory, check with the in-memory node
   223  	// it is a fine-grained check if the block is in memory
   224  	if !node.IsPersisted() {
   225  		return node.MustMNode().allRowsCommittedBefore(ts)
   226  	}
   227  
   228  	// always return false for if the block is persisted
   229  	// it is a coarse-grained check
   230  	return false
   231  }
   232  
   233  func (obj *aobject) resolveColumnData(
   234  	ctx context.Context,
   235  	txn txnif.TxnReader,
   236  	readSchema *catalog.Schema,
   237  	col int,
   238  	skipDeletes bool,
   239  	mp *mpool.MPool,
   240  ) (view *containers.ColumnView, err error) {
   241  	node := obj.PinNode()
   242  	defer node.Unref()
   243  
   244  	if !node.IsPersisted() {
   245  		return node.MustMNode().resolveInMemoryColumnData(
   246  			txn, readSchema, col, skipDeletes, mp,
   247  		)
   248  	} else {
   249  		return obj.ResolvePersistedColumnData(
   250  			ctx,
   251  			txn,
   252  			readSchema,
   253  			0,
   254  			col,
   255  			skipDeletes,
   256  			mp,
   257  		)
   258  	}
   259  }
   260  
   261  func (obj *aobject) GetValue(
   262  	ctx context.Context,
   263  	txn txnif.AsyncTxn,
   264  	readSchema any,
   265  	_ uint16,
   266  	row, col int,
   267  	mp *mpool.MPool,
   268  ) (v any, isNull bool, err error) {
   269  	node := obj.PinNode()
   270  	defer node.Unref()
   271  	schema := readSchema.(*catalog.Schema)
   272  	if !node.IsPersisted() {
   273  		return node.MustMNode().getInMemoryValue(txn, schema, row, col, mp)
   274  	} else {
   275  		return obj.getPersistedValue(
   276  			ctx, txn, schema, 0, row, col, true, mp,
   277  		)
   278  	}
   279  }
   280  
   281  // GetByFilter will read pk column, which seqnum will not change, no need to pass the read schema.
   282  func (obj *aobject) GetByFilter(
   283  	ctx context.Context,
   284  	txn txnif.AsyncTxn,
   285  	filter *handle.Filter,
   286  	mp *mpool.MPool,
   287  ) (blkID uint16, offset uint32, err error) {
   288  	if filter.Op != handle.FilterEq {
   289  		panic("logic error")
   290  	}
   291  	if obj.meta.GetSchema().SortKey == nil {
   292  		rid := filter.Val.(types.Rowid)
   293  		offset = rid.GetRowOffset()
   294  		return
   295  	}
   296  
   297  	node := obj.PinNode()
   298  	defer node.Unref()
   299  	_, offset, err = node.GetRowByFilter(ctx, txn, filter, mp)
   300  	return
   301  }
   302  
   303  func (obj *aobject) BatchDedup(
   304  	ctx context.Context,
   305  	txn txnif.AsyncTxn,
   306  	keys containers.Vector,
   307  	keysZM index.ZM,
   308  	rowmask *roaring.Bitmap,
   309  	precommit bool,
   310  	bf objectio.BloomFilter,
   311  	mp *mpool.MPool,
   312  ) (err error) {
   313  	defer func() {
   314  		if moerr.IsMoErrCode(err, moerr.ErrDuplicateEntry) {
   315  			logutil.Debugf("BatchDedup obj-%s: %v", obj.meta.ID.String(), err)
   316  		}
   317  	}()
   318  	node := obj.PinNode()
   319  	defer node.Unref()
   320  	if !node.IsPersisted() {
   321  		return node.BatchDedup(
   322  			ctx,
   323  			txn,
   324  			precommit,
   325  			keys,
   326  			keysZM,
   327  			rowmask,
   328  			bf,
   329  		)
   330  	} else {
   331  		return obj.PersistedBatchDedup(
   332  			ctx,
   333  			txn,
   334  			precommit,
   335  			keys,
   336  			keysZM,
   337  			rowmask,
   338  			true,
   339  			bf,
   340  			mp,
   341  		)
   342  	}
   343  }
   344  
   345  func (obj *aobject) CollectAppendInRange(
   346  	start, end types.TS,
   347  	withAborted bool,
   348  	mp *mpool.MPool,
   349  ) (*containers.BatchWithVersion, error) {
   350  	node := obj.PinNode()
   351  	defer node.Unref()
   352  	return node.CollectAppendInRange(start, end, withAborted, mp)
   353  }
   354  
   355  func (obj *aobject) estimateRawScore() (score int, dropped bool, err error) {
   356  	if obj.meta.HasDropCommitted() && !obj.meta.InMemoryDeletesExisted() {
   357  		dropped = true
   358  		return
   359  	}
   360  	obj.meta.RLock()
   361  	atLeastOneCommitted := obj.meta.HasCommittedNodeLocked()
   362  	obj.meta.RUnlock()
   363  	if !atLeastOneCommitted {
   364  		score = 1
   365  		return
   366  	}
   367  
   368  	rows, err := obj.Rows()
   369  	if rows == int(obj.meta.GetSchema().BlockMaxRows) {
   370  		score = 100
   371  		return
   372  	}
   373  
   374  	changesCnt := uint32(0)
   375  	obj.meta.RLock()
   376  	objectMVCC := obj.tryGetMVCC()
   377  	if objectMVCC != nil {
   378  		changesCnt = objectMVCC.GetChangeIntentionCntLocked()
   379  	}
   380  	obj.meta.RUnlock()
   381  	if changesCnt == 0 && rows == 0 {
   382  		score = 0
   383  	} else {
   384  		score = 1
   385  	}
   386  
   387  	if score > 0 {
   388  		if _, terminated := obj.meta.GetTerminationTS(); terminated {
   389  			score = 100
   390  		}
   391  	}
   392  	return
   393  }
   394  
   395  func (obj *aobject) RunCalibration() (score int, err error) {
   396  	score, _, err = obj.estimateRawScore()
   397  	return
   398  }
   399  
   400  func (obj *aobject) OnReplayAppend(node txnif.AppendNode) (err error) {
   401  	an := node.(*updates.AppendNode)
   402  	obj.appendMVCC.OnReplayAppendNode(an)
   403  	return
   404  }
   405  
   406  func (obj *aobject) OnReplayAppendPayload(bat *containers.Batch) (err error) {
   407  	appender, err := obj.MakeAppender()
   408  	if err != nil {
   409  		return
   410  	}
   411  	_, err = appender.ReplayAppend(bat, nil)
   412  	return
   413  }
   414  
   415  func (obj *aobject) MakeAppender() (appender data.ObjectAppender, err error) {
   416  	if obj == nil {
   417  		err = moerr.GetOkExpectedEOB()
   418  		return
   419  	}
   420  	appender = newAppender(obj)
   421  	return
   422  }
   423  
   424  func (obj *aobject) Init() (err error) { return }
   425  
   426  func (obj *aobject) EstimateMemSize() (int, int) {
   427  	node := obj.PinNode()
   428  	defer node.Unref()
   429  	obj.RLock()
   430  	defer obj.RUnlock()
   431  	dsize := 0
   432  	objMVCC := obj.tryGetMVCC()
   433  	if objMVCC != nil {
   434  		dsize = objMVCC.EstimateMemSizeLocked()
   435  	}
   436  	asize := obj.appendMVCC.EstimateMemSizeLocked()
   437  	if !node.IsPersisted() {
   438  		asize += node.MustMNode().EstimateMemSize()
   439  	}
   440  	return asize, dsize
   441  }
   442  
   443  func (obj *aobject) GetRowsOnReplay() uint64 {
   444  	rows := uint64(obj.appendMVCC.GetTotalRow())
   445  	fileRows := uint64(obj.meta.GetLatestCommittedNodeLocked().
   446  		BaseNode.ObjectStats.Rows())
   447  	if rows > fileRows {
   448  		return rows
   449  	}
   450  	return fileRows
   451  }