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 }