github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/catalog/database.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 "encoding/binary" 20 "fmt" 21 "io" 22 "sync" 23 24 pkgcatalog "github.com/matrixorigin/matrixone/pkg/catalog" 25 "github.com/matrixorigin/matrixone/pkg/common/moerr" 26 "github.com/matrixorigin/matrixone/pkg/container/types" 27 "github.com/matrixorigin/matrixone/pkg/logutil" 28 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 29 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/txnif" 30 ) 31 32 type accessInfo struct { 33 TenantID, UserID, RoleID uint32 34 CreateAt types.Timestamp 35 } 36 37 func (ai *accessInfo) WriteTo(w io.Writer) (n int64, err error) { 38 for _, id := range []uint32{ai.TenantID, ai.UserID, ai.RoleID} { 39 if err = binary.Write(w, binary.BigEndian, id); err != nil { 40 return 41 } 42 } 43 if err = binary.Write(w, binary.BigEndian, int64(ai.CreateAt)); err != nil { 44 return 45 } 46 return 20, nil 47 } 48 49 func (ai *accessInfo) ReadFrom(r io.Reader) (n int64, err error) { 50 for _, idPtr := range []*uint32{&ai.TenantID, &ai.UserID, &ai.RoleID} { 51 if err = binary.Read(r, binary.BigEndian, idPtr); err != nil { 52 return 53 } 54 } 55 at := int64(0) 56 if err = binary.Read(r, binary.BigEndian, &at); err != nil { 57 return 58 } 59 ai.CreateAt = types.Timestamp(at) 60 return 20, nil 61 } 62 63 func dbVisibilityFn[T *DBEntry](n *common.GenericDLNode[*DBEntry], ts types.TS) (visible, dropped bool) { 64 db := n.GetPayload() 65 visible, dropped = db.GetVisibility(ts) 66 return 67 } 68 69 type DBEntry struct { 70 *DBBaseEntry 71 catalog *Catalog 72 acInfo accessInfo 73 name string 74 createSql string 75 fullName string 76 isSys bool 77 78 entries map[uint64]*common.GenericDLNode[*TableEntry] 79 nameNodes map[string]*nodeList[*TableEntry] 80 link *common.GenericSortedDList[*TableEntry] 81 82 nodesMu sync.RWMutex 83 } 84 85 func compareTableFn(a, b *TableEntry) int { 86 return a.TableBaseEntry.DoCompre(b.TableBaseEntry) 87 } 88 89 func NewDBEntryWithID(catalog *Catalog, name string, createSql string, id uint64, txn txnif.AsyncTxn) *DBEntry { 90 //id := catalog.NextDB() 91 92 e := &DBEntry{ 93 DBBaseEntry: NewDBBaseEntry(id), 94 catalog: catalog, 95 name: name, 96 createSql: createSql, 97 entries: make(map[uint64]*common.GenericDLNode[*TableEntry]), 98 nameNodes: make(map[string]*nodeList[*TableEntry]), 99 link: common.NewGenericSortedDList(compareTableFn), 100 } 101 if txn != nil { 102 // Only in unit test, txn can be nil 103 e.acInfo.TenantID = txn.GetTenantID() 104 e.acInfo.UserID, e.acInfo.RoleID = txn.GetUserAndRoleID() 105 } 106 e.CreateWithTxn(txn) 107 e.acInfo.CreateAt = types.CurrentTimestamp() 108 return e 109 } 110 111 func NewDBEntry(catalog *Catalog, name, createSql string, txn txnif.AsyncTxn) *DBEntry { 112 id := catalog.NextDB() 113 114 e := &DBEntry{ 115 DBBaseEntry: NewDBBaseEntry(id), 116 catalog: catalog, 117 name: name, 118 createSql: createSql, 119 entries: make(map[uint64]*common.GenericDLNode[*TableEntry]), 120 nameNodes: make(map[string]*nodeList[*TableEntry]), 121 link: common.NewGenericSortedDList(compareTableFn), 122 } 123 if txn != nil { 124 // Only in unit test, txn can be nil 125 e.acInfo.TenantID = txn.GetTenantID() 126 e.acInfo.UserID, e.acInfo.RoleID = txn.GetUserAndRoleID() 127 } 128 e.CreateWithTxn(txn) 129 e.acInfo.CreateAt = types.CurrentTimestamp() 130 return e 131 } 132 133 func NewDBEntryByTS(catalog *Catalog, name string, ts types.TS) *DBEntry { 134 id := catalog.NextDB() 135 136 e := &DBEntry{ 137 DBBaseEntry: NewDBBaseEntry(id), 138 catalog: catalog, 139 name: name, 140 entries: make(map[uint64]*common.GenericDLNode[*TableEntry]), 141 nameNodes: make(map[string]*nodeList[*TableEntry]), 142 link: common.NewGenericSortedDList(compareTableFn), 143 } 144 e.CreateWithTS(ts) 145 e.acInfo.CreateAt = types.CurrentTimestamp() 146 return e 147 } 148 149 func NewSystemDBEntry(catalog *Catalog) *DBEntry { 150 entry := &DBEntry{ 151 DBBaseEntry: NewDBBaseEntry(pkgcatalog.MO_CATALOG_ID), 152 catalog: catalog, 153 name: pkgcatalog.MO_CATALOG, 154 createSql: "create database " + pkgcatalog.MO_CATALOG, 155 entries: make(map[uint64]*common.GenericDLNode[*TableEntry]), 156 nameNodes: make(map[string]*nodeList[*TableEntry]), 157 link: common.NewGenericSortedDList(compareTableFn), 158 isSys: true, 159 } 160 entry.CreateWithTS(types.SystemDBTS) 161 return entry 162 } 163 164 func NewReplayDBEntry() *DBEntry { 165 entry := &DBEntry{ 166 DBBaseEntry: NewReplayDBBaseEntry(), 167 entries: make(map[uint64]*common.GenericDLNode[*TableEntry]), 168 nameNodes: make(map[string]*nodeList[*TableEntry]), 169 link: common.NewGenericSortedDList(compareTableFn), 170 } 171 return entry 172 } 173 174 func (e *DBEntry) IsSystemDB() bool { return e.isSys } 175 func (e *DBEntry) CoarseTableCnt() int { 176 e.RLock() 177 defer e.RUnlock() 178 return len(e.entries) 179 } 180 181 func (e *DBEntry) GetTenantID() uint32 { return e.acInfo.TenantID } 182 func (e *DBEntry) GetUserID() uint32 { return e.acInfo.UserID } 183 func (e *DBEntry) GetRoleID() uint32 { return e.acInfo.RoleID } 184 func (e *DBEntry) GetCreateAt() types.Timestamp { return e.acInfo.CreateAt } 185 func (e *DBEntry) GetName() string { return e.name } 186 func (e *DBEntry) GetCreateSql() string { return e.createSql } 187 func (e *DBEntry) GetFullName() string { 188 if len(e.fullName) == 0 { 189 e.fullName = genDBFullName(e.acInfo.TenantID, e.name) 190 } 191 return e.fullName 192 } 193 194 func (e *DBEntry) String() string { 195 e.RLock() 196 defer e.RUnlock() 197 return e.StringLocked() 198 } 199 200 func (e *DBEntry) StringLocked() string { 201 return e.StringWithlevelLocked(common.PPL1) 202 } 203 func (e *DBEntry) StringWithLevel(level common.PPLevel) string { 204 e.RLock() 205 defer e.RUnlock() 206 return e.StringWithlevelLocked(level) 207 } 208 209 func (e *DBEntry) StringWithlevelLocked(level common.PPLevel) string { 210 if level <= common.PPL1 { 211 return fmt.Sprintf("DB[%d][name=%s][C@%s,D@%s]", 212 e.DBBaseEntry.ID, e.GetFullName(), e.GetCreatedAt().ToString(), e.GetDeleteAt().ToString()) 213 } 214 return fmt.Sprintf("DB%s[name=%s]", e.DBBaseEntry.StringLocked(), e.GetFullName()) 215 } 216 217 func (e *DBEntry) MakeTableIt(reverse bool) *common.GenericSortedDListIt[*TableEntry] { 218 e.RLock() 219 defer e.RUnlock() 220 return common.NewGenericSortedDListIt(e.RWMutex, e.link, reverse) 221 } 222 223 func (e *DBEntry) 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, e.StringWithLevel(level))) 226 if level == common.PPL0 { 227 return w.String() 228 } 229 it := e.MakeTableIt(true) 230 for it.Valid() { 231 table := it.Get().GetPayload() 232 _ = w.WriteByte('\n') 233 _, _ = w.WriteString(table.PPString(level, depth+1, "")) 234 it.Next() 235 } 236 return w.String() 237 } 238 239 func (e *DBEntry) GetBlockEntryByID(id *common.ID) (blk *BlockEntry, err error) { 240 e.RLock() 241 table, err := e.GetTableEntryByID(id.TableID) 242 e.RUnlock() 243 if err != nil { 244 return 245 } 246 seg, err := table.GetSegmentByID(id.SegmentID) 247 if err != nil { 248 return 249 } 250 blk, err = seg.GetBlockEntryByID(id.BlockID) 251 return 252 } 253 254 func (e *DBEntry) GetItemNodeByIDLocked(id uint64) *common.GenericDLNode[*TableEntry] { 255 return e.entries[id] 256 } 257 258 func (e *DBEntry) GetTableEntryByID(id uint64) (table *TableEntry, err error) { 259 e.RLock() 260 defer e.RUnlock() 261 node := e.entries[id] 262 if node == nil { 263 return nil, moerr.GetOkExpectedEOB() 264 } 265 table = node.GetPayload() 266 return 267 } 268 269 func (e *DBEntry) txnGetNodeByName( 270 tenantID uint32, 271 name string, 272 ts types.TS) (*common.GenericDLNode[*TableEntry], error) { 273 e.RLock() 274 defer e.RUnlock() 275 fullName := genTblFullName(tenantID, name) 276 node := e.nameNodes[fullName] 277 if node == nil { 278 return nil, moerr.GetOkExpectedEOB() 279 } 280 return node.TxnGetNodeLocked(ts) 281 } 282 283 func (e *DBEntry) TxnGetTableEntryByName(name string, txn txnif.AsyncTxn) (entry *TableEntry, err error) { 284 n, err := e.txnGetNodeByName(txn.GetTenantID(), name, txn.GetStartTS()) 285 if err != nil { 286 return 287 } 288 entry = n.GetPayload() 289 return 290 } 291 292 func (e *DBEntry) GetTableEntryByName( 293 tenantID uint32, 294 name string, 295 ts types.TS) (entry *TableEntry, err error) { 296 n, err := e.txnGetNodeByName(tenantID, name, ts) 297 if err != nil { 298 return 299 } 300 entry = n.GetPayload() 301 return 302 } 303 304 func (e *DBEntry) TxnGetTableEntryByID(id uint64, txn txnif.AsyncTxn) (entry *TableEntry, err error) { 305 entry, err = e.GetTableEntryByID(id) 306 if err != nil { 307 return 308 } 309 //check whether visible and dropped. 310 visible, dropped := entry.GetVisibility(txn.GetStartTS()) 311 if !visible || dropped { 312 return nil, moerr.GetOkExpectedEOB() 313 } 314 return 315 } 316 317 // Catalog entry is dropped in following steps: 318 // 1. Locate the record by timestamp 319 // 2. Check conflication. 320 // 2.1 Wait for the related txn if need. 321 // 2.2 w-w conflict when 1. there's an active txn; or 322 // 2. the CommitTS of the latest related txn is larger than StartTS of write txn 323 // 324 // 3. Check duplicate/not found. 325 // If the entry has already been dropped, return ErrNotFound. 326 func (e *DBEntry) DropTableEntry(name string, txn txnif.AsyncTxn) (newEntry bool, deleted *TableEntry, err error) { 327 dn, err := e.txnGetNodeByName(txn.GetTenantID(), name, txn.GetStartTS()) 328 if err != nil { 329 return 330 } 331 entry := dn.GetPayload() 332 entry.Lock() 333 defer entry.Unlock() 334 newEntry, err = entry.DropEntryLocked(txn) 335 if err == nil { 336 deleted = entry 337 } 338 return 339 } 340 341 func (e *DBEntry) DropTableEntryByID(id uint64, txn txnif.AsyncTxn) (newEntry bool, deleted *TableEntry, err error) { 342 entry, err := e.GetTableEntryByID(id) 343 if err != nil { 344 return 345 } 346 347 entry.Lock() 348 defer entry.Unlock() 349 newEntry, err = entry.DropEntryLocked(txn) 350 if err == nil { 351 deleted = entry 352 } 353 return 354 } 355 356 func (e *DBEntry) CreateTableEntry(schema *Schema, txn txnif.AsyncTxn, dataFactory TableDataFactory) (created *TableEntry, err error) { 357 e.Lock() 358 created = NewTableEntry(e, schema, txn, dataFactory) 359 err = e.AddEntryLocked(created, txn, false) 360 e.Unlock() 361 362 return created, err 363 } 364 365 func (e *DBEntry) CreateTableEntryWithTableId(schema *Schema, txn txnif.AsyncTxn, dataFactory TableDataFactory, tableId uint64) (created *TableEntry, err error) { 366 e.Lock() 367 //Deduplicate for tableId 368 if _, exist := e.entries[tableId]; exist { 369 return nil, moerr.GetOkExpectedDup() 370 } 371 created = NewTableEntryWithTableId(e, schema, txn, dataFactory, tableId) 372 err = e.AddEntryLocked(created, txn, false) 373 e.Unlock() 374 375 return created, err 376 } 377 378 func (e *DBEntry) RemoveEntry(table *TableEntry) (err error) { 379 defer func() { 380 if err == nil { 381 e.catalog.AddTableCnt(-1) 382 e.catalog.AddColumnCnt(-1 * len(table.schema.ColDefs)) 383 } 384 }() 385 // table.Close() 386 logutil.Info("[Catalog]", common.OperationField("remove"), 387 common.OperandField(table.String())) 388 e.Lock() 389 defer e.Unlock() 390 if n, ok := e.entries[table.GetID()]; !ok { 391 return moerr.GetOkExpectedEOB() 392 } else { 393 nn := e.nameNodes[table.GetFullName()] 394 nn.DeleteNode(table.GetID()) 395 e.link.Delete(n) 396 if nn.Length() == 0 { 397 delete(e.nameNodes, table.GetFullName()) 398 } 399 delete(e.entries, table.GetID()) 400 } 401 return 402 } 403 404 func (e *DBEntry) Close() { 405 tbls := e.getAllTablesLocked() 406 for _, tbl := range tbls { 407 err := e.RemoveEntry(tbl) 408 if err != nil { 409 panic(err) 410 } 411 } 412 } 413 414 func (e *DBEntry) getAllTablesLocked() []*TableEntry { 415 tbls := make([]*TableEntry, 0) 416 it := e.MakeTableIt(false) 417 for it.Valid() { 418 tbls = append(tbls, it.Get().GetPayload()) 419 it.Next() 420 } 421 return tbls 422 } 423 424 // Catalog entry is created in following steps: 425 // 1. Locate the record. Creating always gets the latest DBEntry. 426 // 2.1 If there doesn't exist a DBEntry, add new entry and return. 427 // 2.2 If there exists a DBEntry: 428 // 2.2.1 Check conflication. 429 // 1. Wait for the related txn if need. 430 // 2. w-w conflict when: there's an active txn; or 431 // he CommitTS of the latest related txn is larger than StartTS of write txn 432 // 433 // 2.2.2 Check duplicate/not found. 434 // If the entry hasn't been dropped, return ErrDuplicate. 435 func (e *DBEntry) AddEntryLocked(table *TableEntry, txn txnif.TxnReader, skipDedup bool) (err error) { 436 defer func() { 437 if err == nil { 438 e.catalog.AddTableCnt(1) 439 e.catalog.AddColumnCnt(len(table.schema.ColDefs)) 440 } 441 }() 442 fullName := table.GetFullName() 443 nn := e.nameNodes[fullName] 444 if nn == nil { 445 n := e.link.Insert(table) 446 e.entries[table.GetID()] = n 447 448 nn := newNodeList(e.GetItemNodeByIDLocked, 449 tableVisibilityFn[*TableEntry], 450 &e.nodesMu, 451 fullName) 452 e.nameNodes[fullName] = nn 453 454 nn.CreateNode(table.GetID()) 455 } else { 456 node := nn.GetNode() 457 if !skipDedup { 458 record := node.GetPayload() 459 err = record.PrepareAdd(txn) 460 if err != nil { 461 return 462 } 463 } 464 n := e.link.Insert(table) 465 e.entries[table.GetID()] = n 466 nn.CreateNode(table.GetID()) 467 } 468 return 469 } 470 471 func (e *DBEntry) MakeCommand(id uint32) (txnif.TxnCmd, error) { 472 cmdType := CmdUpdateDatabase 473 e.RLock() 474 defer e.RUnlock() 475 return newDBCmd(id, cmdType, e), nil 476 } 477 478 func (e *DBEntry) Set1PC() { 479 e.GetLatestNodeLocked().Set1PC() 480 } 481 func (e *DBEntry) Is1PC() bool { 482 return e.GetLatestNodeLocked().Is1PC() 483 } 484 func (e *DBEntry) GetCatalog() *Catalog { return e.catalog } 485 486 func (e *DBEntry) RecurLoop(processor Processor) (err error) { 487 tableIt := e.MakeTableIt(true) 488 for tableIt.Valid() { 489 table := tableIt.Get().GetPayload() 490 if err = processor.OnTable(table); err != nil { 491 if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) { 492 err = nil 493 tableIt.Next() 494 continue 495 } 496 break 497 } 498 if err = table.RecurLoop(processor); err != nil { 499 return 500 } 501 tableIt.Next() 502 } 503 if moerr.IsMoErrCode(err, moerr.OkStopCurrRecur) { 504 err = nil 505 } 506 return err 507 } 508 509 func (e *DBEntry) PrepareRollback() (err error) { 510 var isEmpty bool 511 if isEmpty, err = e.DBBaseEntry.PrepareRollback(); err != nil { 512 return 513 } 514 if isEmpty { 515 if err = e.catalog.RemoveEntry(e); err != nil { 516 return 517 } 518 } 519 return 520 } 521 522 func (e *DBEntry) WriteTo(w io.Writer) (n int64, err error) { 523 if n, err = e.DBBaseEntry.WriteAllTo(w); err != nil { 524 return 525 } 526 x, err := e.acInfo.WriteTo(w) 527 if err != nil { 528 return 529 } 530 n += x 531 if err = binary.Write(w, binary.BigEndian, uint16(len(e.name))); err != nil { 532 return 533 } 534 var sn int 535 sn, err = w.Write([]byte(e.name)) 536 if err != nil { 537 return 538 } 539 n += int64(sn) + 2 540 if err = binary.Write(w, binary.BigEndian, uint16(len(e.createSql))); err != nil { 541 return 542 } 543 sn, err = w.Write([]byte(e.createSql)) 544 n += int64(sn) + 2 545 return 546 } 547 548 func (e *DBEntry) ReadFrom(r io.Reader) (n int64, err error) { 549 if n, err = e.DBBaseEntry.ReadAllFrom(r); err != nil { 550 return 551 } 552 x, err := e.acInfo.ReadFrom(r) 553 if err != nil { 554 return 555 } 556 n += x 557 size := uint16(0) 558 if err = binary.Read(r, binary.BigEndian, &size); err != nil { 559 return 560 } 561 n += 2 562 buf := make([]byte, size) 563 if _, err = r.Read(buf); err != nil { 564 return 565 } 566 n += int64(size) 567 e.name = string(buf) 568 569 if err = binary.Read(r, binary.BigEndian, &size); err != nil { 570 return 571 } 572 n += 2 573 buf = make([]byte, size) 574 if _, err = r.Read(buf); err != nil { 575 return 576 } 577 n += int64(size) 578 e.createSql = string(buf) 579 return 580 } 581 582 // IsActive is coarse API: no consistency check 583 func (e *DBEntry) IsActive() bool { 584 return !e.HasDropCommitted() 585 }