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 }