github.com/matrixorigin/matrixone@v0.7.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 "fmt" 20 "io" 21 "sync/atomic" 22 23 pkgcatalog "github.com/matrixorigin/matrixone/pkg/catalog" 24 "github.com/matrixorigin/matrixone/pkg/common/moerr" 25 "github.com/matrixorigin/matrixone/pkg/container/types" 26 "github.com/matrixorigin/matrixone/pkg/logutil" 27 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 28 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/data" 29 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 30 ) 31 32 type TableDataFactory = func(meta *TableEntry) data.Table 33 34 func tableVisibilityFn[T *TableEntry](n *common.GenericDLNode[*TableEntry], ts types.TS) (visible, dropped bool) { 35 table := n.GetPayload() 36 visible, dropped = table.GetVisibility(ts) 37 return 38 } 39 40 type TableEntry struct { 41 *TableBaseEntry 42 db *DBEntry 43 schema *Schema 44 entries map[uint64]*common.GenericDLNode[*SegmentEntry] 45 //link.head and link.tail is nil when create tableEntry object. 46 link *common.GenericSortedDList[*SegmentEntry] 47 tableData data.Table 48 rows atomic.Uint64 49 // fullname is format as 'tenantID-tableName', the tenantID prefix is only used 'mo_catalog' database 50 fullName string 51 } 52 53 func genTblFullName(tenantID uint32, name string) string { 54 if name == pkgcatalog.MO_DATABASE || name == pkgcatalog.MO_TABLES || name == pkgcatalog.MO_COLUMNS { 55 tenantID = 0 56 } 57 return fmt.Sprintf("%d-%s", tenantID, name) 58 } 59 60 func NewTableEntry(db *DBEntry, schema *Schema, txnCtx txnif.AsyncTxn, dataFactory TableDataFactory) *TableEntry { 61 id := db.catalog.NextTable() 62 return NewTableEntryWithTableId(db, schema, txnCtx, dataFactory, id) 63 } 64 65 func NewTableEntryWithTableId(db *DBEntry, schema *Schema, txnCtx txnif.AsyncTxn, dataFactory TableDataFactory, tableId uint64) *TableEntry { 66 if txnCtx != nil { 67 // Only in unit test, txnCtx can be nil 68 schema.AcInfo.TenantID = txnCtx.GetTenantID() 69 schema.AcInfo.UserID, schema.AcInfo.RoleID = txnCtx.GetUserAndRoleID() 70 } 71 schema.AcInfo.CreateAt = types.CurrentTimestamp() 72 e := &TableEntry{ 73 TableBaseEntry: NewTableBaseEntry(tableId), 74 db: db, 75 schema: schema, 76 link: common.NewGenericSortedDList(compareSegmentFn), 77 entries: make(map[uint64]*common.GenericDLNode[*SegmentEntry]), 78 } 79 if dataFactory != nil { 80 e.tableData = dataFactory(e) 81 } 82 e.CreateWithTxn(txnCtx, schema) 83 return e 84 } 85 86 func NewSystemTableEntry(db *DBEntry, id uint64, schema *Schema) *TableEntry { 87 e := &TableEntry{ 88 TableBaseEntry: NewTableBaseEntry(id), 89 db: db, 90 schema: schema, 91 link: common.NewGenericSortedDList(compareSegmentFn), 92 entries: make(map[uint64]*common.GenericDLNode[*SegmentEntry]), 93 } 94 e.CreateWithTS(types.SystemDBTS) 95 var sid uint64 96 if schema.Name == SystemTableSchema.Name { 97 sid = SystemSegment_Table_ID 98 } else if schema.Name == SystemDBSchema.Name { 99 sid = SystemSegment_DB_ID 100 } else if schema.Name == SystemColumnSchema.Name { 101 sid = SystemSegment_Columns_ID 102 } else { 103 panic("not supported") 104 } 105 segment := NewSysSegmentEntry(e, sid) 106 e.AddEntryLocked(segment) 107 return e 108 } 109 110 func NewReplayTableEntry() *TableEntry { 111 e := &TableEntry{ 112 TableBaseEntry: NewReplayTableBaseEntry(), 113 link: common.NewGenericSortedDList(compareSegmentFn), 114 entries: make(map[uint64]*common.GenericDLNode[*SegmentEntry]), 115 } 116 return e 117 } 118 119 func MockStaloneTableEntry(id uint64, schema *Schema) *TableEntry { 120 return &TableEntry{ 121 TableBaseEntry: NewTableBaseEntry(id), 122 schema: schema, 123 link: common.NewGenericSortedDList(compareSegmentFn), 124 entries: make(map[uint64]*common.GenericDLNode[*SegmentEntry]), 125 } 126 } 127 128 func (entry *TableEntry) IsVirtual() bool { 129 if !entry.db.IsSystemDB() { 130 return false 131 } 132 return entry.schema.Name == pkgcatalog.MO_DATABASE || 133 entry.schema.Name == pkgcatalog.MO_TABLES || 134 entry.schema.Name == pkgcatalog.MO_COLUMNS 135 } 136 137 func (entry *TableEntry) GetRows() uint64 { 138 return entry.rows.Load() 139 } 140 141 func (entry *TableEntry) AddRows(delta uint64) uint64 { 142 return entry.rows.Add(delta) 143 } 144 145 func (entry *TableEntry) RemoveRows(delta uint64) uint64 { 146 return entry.rows.Add(^(delta - 1)) 147 } 148 149 func (entry *TableEntry) GetSegmentByID(id uint64) (seg *SegmentEntry, err error) { 150 entry.RLock() 151 defer entry.RUnlock() 152 node := entry.entries[id] 153 if node == nil { 154 return nil, moerr.GetOkExpectedEOB() 155 } 156 return node.GetPayload(), nil 157 } 158 159 func (entry *TableEntry) MakeSegmentIt(reverse bool) *common.GenericSortedDListIt[*SegmentEntry] { 160 entry.RLock() 161 defer entry.RUnlock() 162 return common.NewGenericSortedDListIt(entry.RWMutex, entry.link, reverse) 163 } 164 165 func (entry *TableEntry) CreateSegment(txn txnif.AsyncTxn, state EntryState, dataFactory SegmentDataFactory) (created *SegmentEntry, err error) { 166 entry.Lock() 167 defer entry.Unlock() 168 created = NewSegmentEntry(entry, txn, state, dataFactory) 169 entry.AddEntryLocked(created) 170 return 171 } 172 173 func (entry *TableEntry) MakeCommand(id uint32) (cmd txnif.TxnCmd, err error) { 174 cmdType := CmdUpdateTable 175 entry.RLock() 176 defer entry.RUnlock() 177 return newTableCmd(id, cmdType, entry), nil 178 } 179 180 func (entry *TableEntry) Set1PC() { 181 entry.GetLatestNodeLocked().Set1PC() 182 } 183 func (entry *TableEntry) Is1PC() bool { 184 return entry.GetLatestNodeLocked().Is1PC() 185 } 186 func (entry *TableEntry) AddEntryLocked(segment *SegmentEntry) { 187 n := entry.link.Insert(segment) 188 entry.entries[segment.GetID()] = n 189 } 190 191 func (entry *TableEntry) deleteEntryLocked(segment *SegmentEntry) error { 192 if n, ok := entry.entries[segment.GetID()]; !ok { 193 return moerr.GetOkExpectedEOB() 194 } else { 195 entry.link.Delete(n) 196 delete(entry.entries, segment.GetID()) 197 segment.Close() 198 } 199 return nil 200 } 201 202 func (entry *TableEntry) GetSchema() *Schema { 203 return entry.schema 204 } 205 206 func (entry *TableEntry) GetColDefs() []*ColDef { 207 colDefs := entry.schema.ColDefs 208 colDefs = append(colDefs, entry.schema.PhyAddrKey) 209 return colDefs 210 } 211 212 func (entry *TableEntry) GetFullName() string { 213 if len(entry.fullName) == 0 { 214 entry.fullName = genTblFullName(entry.schema.AcInfo.TenantID, entry.schema.Name) 215 } 216 return entry.fullName 217 } 218 219 func (entry *TableEntry) GetDB() *DBEntry { 220 return entry.db 221 } 222 223 func (entry *TableEntry) PPString(level common.PPLevel, depth int, prefix string) string { 224 var w bytes.Buffer 225 _, _ = w.WriteString(fmt.Sprintf("%s%s%s", common.RepeatStr("\t", depth), prefix, entry.StringWithLevel(level))) 226 if level == common.PPL0 { 227 return w.String() 228 } 229 it := entry.MakeSegmentIt(true) 230 for it.Valid() { 231 segment := it.Get().GetPayload() 232 _ = w.WriteByte('\n') 233 _, _ = w.WriteString(segment.PPString(level, depth+1, prefix)) 234 it.Next() 235 } 236 return w.String() 237 } 238 239 func (entry *TableEntry) String() string { 240 entry.RLock() 241 defer entry.RUnlock() 242 return entry.StringLocked() 243 } 244 245 func (entry *TableEntry) StringWithLevel(level common.PPLevel) string { 246 entry.RLock() 247 defer entry.RUnlock() 248 return entry.StringLockedWithLevel(level) 249 } 250 func (entry *TableEntry) StringLockedWithLevel(level common.PPLevel) string { 251 if level <= common.PPL1 { 252 return fmt.Sprintf("TBL[%d][name=%s][C@%s,D@%s]", 253 entry.ID, entry.schema.Name, entry.GetCreatedAt().ToString(), entry.GetDeleteAt().ToString()) 254 } 255 return fmt.Sprintf("TBL%s[name=%s]", entry.TableBaseEntry.StringLocked(), entry.schema.Name) 256 } 257 258 func (entry *TableEntry) StringLocked() string { 259 return entry.StringLockedWithLevel(common.PPL1) 260 } 261 262 func (entry *TableEntry) GetCatalog() *Catalog { return entry.db.catalog } 263 264 func (entry *TableEntry) GetTableData() data.Table { return entry.tableData } 265 266 func (entry *TableEntry) LastAppendableSegmemt() (seg *SegmentEntry) { 267 it := entry.MakeSegmentIt(false) 268 for it.Valid() { 269 itSeg := it.Get().GetPayload() 270 dropped := itSeg.HasDropCommitted() 271 if itSeg.IsAppendable() && !dropped { 272 seg = itSeg 273 break 274 } 275 it.Next() 276 } 277 return seg 278 } 279 280 func (entry *TableEntry) LastNonAppendableSegmemt() (seg *SegmentEntry) { 281 it := entry.MakeSegmentIt(false) 282 for it.Valid() { 283 itSeg := it.Get().GetPayload() 284 dropped := itSeg.HasDropCommitted() 285 if !itSeg.IsAppendable() && !dropped { 286 seg = itSeg 287 break 288 } 289 it.Next() 290 } 291 return seg 292 } 293 294 func (entry *TableEntry) AsCommonID() *common.ID { 295 return &common.ID{ 296 TableID: entry.GetID(), 297 } 298 } 299 300 func (entry *TableEntry) RecurLoop(processor Processor) (err error) { 301 segIt := entry.MakeSegmentIt(true) 302 for segIt.Valid() { 303 segment := segIt.Get().GetPayload() 304 if err = processor.OnSegment(segment); err != nil { 305 if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) { 306 err = nil 307 segIt.Next() 308 continue 309 } 310 break 311 } 312 blkIt := segment.MakeBlockIt(true) 313 for blkIt.Valid() { 314 block := blkIt.Get().GetPayload() 315 if err = processor.OnBlock(block); err != nil { 316 if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) { 317 err = nil 318 blkIt.Next() 319 continue 320 } 321 break 322 } 323 blkIt.Next() 324 } 325 if err = processor.OnPostSegment(segment); err != nil { 326 break 327 } 328 segIt.Next() 329 } 330 if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) { 331 err = nil 332 } 333 return err 334 } 335 336 func (entry *TableEntry) DropSegmentEntry(id uint64, txn txnif.AsyncTxn) (deleted *SegmentEntry, err error) { 337 seg, err := entry.GetSegmentByID(id) 338 if err != nil { 339 return 340 } 341 seg.Lock() 342 defer seg.Unlock() 343 needWait, waitTxn := seg.NeedWaitCommitting(txn.GetStartTS()) 344 if needWait { 345 seg.Unlock() 346 waitTxn.GetTxnState(true) 347 seg.Lock() 348 } 349 var isNewNode bool 350 isNewNode, err = seg.DropEntryLocked(txn) 351 if err == nil && isNewNode { 352 deleted = seg 353 } 354 return 355 } 356 357 func (entry *TableEntry) RemoveEntry(segment *SegmentEntry) (err error) { 358 logutil.Info("[Catalog]", common.OperationField("remove"), 359 common.OperandField(segment.String())) 360 // segment.Close() 361 entry.Lock() 362 defer entry.Unlock() 363 return entry.deleteEntryLocked(segment) 364 } 365 366 func (entry *TableEntry) Close() { 367 segs := entry.getAllSegs() 368 entry.Lock() 369 defer entry.Unlock() 370 for _, seg := range segs { 371 err := entry.deleteEntryLocked(seg) 372 if err != nil { 373 panic(err) 374 } 375 } 376 } 377 378 func (entry *TableEntry) getAllSegs() []*SegmentEntry { 379 segs := make([]*SegmentEntry, 0) 380 it := entry.MakeSegmentIt(false) 381 for it.Valid() { 382 segs = append(segs, it.Get().GetPayload()) 383 it.Next() 384 } 385 return segs 386 } 387 388 func (entry *TableEntry) PrepareRollback() (err error) { 389 var isEmpty bool 390 isEmpty, err = entry.TableBaseEntry.PrepareRollback() 391 if err != nil { 392 return 393 } 394 if isEmpty { 395 err = entry.GetDB().RemoveEntry(entry) 396 if err != nil { 397 return 398 } 399 } 400 return 401 } 402 403 func (entry *TableEntry) WriteTo(w io.Writer) (n int64, err error) { 404 if n, err = entry.TableBaseEntry.WriteAllTo(w); err != nil { 405 return 406 } 407 buf, err := entry.schema.Marshal() 408 if err != nil { 409 return 410 } 411 sn := int(0) 412 sn, err = w.Write(buf) 413 n += int64(sn) 414 return 415 } 416 417 func (entry *TableEntry) ReadFrom(r io.Reader) (n int64, err error) { 418 if n, err = entry.TableBaseEntry.ReadAllFrom(r); err != nil { 419 return 420 } 421 if entry.schema == nil { 422 entry.schema = NewEmptySchema("") 423 } 424 sn := int64(0) 425 sn, err = entry.schema.ReadFrom(r) 426 n += sn 427 return 428 } 429 430 // IsActive is coarse API: no consistency check 431 func (entry *TableEntry) IsActive() bool { 432 db := entry.GetDB() 433 if !db.IsActive() { 434 return false 435 } 436 return !entry.HasDropCommitted() 437 } 438 439 // GetTerminationTS is coarse API: no consistency check 440 func (entry *TableEntry) GetTerminationTS() (ts types.TS, terminated bool) { 441 dbEntry := entry.GetDB() 442 443 dbEntry.RLock() 444 terminated, ts = dbEntry.TryGetTerminatedTS(true) 445 dbEntry.RUnlock() 446 447 return 448 }