github.com/matrixorigin/matrixone@v1.2.0/pkg/vm/engine/disttae/txn_database.go (about) 1 // Copyright 2022 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 disttae 16 17 import ( 18 "context" 19 "runtime/debug" 20 "strconv" 21 "strings" 22 23 "go.uber.org/zap" 24 25 "github.com/matrixorigin/matrixone/pkg/logutil" 26 txn2 "github.com/matrixorigin/matrixone/pkg/pb/txn" 27 28 "github.com/matrixorigin/matrixone/pkg/catalog" 29 "github.com/matrixorigin/matrixone/pkg/common/moerr" 30 "github.com/matrixorigin/matrixone/pkg/container/types" 31 "github.com/matrixorigin/matrixone/pkg/defines" 32 "github.com/matrixorigin/matrixone/pkg/vm/engine" 33 "github.com/matrixorigin/matrixone/pkg/vm/engine/disttae/cache" 34 "github.com/matrixorigin/matrixone/pkg/vm/process" 35 ) 36 37 var _ engine.Database = new(txnDatabase) 38 39 func (db *txnDatabase) getTxn() *Transaction { 40 return db.op.GetWorkspace().(*Transaction) 41 } 42 43 func (db *txnDatabase) getEng() *Engine { 44 return db.op.GetWorkspace().(*Transaction).engine 45 } 46 47 func (db *txnDatabase) Relations(ctx context.Context) ([]string, error) { 48 var rels []string 49 //first get all delete tables 50 deleteTables := make(map[string]any) 51 db.getTxn().deletedTableMap.Range(func(k, _ any) bool { 52 key := k.(tableKey) 53 if key.databaseId == db.databaseId { 54 deleteTables[key.name] = nil 55 } 56 return true 57 }) 58 db.getTxn().createMap.Range(func(k, _ any) bool { 59 key := k.(tableKey) 60 if key.databaseId == db.databaseId { 61 //if the table is deleted, do not save it. 62 if _, exist := deleteTables[key.name]; !exist { 63 rels = append(rels, key.name) 64 } 65 } 66 return true 67 }) 68 accountId, err := defines.GetAccountId(ctx) 69 if err != nil { 70 return nil, err 71 } 72 var catache *cache.CatalogCache 73 if !db.op.IsSnapOp() { 74 catache = db.getTxn().engine.getLatestCatalogCache() 75 } else { 76 catache, err = db.getTxn().engine.getOrCreateSnapCatalogCache( 77 ctx, 78 types.TimestampToTS(db.op.SnapshotTS())) 79 if err != nil { 80 return nil, err 81 } 82 } 83 tbls, _ := catache.Tables( 84 accountId, db.databaseId, db.op.SnapshotTS()) 85 for _, tbl := range tbls { 86 //if the table is deleted, do not save it. 87 if _, exist := deleteTables[tbl]; !exist { 88 rels = append(rels, tbl) 89 } 90 } 91 return rels, nil 92 } 93 94 func (db *txnDatabase) getTableNameById(ctx context.Context, id uint64) (string, error) { 95 tblName := "" 96 //first check the tableID is deleted or not 97 deleted := false 98 db.getTxn().deletedTableMap.Range(func(k, v any) bool { 99 key := k.(tableKey) 100 val := v.(uint64) 101 if key.databaseId == db.databaseId && val == id { 102 deleted = true 103 return false 104 } 105 return true 106 }) 107 if deleted { 108 return "", nil 109 } 110 db.getTxn().createMap.Range(func(k, v any) bool { 111 key := k.(tableKey) 112 val := v.(*txnTable) 113 if key.databaseId == db.databaseId && val.tableId == id { 114 tblName = key.name 115 return false 116 } 117 return true 118 }) 119 120 if tblName == "" { 121 accountId, err := defines.GetAccountId(ctx) 122 if err != nil { 123 return "", err 124 } 125 var catache *cache.CatalogCache 126 if !db.op.IsSnapOp() { 127 catache = db.getTxn().engine.getLatestCatalogCache() 128 } else { 129 catache, err = db.getTxn().engine.getOrCreateSnapCatalogCache( 130 ctx, 131 types.TimestampToTS(db.op.SnapshotTS())) 132 if err != nil { 133 return "", err 134 } 135 } 136 tbls, tblIds := catache.Tables( 137 accountId, db.databaseId, db.op.SnapshotTS()) 138 for idx, tblId := range tblIds { 139 if tblId == id { 140 tblName = tbls[idx] 141 break 142 } 143 } 144 } 145 return tblName, nil 146 } 147 148 func (db *txnDatabase) getRelationById(ctx context.Context, id uint64) (string, engine.Relation, error) { 149 tblName, err := db.getTableNameById(ctx, id) 150 if err != nil { 151 return "", nil, err 152 } 153 if tblName == "" { 154 return "", nil, nil 155 } 156 rel, _ := db.Relation(ctx, tblName, nil) 157 return tblName, rel, nil 158 } 159 160 func (db *txnDatabase) RelationByAccountID( 161 accountID uint32, 162 name string, 163 proc any) (engine.Relation, error) { 164 logDebugf(db.op.Txn(), "txnDatabase.RelationByAccountID table %s", name) 165 txn := db.getTxn() 166 if txn.op.Status() == txn2.TxnStatus_Aborted { 167 return nil, moerr.NewTxnClosedNoCtx(txn.op.Txn().ID) 168 } 169 170 key := genTableKey(accountID, name, db.databaseId) 171 // check the table is deleted or not 172 if _, exist := db.getTxn().deletedTableMap.Load(key); exist { 173 if strings.Contains(name, "_copy_") { 174 stackInfo := debug.Stack() 175 logutil.Error(moerr.NewParseError(context.Background(), "table %q does not exists", name).Error(), zap.String("Stack Trace", string(stackInfo))) 176 } 177 return nil, moerr.NewParseError(context.Background(), "table %q does not exist", name) 178 } 179 180 p := db.getTxn().proc 181 if proc != nil { 182 p = proc.(*process.Process) 183 } 184 185 rel := db.getTxn().getCachedTable(context.Background(), key) 186 if rel != nil { 187 rel.proc.Store(p) 188 return rel, nil 189 } 190 191 // get relation from the txn created tables cache: created by this txn 192 if v, ok := db.getTxn().createMap.Load(key); ok { 193 v.(*txnTable).proc.Store(p) 194 return v.(*txnTable), nil 195 } 196 197 // special tables 198 if db.databaseName == catalog.MO_CATALOG { 199 switch name { 200 case catalog.MO_DATABASE: 201 id := uint64(catalog.MO_DATABASE_ID) 202 defs := catalog.MoDatabaseTableDefs 203 return db.openSysTable(p, id, name, defs), nil 204 case catalog.MO_TABLES: 205 id := uint64(catalog.MO_TABLES_ID) 206 defs := catalog.MoTablesTableDefs 207 return db.openSysTable(p, id, name, defs), nil 208 case catalog.MO_COLUMNS: 209 id := uint64(catalog.MO_COLUMNS_ID) 210 defs := catalog.MoColumnsTableDefs 211 return db.openSysTable(p, id, name, defs), nil 212 } 213 } 214 item := &cache.TableItem{ 215 Name: name, 216 DatabaseId: db.databaseId, 217 AccountId: accountID, 218 Ts: db.op.SnapshotTS(), 219 } 220 var catache *cache.CatalogCache 221 var err error 222 if !db.op.IsSnapOp() { 223 catache = db.getTxn().engine.getLatestCatalogCache() 224 } else { 225 catache, err = db.getTxn().engine.getOrCreateSnapCatalogCache( 226 context.Background(), 227 types.TimestampToTS(db.op.SnapshotTS())) 228 if err != nil { 229 return nil, err 230 } 231 } 232 if ok := catache.GetTable(item); !ok { 233 logutil.Debugf("txnDatabase.Relation table %q(acc %d db %d) does not exist", 234 name, 235 accountID, 236 db.databaseId) 237 return nil, moerr.NewParseError(context.Background(), "table %q does not exist", name) 238 } 239 240 tbl := &txnTable{ 241 db: db, 242 accountId: item.AccountId, 243 tableId: item.Id, 244 version: item.Version, 245 tableName: item.Name, 246 defs: item.Defs, 247 tableDef: item.TableDef, 248 primaryIdx: item.PrimaryIdx, 249 primarySeqnum: item.PrimarySeqnum, 250 clusterByIdx: item.ClusterByIdx, 251 relKind: item.Kind, 252 viewdef: item.ViewDef, 253 comment: item.Comment, 254 partitioned: item.Partitioned, 255 partition: item.Partition, 256 createSql: item.CreateSql, 257 constraint: item.Constraint, 258 rowid: item.Rowid, 259 rowids: item.Rowids, 260 lastTS: txn.op.SnapshotTS(), 261 } 262 tbl.proc.Store(p) 263 264 db.getTxn().tableCache.tableMap.Store(key, tbl) 265 return tbl, nil 266 } 267 268 func (db *txnDatabase) Relation(ctx context.Context, name string, proc any) (engine.Relation, error) { 269 if db.databaseName == "test" && name == "bugt" && db.op.IsSnapOp() { 270 logutil.Infof("xxxx open relation, txn:%s", db.op.Txn().DebugString()) 271 } 272 logDebugf(db.op.Txn(), "txnDatabase.Relation table %s", name) 273 txn := db.getTxn() 274 if txn.op.Status() == txn2.TxnStatus_Aborted { 275 return nil, moerr.NewTxnClosedNoCtx(txn.op.Txn().ID) 276 } 277 accountId, err := defines.GetAccountId(ctx) 278 if err != nil { 279 return nil, err 280 } 281 key := genTableKey(accountId, name, db.databaseId) 282 // check the table is deleted or not 283 if _, exist := db.getTxn().deletedTableMap.Load(key); exist { 284 return nil, moerr.NewParseError(ctx, "table %q does not exist", name) 285 } 286 287 p := db.getTxn().proc 288 if proc != nil { 289 p = proc.(*process.Process) 290 } 291 292 rel := db.getTxn().getCachedTable(ctx, key) 293 if rel != nil { 294 rel.proc.Store(p) 295 return rel, nil 296 } 297 298 // get relation from the txn created tables cache: created by this txn 299 if v, ok := db.getTxn().createMap.Load(key); ok { 300 v.(*txnTable).proc.Store(p) 301 return v.(*txnTable), nil 302 } 303 304 // special tables 305 if db.databaseName == catalog.MO_CATALOG { 306 switch name { 307 case catalog.MO_DATABASE: 308 id := uint64(catalog.MO_DATABASE_ID) 309 defs := catalog.MoDatabaseTableDefs 310 return db.openSysTable(p, id, name, defs), nil 311 case catalog.MO_TABLES: 312 id := uint64(catalog.MO_TABLES_ID) 313 defs := catalog.MoTablesTableDefs 314 return db.openSysTable(p, id, name, defs), nil 315 case catalog.MO_COLUMNS: 316 id := uint64(catalog.MO_COLUMNS_ID) 317 defs := catalog.MoColumnsTableDefs 318 return db.openSysTable(p, id, name, defs), nil 319 } 320 } 321 item := &cache.TableItem{ 322 Name: name, 323 DatabaseId: db.databaseId, 324 AccountId: accountId, 325 Ts: db.op.SnapshotTS(), 326 } 327 var catache *cache.CatalogCache 328 if !db.op.IsSnapOp() { 329 catache = db.getTxn().engine.getLatestCatalogCache() 330 } else { 331 catache, err = db.getTxn().engine.getOrCreateSnapCatalogCache( 332 ctx, 333 types.TimestampToTS(db.op.SnapshotTS())) 334 if err != nil { 335 return nil, err 336 } 337 } 338 if ok := catache.GetTable(item); !ok { 339 logutil.Debugf("txnDatabase.Relation table %q(acc %d db %d) does not exist", 340 name, 341 accountId, 342 db.databaseId) 343 if strings.Contains(name, "_copy_") { 344 stackInfo := debug.Stack() 345 logutil.Error(moerr.NewParseError(context.Background(), "table %q does not exists", name).Error(), zap.String("Stack Trace", string(stackInfo))) 346 } 347 return nil, moerr.NewParseError(ctx, "table %q does not exist", name) 348 } 349 350 tbl := &txnTable{ 351 db: db, 352 accountId: item.AccountId, 353 tableId: item.Id, 354 version: item.Version, 355 tableName: item.Name, 356 defs: item.Defs, 357 tableDef: item.TableDef, 358 primaryIdx: item.PrimaryIdx, 359 primarySeqnum: item.PrimarySeqnum, 360 clusterByIdx: item.ClusterByIdx, 361 relKind: item.Kind, 362 viewdef: item.ViewDef, 363 comment: item.Comment, 364 partitioned: item.Partitioned, 365 partition: item.Partition, 366 createSql: item.CreateSql, 367 constraint: item.Constraint, 368 rowid: item.Rowid, 369 rowids: item.Rowids, 370 lastTS: txn.op.SnapshotTS(), 371 } 372 tbl.proc.Store(p) 373 374 db.getTxn().tableCache.tableMap.Store(key, tbl) 375 return tbl, nil 376 } 377 378 func (db *txnDatabase) Delete(ctx context.Context, name string) error { 379 var id uint64 380 var rowid types.Rowid 381 var rowids []types.Rowid 382 if db.op.IsSnapOp() { 383 return moerr.NewInternalErrorNoCtx("delete table in snapshot transaction") 384 } 385 accountId, err := defines.GetAccountId(ctx) 386 if err != nil { 387 return err 388 } 389 k := genTableKey(accountId, name, db.databaseId) 390 if v, ok := db.getTxn().createMap.Load(k); ok { 391 db.getTxn().createMap.Delete(k) 392 table := v.(*txnTable) 393 id = table.tableId 394 rowid = table.rowid 395 rowids = table.rowids 396 /* 397 Even if the created table in the createMap, there is an 398 INSERT entry in the CN workspace. We need add a DELETE 399 entry in the CN workspace to tell the TN to delete the 400 table. 401 CORNER CASE 402 begin; 403 create table t1; 404 drop table t1; 405 commit; 406 If we do not add DELETE entry in workspace, there is 407 a table t1 there after commit. 408 */ 409 } else if v, ok := db.getTxn().tableCache.tableMap.Load(k); ok { 410 table := v.(*txnTable) 411 id = table.tableId 412 db.getTxn().tableCache.tableMap.Delete(k) 413 rowid = table.rowid 414 rowids = table.rowids 415 } else { 416 item := &cache.TableItem{ 417 Name: name, 418 DatabaseId: db.databaseId, 419 AccountId: accountId, 420 Ts: db.op.SnapshotTS(), 421 } 422 if ok := db.getTxn().engine.getLatestCatalogCache().GetTable(item); !ok { 423 return moerr.GetOkExpectedEOB() 424 } 425 id = item.Id 426 rowid = item.Rowid 427 rowids = item.Rowids 428 } 429 bat, err := genDropTableTuple(rowid, id, db.databaseId, 430 name, db.databaseName, db.getTxn().proc.Mp()) 431 if err != nil { 432 return err 433 } 434 435 for _, store := range db.getTxn().tnStores { 436 if err := db.getTxn().WriteBatch( 437 DELETE, 0, catalog.MO_CATALOG_ID, catalog.MO_TABLES_ID, 438 catalog.MO_CATALOG, catalog.MO_TABLES, bat, store, -1, false, false); err != nil { 439 bat.Clean(db.getTxn().proc.Mp()) 440 return err 441 } 442 } 443 444 //Add writeBatch(delete,mo_columns) to filter table in mo_columns. 445 //Every row in writeBatch(delete,mo_columns) needs rowid 446 for _, rid := range rowids { 447 bat, err = genDropColumnTuple(rid, db.getTxn().proc.Mp()) 448 if err != nil { 449 return err 450 } 451 for _, store := range db.getTxn().tnStores { 452 if err = db.getTxn().WriteBatch( 453 DELETE, 0, catalog.MO_CATALOG_ID, catalog.MO_COLUMNS_ID, 454 catalog.MO_CATALOG, catalog.MO_COLUMNS, bat, store, -1, false, false); err != nil { 455 bat.Clean(db.getTxn().proc.Mp()) 456 return err 457 } 458 } 459 } 460 461 db.getTxn().deletedTableMap.Store(k, id) 462 return nil 463 } 464 465 func (db *txnDatabase) Truncate(ctx context.Context, name string) (uint64, error) { 466 var oldId uint64 467 var rowid types.Rowid 468 var v any 469 var ok bool 470 if db.op.IsSnapOp() { 471 return 0, moerr.NewInternalErrorNoCtx("truncate table in snapshot transaction") 472 } 473 newId, err := db.getTxn().allocateID(ctx) 474 if err != nil { 475 return 0, err 476 } 477 accountId, err := defines.GetAccountId(ctx) 478 if err != nil { 479 return 0, err 480 } 481 k := genTableKey(accountId, name, db.databaseId) 482 v, ok = db.getTxn().createMap.Load(k) 483 if !ok { 484 v, ok = db.getTxn().tableCache.tableMap.Load(k) 485 } 486 487 if ok { 488 txnTable := v.(*txnTable) 489 oldId = txnTable.tableId 490 txnTable.reset(newId) 491 rowid = txnTable.rowid 492 } else { 493 item := &cache.TableItem{ 494 Name: name, 495 DatabaseId: db.databaseId, 496 AccountId: accountId, 497 Ts: db.op.SnapshotTS(), 498 } 499 if ok := db.getTxn().engine.getLatestCatalogCache().GetTable(item); !ok { 500 return 0, moerr.GetOkExpectedEOB() 501 } 502 oldId = item.Id 503 rowid = item.Rowid 504 } 505 bat, err := genTruncateTableTuple(rowid, newId, db.databaseId, 506 genMetaTableName(oldId)+name, db.databaseName, db.getTxn().proc.Mp()) 507 if err != nil { 508 return 0, err 509 } 510 for _, store := range db.getTxn().tnStores { 511 if err := db.getTxn().WriteBatch(DELETE, 0, catalog.MO_CATALOG_ID, catalog.MO_TABLES_ID, 512 catalog.MO_CATALOG, catalog.MO_TABLES, bat, store, -1, false, true); err != nil { 513 bat.Clean(db.getTxn().proc.Mp()) 514 return 0, err 515 } 516 } 517 return newId, nil 518 } 519 520 func (db *txnDatabase) GetDatabaseId(ctx context.Context) string { 521 return strconv.FormatUint(db.databaseId, 10) 522 } 523 524 func (db *txnDatabase) GetCreateSql(ctx context.Context) string { 525 return db.databaseCreateSql 526 } 527 528 func (db *txnDatabase) IsSubscription(ctx context.Context) bool { 529 return db.databaseType == catalog.SystemDBTypeSubscription 530 } 531 532 func (db *txnDatabase) Create(ctx context.Context, name string, defs []engine.TableDef) error { 533 if db.op.IsSnapOp() { 534 return moerr.NewInternalErrorNoCtx("create table in snapshot transaction") 535 } 536 accountId, userId, roleId, err := getAccessInfo(ctx) 537 if err != nil { 538 return err 539 } 540 tableId, err := db.getTxn().allocateID(ctx) 541 if err != nil { 542 return err 543 } 544 tbl := new(txnTable) 545 tbl.accountId = accountId 546 tbl.rowid = types.DecodeFixed[types.Rowid](types.EncodeSlice([]uint64{tableId})) 547 tbl.comment = getTableComment(defs) 548 { 549 for _, def := range defs { // copy from tae 550 switch defVal := def.(type) { 551 case *engine.PropertiesDef: 552 for _, property := range defVal.Properties { 553 switch strings.ToLower(property.Key) { 554 case catalog.SystemRelAttr_Comment: // Watch priority over commentDef 555 tbl.comment = property.Value 556 case catalog.SystemRelAttr_Kind: 557 tbl.relKind = property.Value 558 case catalog.SystemRelAttr_CreateSQL: 559 tbl.createSql = property.Value // I don't trust this information. 560 default: 561 } 562 } 563 case *engine.ViewDef: 564 tbl.viewdef = defVal.View 565 case *engine.PartitionDef: 566 tbl.partitioned = defVal.Partitioned 567 tbl.partition = defVal.Partition 568 case *engine.ConstraintDef: 569 tbl.constraint, err = defVal.MarshalBinary() 570 if err != nil { 571 return err 572 } 573 } 574 } 575 } 576 cols, err := genColumns(accountId, name, db.databaseName, tableId, db.databaseId, defs) 577 if err != nil { 578 return err 579 } 580 { 581 sql := getSql(ctx) 582 bat, err := genCreateTableTuple( 583 tbl, sql, accountId, userId, roleId, name, 584 tableId, db.databaseId, db.databaseName, 585 tbl.rowid, true, db.getTxn().proc.Mp()) 586 if err != nil { 587 return err 588 } 589 for _, store := range db.getTxn().tnStores { 590 if err := db.getTxn().WriteBatch(INSERT, 0, catalog.MO_CATALOG_ID, catalog.MO_TABLES_ID, 591 catalog.MO_CATALOG, catalog.MO_TABLES, bat, store, -1, true, false); err != nil { 592 bat.Clean(db.getTxn().proc.Mp()) 593 return err 594 } 595 } 596 } 597 tbl.primaryIdx = -1 598 tbl.primarySeqnum = -1 599 tbl.clusterByIdx = -1 600 tbl.rowids = make([]types.Rowid, len(cols)) 601 for i, col := range cols { 602 tbl.rowids[i] = db.getTxn().genRowId() 603 bat, err := genCreateColumnTuple(col, tbl.rowids[i], true, 604 db.getTxn().proc.Mp()) 605 if err != nil { 606 return err 607 } 608 for _, store := range db.getTxn().tnStores { 609 if err := db.getTxn().WriteBatch( 610 INSERT, 0, catalog.MO_CATALOG_ID, catalog.MO_COLUMNS_ID, 611 catalog.MO_CATALOG, catalog.MO_COLUMNS, bat, store, -1, true, false); err != nil { 612 bat.Clean(db.getTxn().proc.Mp()) 613 return err 614 } 615 } 616 if col.constraintType == catalog.SystemColPKConstraint { 617 tbl.primaryIdx = i 618 tbl.primarySeqnum = i 619 } 620 if col.isClusterBy == 1 { 621 tbl.clusterByIdx = i 622 } 623 } 624 tbl.db = db 625 tbl.defs = defs 626 tbl.tableName = name 627 tbl.tableId = tableId 628 tbl.GetTableDef(ctx) 629 key := genTableKey(accountId, name, db.databaseId) 630 db.getTxn().addCreateTable(key, tbl) 631 //CORNER CASE 632 //begin; 633 //create table t1(a int); 634 //drop table t1; //t1 is in deleteTableMap now. 635 //select * from t1; //t1 does not exist. 636 //create table t1(a int); //t1 does not exist. t1 can be created again. 637 // t1 needs be deleted from deleteTableMap 638 db.getTxn().deletedTableMap.Delete(key) 639 return nil 640 } 641 642 func (db *txnDatabase) openSysTable(p *process.Process, id uint64, name string, 643 defs []engine.TableDef) engine.Relation { 644 tbl := &txnTable{ 645 //AccountID for mo_tables, mo_database, mo_columns is always 0. 646 accountId: 0, 647 db: db, 648 tableId: id, 649 tableName: name, 650 defs: defs, 651 primaryIdx: 0, 652 primarySeqnum: db.getEng().getLatestCatalogCache().GetTableById(db.databaseId, id).PrimarySeqnum, 653 clusterByIdx: -1, 654 } 655 switch name { 656 case catalog.MO_DATABASE: 657 tbl.constraint = catalog.MoDatabaseConstraint 658 case catalog.MO_TABLES: 659 tbl.constraint = catalog.MoTableConstraint 660 case catalog.MO_COLUMNS: 661 tbl.constraint = catalog.MoColumnConstraint 662 } 663 tbl.GetTableDef(context.TODO()) 664 tbl.proc.Store(p) 665 return tbl 666 }