github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/db/scannerop.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 db
    16  
    17  import (
    18  	"sync/atomic"
    19  
    20  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    21  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog"
    22  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    23  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/db/merge"
    24  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif"
    25  )
    26  
    27  type ScannerOp interface {
    28  	catalog.Processor
    29  	PreExecute() error
    30  	PostExecute() error
    31  }
    32  
    33  type MergeTaskBuilder struct {
    34  	db *DB
    35  	*catalog.LoopProcessor
    36  	tid  uint64
    37  	name string
    38  	tbl  *catalog.TableEntry
    39  
    40  	objPolicy   merge.Policy
    41  	executor    *merge.MergeExecutor
    42  	tableRowCnt int
    43  	tableRowDel int
    44  
    45  	// concurrecy control
    46  	suspend    atomic.Bool
    47  	suspendCnt atomic.Int32
    48  }
    49  
    50  func newMergeTaskBuilder(db *DB) *MergeTaskBuilder {
    51  	op := &MergeTaskBuilder{
    52  		db:            db,
    53  		LoopProcessor: new(catalog.LoopProcessor),
    54  		objPolicy:     merge.NewBasicPolicy(),
    55  		executor:      merge.NewMergeExecutor(db.Runtime, db.CNMergeSched),
    56  	}
    57  
    58  	op.DatabaseFn = op.onDataBase
    59  	op.TableFn = op.onTable
    60  	op.ObjectFn = op.onObject
    61  	op.PostObjectFn = op.onPostObject
    62  	op.PostTableFn = op.onPostTable
    63  	return op
    64  }
    65  
    66  func (s *MergeTaskBuilder) ConfigPolicy(tbl *catalog.TableEntry, c any) {
    67  	f := func() txnif.AsyncTxn {
    68  		txn, _ := s.db.StartTxn(nil)
    69  		return txn
    70  	}
    71  
    72  	s.objPolicy.SetConfig(tbl, f, c)
    73  }
    74  
    75  func (s *MergeTaskBuilder) GetPolicy(tbl *catalog.TableEntry) any {
    76  	return s.objPolicy.GetConfig(tbl)
    77  }
    78  
    79  func (s *MergeTaskBuilder) trySchedMergeTask() {
    80  	if s.tid == 0 {
    81  		return
    82  	}
    83  	// delObjs := s.ObjectHelper.finish()
    84  	s.executor.ExecuteFor(s.tbl, s.objPolicy)
    85  }
    86  
    87  func (s *MergeTaskBuilder) resetForTable(entry *catalog.TableEntry) {
    88  	s.tid = 0
    89  	if entry != nil {
    90  		s.tid = entry.ID
    91  		s.tbl = entry
    92  		s.name = entry.GetLastestSchemaLocked().Name
    93  		s.tableRowCnt = 0
    94  		s.tableRowDel = 0
    95  	}
    96  	s.objPolicy.ResetForTable(entry)
    97  }
    98  
    99  func (s *MergeTaskBuilder) PreExecute() error {
   100  	s.executor.RefreshMemInfo()
   101  	return nil
   102  }
   103  
   104  func (s *MergeTaskBuilder) PostExecute() error {
   105  	s.executor.PrintStats()
   106  	return nil
   107  }
   108  func (s *MergeTaskBuilder) onDataBase(dbEntry *catalog.DBEntry) (err error) {
   109  	if s.suspend.Load() {
   110  		s.suspendCnt.Add(1)
   111  		return moerr.GetOkStopCurrRecur()
   112  	}
   113  	s.suspendCnt.Store(0)
   114  	if merge.StopMerge.Load() {
   115  		return moerr.GetOkStopCurrRecur()
   116  	}
   117  	if s.executor.MemAvailBytes() < 100*common.Const1MBytes {
   118  		return moerr.GetOkStopCurrRecur()
   119  	}
   120  	return
   121  }
   122  
   123  func (s *MergeTaskBuilder) onTable(tableEntry *catalog.TableEntry) (err error) {
   124  	if merge.StopMerge.Load() || s.suspend.Load() {
   125  		return moerr.GetOkStopCurrRecur()
   126  	}
   127  	if !tableEntry.IsActive() {
   128  		return moerr.GetOkStopCurrRecur()
   129  	}
   130  	tableEntry.RLock()
   131  	// this table is creating or altering
   132  	if !tableEntry.IsCommittedLocked() {
   133  		tableEntry.RUnlock()
   134  		return moerr.GetOkStopCurrRecur()
   135  	}
   136  	tableEntry.RUnlock()
   137  	s.resetForTable(tableEntry)
   138  	return
   139  }
   140  
   141  func (s *MergeTaskBuilder) onPostTable(tableEntry *catalog.TableEntry) (err error) {
   142  	// base on the info of tableEntry, we can decide whether to merge or not
   143  	tableEntry.Stats.AddRowStat(s.tableRowCnt, s.tableRowDel)
   144  	s.trySchedMergeTask()
   145  	return
   146  }
   147  
   148  func (s *MergeTaskBuilder) onObject(objectEntry *catalog.ObjectEntry) (err error) {
   149  	if !objectEntry.IsActive() {
   150  		return moerr.GetOkStopCurrRecur()
   151  	}
   152  
   153  	objectEntry.RLock()
   154  	defer objectEntry.RUnlock()
   155  
   156  	// Skip uncommitted entries
   157  	// TODO: consider the case: add metaloc, is it possible to see a constructing object?
   158  	if !objectEntry.IsCommittedLocked() || !catalog.ActiveObjectWithNoTxnFilter(objectEntry.BaseEntryImpl) {
   159  		return moerr.GetOkStopCurrRecur()
   160  	}
   161  
   162  	if objectEntry.IsAppendable() {
   163  		return moerr.GetOkStopCurrRecur()
   164  	}
   165  
   166  	objectEntry.RUnlock()
   167  	// Rows will check objectStat, and if not loaded, it will load it.
   168  	rows, err := objectEntry.GetObjectData().Rows()
   169  	if err != nil {
   170  		return
   171  	}
   172  
   173  	dels := objectEntry.GetObjectData().GetTotalChanges()
   174  
   175  	// these operations do not require object lock
   176  	objectEntry.SetRemainingRows(rows - dels)
   177  	s.tableRowCnt += rows
   178  	s.tableRowDel += dels
   179  	s.objPolicy.OnObject(objectEntry)
   180  	objectEntry.RLock()
   181  	return
   182  }
   183  
   184  func (s *MergeTaskBuilder) onPostObject(obj *catalog.ObjectEntry) (err error) {
   185  	return nil
   186  }