github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/tae/catalog/table.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 catalog 16 17 import ( 18 "bytes" 19 "context" 20 "fmt" 21 "math" 22 "strings" 23 "sync/atomic" 24 25 pkgcatalog "github.com/matrixorigin/matrixone/pkg/catalog" 26 "github.com/matrixorigin/matrixone/pkg/common/moerr" 27 "github.com/matrixorigin/matrixone/pkg/container/types" 28 "github.com/matrixorigin/matrixone/pkg/logutil" 29 "github.com/matrixorigin/matrixone/pkg/objectio" 30 apipb "github.com/matrixorigin/matrixone/pkg/pb/api" 31 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 32 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/data" 33 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 34 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/txn/txnbase" 35 "github.com/tidwall/btree" 36 ) 37 38 type TableDataFactory = func(meta *TableEntry) data.Table 39 40 func tableVisibilityFn[T *TableEntry](n *common.GenericDLNode[*TableEntry], txn txnif.TxnReader) (visible, dropped bool, name string) { 41 table := n.GetPayload() 42 visible, dropped, name = table.GetVisibilityAndName(txn) 43 return 44 } 45 46 type TableEntry struct { 47 *BaseEntryImpl[*TableMVCCNode] 48 *TableNode 49 Stats *common.TableCompactStat 50 ID uint64 51 db *DBEntry 52 entries map[types.Objectid]*common.GenericDLNode[*ObjectEntry] 53 //link.head and link.tail is nil when create tableEntry object. 54 link *common.GenericSortedDList[*ObjectEntry] 55 tableData data.Table 56 rows atomic.Uint64 57 // used for the next flush table tail. 58 DeletedDirties []*ObjectEntry 59 // fullname is format as 'tenantID-tableName', the tenantID prefix is only used 'mo_catalog' database 60 fullName string 61 62 deleteList *btree.BTreeG[DeleteEntry] 63 } 64 65 type DeleteEntry struct { 66 ObjectID objectio.ObjectId 67 data.Tombstone 68 } 69 70 func (d DeleteEntry) Less(o DeleteEntry) bool { 71 return bytes.Compare(d.ObjectID[:], o.ObjectID[:]) < 0 72 } 73 74 func genTblFullName(tenantID uint32, name string) string { 75 if name == pkgcatalog.MO_DATABASE || name == pkgcatalog.MO_TABLES || name == pkgcatalog.MO_COLUMNS { 76 tenantID = 0 77 } 78 return fmt.Sprintf("%d-%s", tenantID, name) 79 } 80 81 func NewTableEntry(db *DBEntry, schema *Schema, txnCtx txnif.AsyncTxn, dataFactory TableDataFactory) *TableEntry { 82 id := db.catalog.NextTable() 83 return NewTableEntryWithTableId(db, schema, txnCtx, dataFactory, id) 84 } 85 86 func NewTableEntryWithTableId(db *DBEntry, schema *Schema, txnCtx txnif.AsyncTxn, dataFactory TableDataFactory, tableId uint64) *TableEntry { 87 if txnCtx != nil { 88 // Only in unit test, txnCtx can be nil 89 schema.AcInfo.TenantID = txnCtx.GetTenantID() 90 schema.AcInfo.UserID, schema.AcInfo.RoleID = txnCtx.GetUserAndRoleID() 91 } 92 schema.AcInfo.CreateAt = types.CurrentTimestamp() 93 opts := btree.Options{ 94 Degree: 4, 95 } 96 e := &TableEntry{ 97 ID: tableId, 98 BaseEntryImpl: NewBaseEntry( 99 func() *TableMVCCNode { return &TableMVCCNode{} }), 100 db: db, 101 TableNode: &TableNode{}, 102 link: common.NewGenericSortedDList((*ObjectEntry).Less), 103 entries: make(map[types.Objectid]*common.GenericDLNode[*ObjectEntry]), 104 deleteList: btree.NewBTreeGOptions(DeleteEntry.Less, opts), 105 Stats: common.NewTableCompactStat(), 106 } 107 e.TableNode.schema.Store(schema) 108 if dataFactory != nil { 109 e.tableData = dataFactory(e) 110 } 111 e.CreateWithTxnAndSchema(txnCtx, schema) 112 return e 113 } 114 115 func NewSystemTableEntry(db *DBEntry, id uint64, schema *Schema) *TableEntry { 116 opts := btree.Options{ 117 Degree: 4, 118 } 119 e := &TableEntry{ 120 ID: id, 121 BaseEntryImpl: NewBaseEntry( 122 func() *TableMVCCNode { return &TableMVCCNode{} }), 123 db: db, 124 TableNode: &TableNode{}, 125 link: common.NewGenericSortedDList((*ObjectEntry).Less), 126 entries: make(map[types.Objectid]*common.GenericDLNode[*ObjectEntry]), 127 deleteList: btree.NewBTreeGOptions(DeleteEntry.Less, opts), 128 Stats: common.NewTableCompactStat(), 129 } 130 e.TableNode.schema.Store(schema) 131 e.CreateWithTS(types.SystemDBTS, &TableMVCCNode{Schema: schema}) 132 var sid types.Uuid 133 if schema.Name == SystemTableSchema.Name { 134 sid = SystemObject_Table_ID 135 } else if schema.Name == SystemDBSchema.Name { 136 sid = SystemObject_DB_ID 137 } else if schema.Name == SystemColumnSchema.Name { 138 sid = SystemObject_Columns_ID 139 } else { 140 panic("not supported") 141 } 142 objectEntry := NewSysObjectEntry(e, sid) 143 e.AddEntryLocked(objectEntry) 144 return e 145 } 146 147 func NewReplayTableEntry() *TableEntry { 148 opts := btree.Options{ 149 Degree: 4, 150 } 151 e := &TableEntry{ 152 BaseEntryImpl: NewReplayBaseEntry( 153 func() *TableMVCCNode { return &TableMVCCNode{} }), 154 link: common.NewGenericSortedDList((*ObjectEntry).Less), 155 entries: make(map[types.Objectid]*common.GenericDLNode[*ObjectEntry]), 156 deleteList: btree.NewBTreeGOptions(DeleteEntry.Less, opts), 157 Stats: common.NewTableCompactStat(), 158 } 159 return e 160 } 161 162 func MockStaloneTableEntry(id uint64, schema *Schema) *TableEntry { 163 node := &TableNode{} 164 node.schema.Store(schema) 165 opts := btree.Options{ 166 Degree: 4, 167 } 168 return &TableEntry{ 169 ID: id, 170 BaseEntryImpl: NewBaseEntry( 171 func() *TableMVCCNode { return &TableMVCCNode{} }), 172 TableNode: node, 173 link: common.NewGenericSortedDList((*ObjectEntry).Less), 174 entries: make(map[types.Objectid]*common.GenericDLNode[*ObjectEntry]), 175 deleteList: btree.NewBTreeGOptions(DeleteEntry.Less, opts), 176 Stats: common.NewTableCompactStat(), 177 } 178 } 179 func (entry *TableEntry) GCTombstone(id objectio.ObjectId) { 180 pivot := DeleteEntry{ 181 ObjectID: id, 182 } 183 entry.deleteList.Delete(pivot) 184 } 185 func (entry *TableEntry) GetDeleteList() *btree.BTreeG[DeleteEntry] { 186 return entry.deleteList.Copy() 187 } 188 func (entry *TableEntry) TryGetTombstone(oid objectio.ObjectId) data.Tombstone { 189 pivot := DeleteEntry{ObjectID: oid} 190 tombstone, ok := entry.deleteList.Get(pivot) 191 if !ok { 192 return nil 193 } 194 return tombstone.Tombstone 195 } 196 197 func (entry *TableEntry) GetOrCreateTombstone(obj *ObjectEntry, factory TombstoneFactory) data.Tombstone { 198 pivot := DeleteEntry{ObjectID: obj.ID} 199 delete, ok := entry.deleteList.Get(pivot) 200 if ok { 201 return delete.Tombstone 202 } 203 pivot.Tombstone = factory(obj) 204 entry.deleteList.Set(pivot) 205 return pivot.Tombstone 206 } 207 208 func (entry *TableEntry) GetID() uint64 { return entry.ID } 209 func (entry *TableEntry) IsVirtual() bool { 210 if !entry.db.IsSystemDB() { 211 return false 212 } 213 name := entry.GetLastestSchemaLocked().Name 214 return name == pkgcatalog.MO_DATABASE || 215 name == pkgcatalog.MO_TABLES || 216 name == pkgcatalog.MO_COLUMNS 217 } 218 219 func (entry *TableEntry) GetRows() uint64 { 220 return entry.rows.Load() 221 } 222 223 func (entry *TableEntry) AddRows(delta uint64) uint64 { 224 return entry.rows.Add(delta) 225 } 226 227 func (entry *TableEntry) RemoveRows(delta uint64) uint64 { 228 return entry.rows.Add(^(delta - 1)) 229 } 230 231 func (entry *TableEntry) GetObjectByID(id *types.Objectid) (obj *ObjectEntry, err error) { 232 entry.RLock() 233 defer entry.RUnlock() 234 node := entry.entries[*id] 235 if node == nil { 236 return nil, moerr.GetOkExpectedEOB() 237 } 238 return node.GetPayload(), nil 239 } 240 func (entry *TableEntry) GetObjectsByID(id *types.Segmentid) (obj []*ObjectEntry, err error) { 241 entry.RLock() 242 defer entry.RUnlock() 243 for nodeID, node := range entry.entries { 244 if nodeID.Segment().Eq(*id) { 245 if obj == nil { 246 obj = make([]*ObjectEntry, 0) 247 } 248 obj = append(obj, node.GetPayload()) 249 } 250 } 251 if obj == nil { 252 return nil, moerr.GetOkExpectedEOB() 253 } 254 return obj, nil 255 } 256 257 func (entry *TableEntry) MakeObjectIt(reverse bool) *common.GenericSortedDListIt[*ObjectEntry] { 258 entry.RLock() 259 defer entry.RUnlock() 260 return common.NewGenericSortedDListIt(entry.RWMutex, entry.link, reverse) 261 } 262 263 func (entry *TableEntry) CreateObject( 264 txn txnif.AsyncTxn, 265 state EntryState, 266 opts *objectio.CreateObjOpt, 267 dataFactory ObjectDataFactory, 268 ) (created *ObjectEntry, err error) { 269 entry.Lock() 270 defer entry.Unlock() 271 var id *objectio.ObjectId 272 if opts != nil && opts.Id != nil { 273 id = opts.Id 274 } else { 275 id = objectio.NewObjectid() 276 } 277 created = NewObjectEntry(entry, id, txn, state, dataFactory) 278 entry.AddEntryLocked(created) 279 return 280 } 281 282 func (entry *TableEntry) MakeCommand(id uint32) (cmd txnif.TxnCmd, err error) { 283 cmdType := IOET_WALTxnCommand_Table 284 entry.RLock() 285 defer entry.RUnlock() 286 return newTableCmd(id, cmdType, entry), nil 287 } 288 289 func (entry *TableEntry) Set1PC() { 290 entry.GetLatestNodeLocked().Set1PC() 291 } 292 func (entry *TableEntry) Is1PC() bool { 293 return entry.GetLatestNodeLocked().Is1PC() 294 } 295 func (entry *TableEntry) AddEntryLocked(objectEntry *ObjectEntry) { 296 n := entry.link.Insert(objectEntry) 297 entry.entries[objectEntry.ID] = n 298 } 299 300 func (entry *TableEntry) deleteEntryLocked(objectEntry *ObjectEntry) error { 301 if n, ok := entry.entries[objectEntry.ID]; !ok { 302 return moerr.GetOkExpectedEOB() 303 } else { 304 entry.link.Delete(n) 305 delete(entry.entries, objectEntry.ID) 306 } 307 return nil 308 } 309 310 // GetLastestSchemaLocked returns the latest committed schema with entry Not locked 311 func (entry *TableEntry) GetLastestSchemaLocked() *Schema { 312 return entry.schema.Load() 313 } 314 315 // GetLastestSchema returns the latest committed schema with entry locked 316 func (entry *TableEntry) GetLastestSchema() *Schema { 317 entry.Lock() 318 defer entry.Unlock() 319 320 return entry.schema.Load() 321 } 322 323 // GetVisibleSchema returns committed schema visible at the given txn 324 func (entry *TableEntry) GetVisibleSchema(txn txnif.TxnReader) *Schema { 325 entry.RLock() 326 defer entry.RUnlock() 327 node := entry.GetVisibleNodeLocked(txn) 328 if node != nil { 329 return node.BaseNode.Schema 330 } 331 return nil 332 } 333 334 func (entry *TableEntry) GetVersionSchema(ver uint32) *Schema { 335 entry.RLock() 336 defer entry.RUnlock() 337 var ret *Schema 338 entry.LoopChainLocked(func(m *MVCCNode[*TableMVCCNode]) bool { 339 if cur := m.BaseNode.Schema.Version; cur > ver { 340 return true 341 } else if cur == ver { 342 ret = m.BaseNode.Schema 343 } 344 return false 345 }) 346 return ret 347 } 348 349 func (entry *TableEntry) GetColDefs() []*ColDef { 350 return entry.GetLastestSchemaLocked().ColDefs 351 } 352 353 func (entry *TableEntry) GetFullName() string { 354 if len(entry.fullName) == 0 { 355 schema := entry.GetLastestSchemaLocked() 356 entry.fullName = genTblFullName(schema.AcInfo.TenantID, schema.Name) 357 } 358 return entry.fullName 359 } 360 361 func (entry *TableEntry) GetDB() *DBEntry { 362 return entry.db 363 } 364 365 func (entry *TableEntry) PPString(level common.PPLevel, depth int, prefix string) string { 366 var w bytes.Buffer 367 _, _ = w.WriteString(fmt.Sprintf("%s%s%s", common.RepeatStr("\t", depth), prefix, entry.StringWithLevel(level))) 368 if level == common.PPL0 { 369 return w.String() 370 } 371 it := entry.MakeObjectIt(true) 372 for it.Valid() { 373 objectEntry := it.Get().GetPayload() 374 _ = w.WriteByte('\n') 375 _, _ = w.WriteString(objectEntry.PPString(level, depth+1, prefix)) 376 it.Next() 377 } 378 if level > common.PPL2 { 379 _ = w.WriteByte('\n') 380 it2 := entry.deleteList.Copy().Iter() 381 for it2.Next() { 382 w.WriteString(common.RepeatStr("\t", depth+1)) 383 w.WriteString(prefix) 384 objID := it2.Item().ObjectID 385 w.WriteString(fmt.Sprintf("Tombstone[%s]\n", objID.String())) 386 it2.Item().GetObject().(*ObjectEntry).RLock() 387 w.WriteString(it2.Item().StringLocked(level, depth+1, prefix)) 388 it2.Item().GetObject().(*ObjectEntry).RUnlock() 389 } 390 } 391 return w.String() 392 } 393 394 type TableStat struct { 395 ObjectCnt int 396 Loaded int 397 Rows int 398 OSize int 399 Csize int 400 } 401 402 func (entry *TableEntry) ObjectStats(level common.PPLevel, start, end int) (stat TableStat, w bytes.Buffer) { 403 404 it := entry.MakeObjectIt(true) 405 zonemapKind := common.ZonemapPrintKindNormal 406 if schema := entry.GetLastestSchemaLocked(); schema.HasSortKey() && strings.HasPrefix(schema.GetSingleSortKey().Name, "__") { 407 zonemapKind = common.ZonemapPrintKindCompose 408 } 409 410 if level == common.PPL3 { // some magic, do not ask why 411 zonemapKind = common.ZonemapPrintKindHex 412 } 413 414 scanCount := 0 415 needCount := end - start 416 if needCount < 0 { 417 needCount = math.MaxInt 418 } 419 420 for ; it.Valid(); it.Next() { 421 objectEntry := it.Get().GetPayload() 422 if !objectEntry.IsActive() { 423 continue 424 } 425 scanCount++ 426 if scanCount <= start { 427 continue 428 } 429 if needCount <= 0 { 430 break 431 } 432 needCount-- 433 stat.ObjectCnt += 1 434 if objectEntry.GetLoaded() { 435 stat.Loaded += 1 436 stat.Rows += int(objectEntry.GetRows()) 437 stat.OSize += int(objectEntry.GetOriginSize()) 438 stat.Csize += int(objectEntry.GetCompSize()) 439 } 440 if level > common.PPL0 { 441 _ = w.WriteByte('\n') 442 _, _ = w.WriteString(objectEntry.ID.String()) 443 _ = w.WriteByte('\n') 444 _, _ = w.WriteString(" ") 445 _, _ = w.WriteString(objectEntry.StatsString(zonemapKind)) 446 } 447 if w.Len() > 8*common.Const1MBytes { 448 w.WriteString("\n...(truncated for too long, more than 8 MB)") 449 break 450 } 451 } 452 if level > common.PPL0 && stat.ObjectCnt > 0 { 453 w.WriteByte('\n') 454 } 455 return 456 } 457 458 func (entry *TableEntry) ObjectStatsString(level common.PPLevel, start, end int) string { 459 stat, detail := entry.ObjectStats(level, start, end) 460 461 var avgCsize, avgRow, avgOsize int 462 if stat.Loaded > 0 { 463 avgRow = stat.Rows / stat.Loaded 464 avgOsize = stat.OSize / stat.Loaded 465 avgCsize = stat.Csize / stat.Loaded 466 } 467 468 summary := fmt.Sprintf( 469 "summary: %d total, %d unknown, avgRow %d, avgOsize %s, avgCsize %v\n"+ 470 "Update History:\n rows %v\n dels %v ", 471 stat.ObjectCnt, stat.ObjectCnt-stat.Loaded, avgRow, common.HumanReadableBytes(avgOsize), common.HumanReadableBytes(avgCsize), 472 entry.Stats.RowCnt.String(), entry.Stats.RowDel.String(), 473 ) 474 detail.WriteString(summary) 475 return detail.String() 476 } 477 478 func (entry *TableEntry) String() string { 479 entry.RLock() 480 defer entry.RUnlock() 481 return entry.StringLocked() 482 } 483 484 func (entry *TableEntry) StringWithLevel(level common.PPLevel) string { 485 entry.RLock() 486 defer entry.RUnlock() 487 return entry.StringLockedWithLevel(level) 488 } 489 func (entry *TableEntry) StringLockedWithLevel(level common.PPLevel) string { 490 name := entry.GetLastestSchemaLocked().Name 491 if level <= common.PPL1 { 492 return fmt.Sprintf("TBL[%d][name=%s][C@%s,D@%s]", 493 entry.ID, name, entry.GetCreatedAtLocked().ToString(), entry.GetDeleteAtLocked().ToString()) 494 } 495 return fmt.Sprintf("TBL%s[name=%s, id=%d]", entry.BaseEntryImpl.StringLocked(), name, entry.ID) 496 } 497 498 func (entry *TableEntry) StringLocked() string { 499 return entry.StringLockedWithLevel(common.PPL1) 500 } 501 502 func (entry *TableEntry) GetCatalog() *Catalog { return entry.db.catalog } 503 504 func (entry *TableEntry) GetTableData() data.Table { return entry.tableData } 505 506 func (entry *TableEntry) LastAppendableObject() (obj *ObjectEntry) { 507 it := entry.MakeObjectIt(false) 508 for it.Valid() { 509 itObj := it.Get().GetPayload() 510 dropped := itObj.HasDropCommitted() 511 if itObj.IsAppendable() && !dropped { 512 obj = itObj 513 break 514 } 515 it.Next() 516 } 517 return obj 518 } 519 520 func (entry *TableEntry) AsCommonID() *common.ID { 521 return &common.ID{ 522 DbID: entry.GetDB().ID, 523 TableID: entry.ID, 524 } 525 } 526 527 func (entry *TableEntry) RecurLoop(processor Processor) (err error) { 528 defer func() { 529 if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) { 530 err = nil 531 } 532 }() 533 objIt := entry.MakeObjectIt(true) 534 for objIt.Valid() { 535 objectEntry := objIt.Get().GetPayload() 536 if err := processor.OnObject(objectEntry); err != nil { 537 if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) { 538 objIt.Next() 539 continue 540 } 541 return err 542 } 543 if err := processor.OnPostObject(objectEntry); err != nil { 544 return err 545 } 546 objIt.Next() 547 } 548 tombstones := entry.deleteList.Copy().Items() 549 for _, deletes := range tombstones { 550 err = processor.OnTombstone(deletes) 551 if err != nil { 552 return 553 } 554 } 555 return 556 } 557 558 func (entry *TableEntry) DropObjectEntry(id *types.Objectid, txn txnif.AsyncTxn) (deleted *ObjectEntry, err error) { 559 obj, err := entry.GetObjectByID(id) 560 if err != nil { 561 return 562 } 563 obj.Lock() 564 defer obj.Unlock() 565 needWait, waitTxn := obj.NeedWaitCommittingLocked(txn.GetStartTS()) 566 if needWait { 567 obj.Unlock() 568 waitTxn.GetTxnState(true) 569 obj.Lock() 570 } 571 var isNewNode bool 572 isNewNode, err = obj.DropEntryLocked(txn) 573 if err == nil && isNewNode { 574 deleted = obj 575 } 576 return 577 } 578 579 func (entry *TableEntry) RemoveEntry(objectEntry *ObjectEntry) (err error) { 580 logutil.Debug("[Catalog]", common.OperationField("remove"), 581 common.OperandField(objectEntry.String())) 582 // objectEntry.Close() 583 entry.Lock() 584 defer entry.Unlock() 585 return entry.deleteEntryLocked(objectEntry) 586 } 587 588 func (entry *TableEntry) PrepareRollback() (err error) { 589 // Safety: in commit queue, that's ok without lock 590 t := entry.GetLatestNodeLocked() 591 if schema := t.BaseNode.Schema; schema.Extra.OldName != "" { 592 fullname := genTblFullName(schema.AcInfo.TenantID, schema.Name) 593 entry.GetDB().RollbackRenameTable(fullname, entry.ID) 594 } 595 var isEmpty bool 596 isEmpty, err = entry.BaseEntryImpl.PrepareRollback() 597 if err != nil { 598 return 599 } 600 if isEmpty { 601 err = entry.GetDB().RemoveEntry(entry) 602 if err != nil { 603 return 604 } 605 } 606 return 607 } 608 609 /* 610 s: start 611 p: prepare 612 c: commit 613 614 old schema <- | -> new schema 615 | 616 s------------------p-----c AlterColumn Txn 617 618 Append Txn: 619 620 s------------p----c Yes 621 s-------------p--------c Yes 622 s-----------------------p---------c Yes 623 s----------------------p No, schema at s is not same with schema at p 624 */ 625 func (entry *TableEntry) ApplyCommit() (err error) { 626 err = entry.BaseEntryImpl.ApplyCommit() 627 if err != nil { 628 return 629 } 630 // It is not wanted that a block spans across different schemas 631 if entry.isColumnChangedInSchema() { 632 entry.FreezeAppend() 633 } 634 entry.RLock() 635 schema := entry.GetLatestNodeLocked().BaseNode.Schema 636 entry.RUnlock() 637 // update the shortcut to the lastest schema 638 entry.TableNode.schema.Store(schema) 639 return 640 } 641 642 // hasColumnChangedSchema checks if add or drop columns on previous schema 643 func (entry *TableEntry) isColumnChangedInSchema() bool { 644 entry.RLock() 645 defer entry.RUnlock() 646 node := entry.GetLatestNodeLocked() 647 toCommitted := node.BaseNode.Schema 648 ver := toCommitted.Version 649 // skip create table 650 if ver == 0 { 651 return false 652 } 653 return toCommitted.Extra.ColumnChanged 654 } 655 656 func (entry *TableEntry) FreezeAppend() { 657 obj := entry.LastAppendableObject() 658 if obj == nil { 659 // nothing to freeze 660 return 661 } 662 obj.GetObjectData().FreezeAppend() 663 } 664 665 // IsActive is coarse API: no consistency check 666 func (entry *TableEntry) IsActive() bool { 667 db := entry.GetDB() 668 if !db.IsActive() { 669 return false 670 } 671 return !entry.HasDropCommitted() 672 } 673 674 // GetTerminationTS is coarse API: no consistency check 675 func (entry *TableEntry) GetTerminationTS() (ts types.TS, terminated bool) { 676 dbEntry := entry.GetDB() 677 678 terminated, ts = dbEntry.TryGetTerminatedTS(true) 679 680 return 681 } 682 683 func (entry *TableEntry) AlterTable(ctx context.Context, txn txnif.TxnReader, req *apipb.AlterTableReq) (isNewNode bool, newSchema *Schema, err error) { 684 entry.Lock() 685 defer entry.Unlock() 686 needWait, txnToWait := entry.NeedWaitCommittingLocked(txn.GetStartTS()) 687 if needWait { 688 entry.Unlock() 689 txnToWait.GetTxnState(true) 690 entry.Lock() 691 } 692 err = entry.CheckConflictLocked(txn) 693 if err != nil { 694 return 695 } 696 var node *MVCCNode[*TableMVCCNode] 697 isNewNode, node = entry.getOrSetUpdateNodeLocked(txn) 698 699 newSchema = node.BaseNode.Schema 700 if isNewNode { 701 // Extra info(except seqnnum etc.) is meaningful to the previous version schema 702 // reset in new Schema 703 var hints []apipb.MergeHint 704 copy(hints, newSchema.Extra.Hints) 705 newSchema.Extra = &apipb.SchemaExtra{ 706 NextColSeqnum: newSchema.Extra.NextColSeqnum, 707 MinOsizeQuailifed: newSchema.Extra.MinOsizeQuailifed, 708 MaxObjOnerun: newSchema.Extra.MaxObjOnerun, 709 MaxOsizeMergedObj: newSchema.Extra.MaxOsizeMergedObj, 710 MinCnMergeSize: newSchema.Extra.MinCnMergeSize, 711 Hints: hints, 712 } 713 714 } 715 if err = newSchema.ApplyAlterTable(req); err != nil { 716 return 717 } 718 if isNewNode { 719 node.BaseNode.Schema.Version += 1 720 } 721 return 722 } 723 724 func (entry *TableEntry) CreateWithTxnAndSchema(txn txnif.AsyncTxn, schema *Schema) { 725 node := &MVCCNode[*TableMVCCNode]{ 726 EntryMVCCNode: &EntryMVCCNode{ 727 CreatedAt: txnif.UncommitTS, 728 }, 729 TxnMVCCNode: txnbase.NewTxnMVCCNodeWithTxn(txn), 730 BaseNode: &TableMVCCNode{ 731 Schema: schema, 732 }, 733 } 734 entry.Insert(node) 735 } 736 737 func (entry *TableEntry) GetVisibilityAndName(txn txnif.TxnReader) (visible, dropped bool, name string) { 738 entry.RLock() 739 defer entry.RUnlock() 740 needWait, txnToWait := entry.NeedWaitCommittingLocked(txn.GetStartTS()) 741 if needWait { 742 entry.RUnlock() 743 txnToWait.GetTxnState(true) 744 entry.RLock() 745 } 746 un := entry.GetVisibleNodeLocked(txn) 747 if un == nil { 748 return 749 } 750 visible = true 751 if un.IsSameTxn(txn) { 752 dropped = un.HasDropIntent() 753 } else { 754 dropped = un.HasDropCommitted() 755 } 756 name = un.BaseNode.Schema.Name 757 return 758 } 759 760 // only for test 761 func MockTableEntryWithDB(dbEntry *DBEntry, tblId uint64) *TableEntry { 762 entry := NewReplayTableEntry() 763 entry.TableNode = &TableNode{} 764 entry.TableNode.schema.Store(NewEmptySchema("test")) 765 entry.ID = tblId 766 entry.db = dbEntry 767 return entry 768 }