github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/rpc/handle.go (about) 1 // Copyright 2021 - 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 rpc 16 17 import ( 18 "bytes" 19 "context" 20 "fmt" 21 "os" 22 "sync" 23 "syscall" 24 "time" 25 26 "github.com/google/shlex" 27 "github.com/matrixorigin/matrixone/pkg/catalog" 28 "github.com/matrixorigin/matrixone/pkg/common/moerr" 29 "github.com/matrixorigin/matrixone/pkg/container/batch" 30 "github.com/matrixorigin/matrixone/pkg/container/types" 31 "github.com/matrixorigin/matrixone/pkg/container/vector" 32 "github.com/matrixorigin/matrixone/pkg/defines" 33 "github.com/matrixorigin/matrixone/pkg/logutil" 34 apipb "github.com/matrixorigin/matrixone/pkg/pb/api" 35 "github.com/matrixorigin/matrixone/pkg/pb/timestamp" 36 "github.com/matrixorigin/matrixone/pkg/pb/txn" 37 "github.com/matrixorigin/matrixone/pkg/util/trace" 38 catalog2 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/catalog" 39 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common" 40 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/containers" 41 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/dataio/blockio" 42 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/db" 43 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/iface/rpchandle" 44 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/logtail" 45 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/moengine" 46 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/options" 47 "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tasks" 48 49 "go.uber.org/zap" 50 ) 51 52 // TODO::GC the abandoned txn. 53 type Handle struct { 54 eng moengine.TxnEngine 55 mu struct { 56 sync.RWMutex 57 //map txn id to txnContext. 58 txnCtxs map[string]*txnContext 59 } 60 jobScheduler tasks.JobScheduler 61 } 62 63 var _ rpchandle.Handler = (*Handle)(nil) 64 65 type txnContext struct { 66 //createAt is used to GC the abandoned txn. 67 createAt time.Time 68 meta txn.TxnMeta 69 reqs []any 70 //the table to create by this txn. 71 toCreate map[uint64]*catalog2.Schema 72 } 73 74 func (h *Handle) GetTxnEngine() moengine.TxnEngine { 75 return h.eng 76 } 77 78 func NewTAEHandle(path string, opt *options.Options) *Handle { 79 if path == "" { 80 path = "./store" 81 } 82 tae, err := openTAE(path, opt) 83 if err != nil { 84 panic(err) 85 } 86 87 h := &Handle{ 88 eng: moengine.NewEngine(tae), 89 jobScheduler: tasks.NewParallelJobScheduler(100), 90 } 91 h.mu.txnCtxs = make(map[string]*txnContext) 92 return h 93 } 94 95 func (h *Handle) HandleCommit( 96 ctx context.Context, 97 meta txn.TxnMeta) (err error) { 98 h.mu.RLock() 99 txnCtx, ok := h.mu.txnCtxs[string(meta.GetID())] 100 h.mu.RUnlock() 101 //Handle precommit-write command for 1PC 102 var txn moengine.Txn 103 if ok { 104 for _, e := range txnCtx.reqs { 105 switch req := e.(type) { 106 case *db.CreateDatabaseReq: 107 err = h.HandleCreateDatabase( 108 ctx, 109 meta, 110 req, 111 &db.CreateDatabaseResp{}, 112 ) 113 case *db.CreateRelationReq: 114 err = h.HandleCreateRelation( 115 ctx, 116 meta, 117 req, 118 &db.CreateRelationResp{}, 119 ) 120 case *db.DropDatabaseReq: 121 err = h.HandleDropDatabase( 122 ctx, 123 meta, 124 req, 125 &db.DropDatabaseResp{}, 126 ) 127 case *db.DropOrTruncateRelationReq: 128 err = h.HandleDropOrTruncateRelation( 129 ctx, 130 meta, 131 req, 132 &db.DropOrTruncateRelationResp{}, 133 ) 134 case *db.UpdateConstraintReq: 135 err = h.HandleUpdateConstraint( 136 ctx, 137 meta, 138 req, 139 &db.UpdateConstraintResp{}, 140 ) 141 case *db.WriteReq: 142 err = h.HandleWrite( 143 ctx, 144 meta, 145 req, 146 &db.WriteResp{}, 147 ) 148 default: 149 panic(moerr.NewNYI(ctx, "Pls implement me")) 150 } 151 //Need to roll back the txn. 152 if err != nil { 153 txn, _ = h.eng.GetTxnByID(meta.GetID()) 154 txn.Rollback() 155 return 156 } 157 } 158 } 159 txn, err = h.eng.GetTxnByID(meta.GetID()) 160 if err != nil { 161 return 162 } 163 //if txn is 2PC ,need to set commit timestamp passed by coordinator. 164 if txn.Is2PC() { 165 txn.SetCommitTS(types.TimestampToTS(meta.GetCommitTS())) 166 } 167 err = txn.Commit() 168 169 //delete the txn's context. 170 h.mu.Lock() 171 delete(h.mu.txnCtxs, string(meta.GetID())) 172 h.mu.Unlock() 173 return 174 } 175 176 func (h *Handle) HandleRollback( 177 ctx context.Context, 178 meta txn.TxnMeta) (err error) { 179 h.mu.Lock() 180 _, ok := h.mu.txnCtxs[string(meta.GetID())] 181 delete(h.mu.txnCtxs, string(meta.GetID())) 182 h.mu.Unlock() 183 //Rollback after pre-commit write. 184 if ok { 185 return 186 } 187 var txn moengine.Txn 188 txn, err = h.eng.GetTxnByID(meta.GetID()) 189 190 if err != nil { 191 return err 192 } 193 err = txn.Rollback() 194 return 195 } 196 197 func (h *Handle) HandleCommitting( 198 ctx context.Context, 199 meta txn.TxnMeta) (err error) { 200 var txn moengine.Txn 201 txn, err = h.eng.GetTxnByID(meta.GetID()) 202 if err != nil { 203 return err 204 } 205 txn.SetCommitTS(types.TimestampToTS(meta.GetCommitTS())) 206 err = txn.Committing() 207 return 208 } 209 210 func (h *Handle) HandlePrepare( 211 ctx context.Context, 212 meta txn.TxnMeta) (pts timestamp.Timestamp, err error) { 213 h.mu.RLock() 214 txnCtx, ok := h.mu.txnCtxs[string(meta.GetID())] 215 h.mu.RUnlock() 216 var txn moengine.Txn 217 if ok { 218 //handle pre-commit write for 2PC 219 for _, e := range txnCtx.reqs { 220 switch req := e.(type) { 221 case *db.CreateDatabaseReq: 222 err = h.HandleCreateDatabase( 223 ctx, 224 meta, 225 req, 226 &db.CreateDatabaseResp{}, 227 ) 228 case *db.CreateRelationReq: 229 err = h.HandleCreateRelation( 230 ctx, 231 meta, 232 req, 233 &db.CreateRelationResp{}, 234 ) 235 case *db.DropDatabaseReq: 236 err = h.HandleDropDatabase( 237 ctx, 238 meta, 239 req, 240 &db.DropDatabaseResp{}, 241 ) 242 case *db.DropOrTruncateRelationReq: 243 err = h.HandleDropOrTruncateRelation( 244 ctx, 245 meta, 246 req, 247 &db.DropOrTruncateRelationResp{}, 248 ) 249 case *db.UpdateConstraintReq: 250 err = h.HandleUpdateConstraint( 251 ctx, 252 meta, 253 req, 254 &db.UpdateConstraintResp{}, 255 ) 256 case *db.WriteReq: 257 err = h.HandleWrite( 258 ctx, 259 meta, 260 req, 261 &db.WriteResp{}, 262 ) 263 default: 264 panic(moerr.NewNYI(ctx, "Pls implement me")) 265 } 266 //need to rollback the txn 267 if err != nil { 268 txn, _ = h.eng.GetTxnByID(meta.GetID()) 269 txn.Rollback() 270 return 271 } 272 } 273 } 274 txn, err = h.eng.GetTxnByID(meta.GetID()) 275 if err != nil { 276 return timestamp.Timestamp{}, err 277 } 278 participants := make([]uint64, 0, len(meta.GetDNShards())) 279 for _, shard := range meta.GetDNShards() { 280 participants = append(participants, shard.GetShardID()) 281 } 282 txn.SetParticipants(participants) 283 var ts types.TS 284 ts, err = txn.Prepare() 285 pts = ts.ToTimestamp() 286 //delete the txn's context. 287 h.mu.Lock() 288 delete(h.mu.txnCtxs, string(meta.GetID())) 289 h.mu.Unlock() 290 return 291 } 292 293 func (h *Handle) HandleStartRecovery( 294 ctx context.Context, 295 ch chan txn.TxnMeta) { 296 //panic(moerr.NewNYI("HandleStartRecovery is not implemented yet")) 297 //TODO:: 1. Get the 2PC transactions which be in prepared or 298 // committing state from txn engine's recovery. 299 // 2. Feed these transaction into ch. 300 close(ch) 301 } 302 303 func (h *Handle) HandleClose(ctx context.Context) (err error) { 304 //FIXME::should wait txn request's job done? 305 h.jobScheduler.Stop() 306 return h.eng.Close() 307 } 308 309 func (h *Handle) HandleDestroy(ctx context.Context) (err error) { 310 //FIXME::should wait txn request's job done? 311 h.jobScheduler.Stop() 312 return h.eng.Destroy() 313 } 314 315 func (h *Handle) HandleGetLogTail( 316 ctx context.Context, 317 meta txn.TxnMeta, 318 req apipb.SyncLogTailReq, 319 resp *apipb.SyncLogTailResp) (err error) { 320 tae := h.eng.GetTAE(context.Background()) 321 res, err := logtail.HandleSyncLogTailReq( 322 ctx, 323 tae.BGCheckpointRunner, 324 tae.LogtailMgr, 325 tae.Catalog, 326 req, 327 true) 328 if err != nil { 329 return err 330 } 331 *resp = res 332 return nil 333 } 334 335 func (h *Handle) HandleFlushTable( 336 ctx context.Context, 337 meta txn.TxnMeta, 338 req db.FlushTable, 339 resp *apipb.SyncLogTailResp) (err error) { 340 341 // We use current TS instead of transaction ts. 342 // Here, the point of this handle function is to trigger a flush 343 // via mo_ctl. We mimic the behaviour of a real background flush 344 // currTs := types.TimestampToTS(meta.GetSnapshotTS()) 345 currTs := types.BuildTS(time.Now().UTC().UnixNano(), 0) 346 347 err = h.eng.FlushTable(ctx, 348 req.AccessInfo.AccountID, 349 req.DatabaseID, 350 req.TableID, 351 currTs) 352 return err 353 } 354 355 func (h *Handle) HandleForceCheckpoint( 356 ctx context.Context, 357 meta txn.TxnMeta, 358 req db.Checkpoint, 359 resp *apipb.SyncLogTailResp) (err error) { 360 361 timeout := req.FlushDuration 362 363 currTs := types.BuildTS(time.Now().UTC().UnixNano(), 0) 364 365 err = h.eng.ForceCheckpoint(ctx, 366 currTs, timeout) 367 return err 368 } 369 370 func (h *Handle) HandleInspectDN( 371 ctx context.Context, 372 meta txn.TxnMeta, 373 req db.InspectDN, 374 resp *db.InspectResp) (err error) { 375 tae := h.eng.GetTAE(context.Background()) 376 args, _ := shlex.Split(req.Operation) 377 logutil.Info("Inspect", zap.Strings("args", args)) 378 b := &bytes.Buffer{} 379 380 inspectCtx := &inspectContext{ 381 db: tae, 382 acinfo: &req.AccessInfo, 383 args: args, 384 out: b, 385 resp: resp, 386 } 387 RunInspect(inspectCtx) 388 resp.Message = b.String() 389 return nil 390 } 391 392 func (h *Handle) startLoadJobs( 393 ctx context.Context, 394 meta txn.TxnMeta, 395 req *db.WriteReq, 396 ) (err error) { 397 var locations []string 398 var columnTypes []types.Type 399 var columnNames []string 400 var isNull []bool 401 var jobIds []string 402 var columnIdx int 403 if req.Type == db.EntryInsert { 404 //for loading primary keys of blocks 405 locations = append(locations, req.MetaLocs...) 406 columnTypes = append(columnTypes, req.Schema.GetSingleSortKey().Type) 407 columnNames = append(columnNames, req.Schema.GetSingleSortKey().Name) 408 columnIdx = req.Schema.GetSingleSortKeyIdx() 409 isNull = append(isNull, false) 410 req.Jobs = make([]*tasks.Job, len(req.MetaLocs)) 411 req.JobRes = make([]*tasks.JobResult, len(req.Jobs)) 412 for i := range req.MetaLocs { 413 jobIds = append(jobIds, 414 fmt.Sprintf("load-primarykey-%s", req.MetaLocs[i])) 415 } 416 } else { 417 //for loading deleted rowid. 418 locations = append(locations, req.DeltaLocs...) 419 columnTypes = append(columnTypes, types.T_Rowid.ToType()) 420 columnIdx = 0 421 columnNames = append(columnNames, catalog.Row_ID) 422 isNull = append(isNull, false) 423 req.Jobs = make([]*tasks.Job, len(req.DeltaLocs)) 424 req.JobRes = make([]*tasks.JobResult, len(req.Jobs)) 425 for i := range req.DeltaLocs { 426 jobIds = append(jobIds, 427 fmt.Sprintf("load-deleted-rowid-%s", req.DeltaLocs[i])) 428 } 429 } 430 //start loading jobs asynchronously,should create a new root context. 431 nctx := context.Background() 432 if deadline, ok := ctx.Deadline(); ok { 433 nctx, req.Cancel = context.WithTimeout(nctx, time.Until(deadline)) 434 } 435 for i, v := range locations { 436 nctx = context.WithValue(nctx, db.LocationKey{}, v) 437 req.Jobs[i] = tasks.NewJob( 438 jobIds[i], 439 nctx, 440 func(ctx context.Context) (jobR *tasks.JobResult) { 441 jobR = &tasks.JobResult{} 442 loc, ok := ctx.Value(db.LocationKey{}).(string) 443 if !ok { 444 panic(moerr.NewInternalErrorNoCtx("Miss Location")) 445 } 446 //reader, err := blockio.NewReader(ctx, 447 // h.eng.GetTAE(ctx).Fs, req.MetaLocs[i]) 448 reader, err := blockio.NewReader(ctx, 449 h.eng.GetTAE(ctx).Fs, loc) 450 if err != nil { 451 jobR.Err = err 452 return 453 } 454 meta, err := reader.ReadMeta(nil) 455 if err != nil { 456 jobR.Err = err 457 return 458 } 459 bat, err := reader.LoadBlkColumnsByMetaAndIdx( 460 columnTypes, 461 columnNames, 462 isNull, 463 meta, 464 columnIdx, 465 ) 466 if err != nil { 467 jobR.Err = err 468 return 469 } 470 jobR.Res = bat.Vecs[0] 471 return 472 }, 473 ) 474 if err = h.jobScheduler.Schedule(req.Jobs[i]); err != nil { 475 return err 476 } 477 } 478 return 479 } 480 481 // EvaluateTxnRequest only evaluate the request ,do not change the state machine of TxnEngine. 482 func (h *Handle) EvaluateTxnRequest( 483 ctx context.Context, 484 meta txn.TxnMeta, 485 ) (err error) { 486 h.mu.RLock() 487 txnCtx := h.mu.txnCtxs[string(meta.GetID())] 488 h.mu.RUnlock() 489 for _, e := range txnCtx.reqs { 490 if r, ok := e.(*db.WriteReq); ok { 491 if r.FileName != "" { 492 if r.Type == db.EntryInsert { 493 v, ok := txnCtx.toCreate[r.TableID] 494 if !ok { 495 txn, err := h.eng.GetOrCreateTxnWithMeta( 496 nil, 497 meta.GetID(), 498 types.TimestampToTS(meta.GetSnapshotTS())) 499 if err != nil { 500 return err 501 } 502 dbase, err := h.eng.GetDatabaseByID(ctx, r.DatabaseId, txn) 503 if err != nil { 504 return err 505 } 506 tb, err := dbase.GetRelationByID(ctx, r.TableID) 507 if err != nil { 508 return err 509 } 510 r.Schema = tb.GetSchema(ctx) 511 } else { 512 r.Schema = v 513 } 514 if r.Schema.HasPK() { 515 //start to load primary keys 516 err = h.startLoadJobs(ctx, meta, r) 517 if err != nil { 518 return 519 } 520 } 521 continue 522 } 523 //start to load deleted row ids 524 err = h.startLoadJobs(ctx, meta, r) 525 if err != nil { 526 return 527 } 528 529 } 530 } 531 } 532 return 533 } 534 535 func (h *Handle) CacheTxnRequest( 536 ctx context.Context, 537 meta txn.TxnMeta, 538 req any, 539 rsp any) (err error) { 540 h.mu.Lock() 541 txnCtx, ok := h.mu.txnCtxs[string(meta.GetID())] 542 if !ok { 543 txnCtx = &txnContext{ 544 createAt: time.Now(), 545 meta: meta, 546 toCreate: make(map[uint64]*catalog2.Schema), 547 } 548 h.mu.txnCtxs[string(meta.GetID())] = txnCtx 549 } 550 h.mu.Unlock() 551 txnCtx.reqs = append(txnCtx.reqs, req) 552 if r, ok := req.(*db.CreateRelationReq); ok { 553 // Does this place need 554 schema, err := moengine.DefsToSchema(r.Name, r.Defs) 555 if err != nil { 556 return err 557 } 558 txnCtx.toCreate[r.RelationId] = schema 559 } 560 return nil 561 } 562 563 func (h *Handle) HandlePreCommitWrite( 564 ctx context.Context, 565 meta txn.TxnMeta, 566 req apipb.PrecommitWriteCmd, 567 resp *apipb.SyncLogTailResp) (err error) { 568 var e any 569 570 es := req.EntryList 571 572 for len(es) > 0 { 573 e, es, err = catalog.ParseEntryList(es) 574 if err != nil { 575 return err 576 } 577 switch cmds := e.(type) { 578 case []catalog.CreateDatabase: 579 for _, cmd := range cmds { 580 req := &db.CreateDatabaseReq{ 581 Name: cmd.Name, 582 CreateSql: cmd.CreateSql, 583 DatabaseId: cmd.DatabaseId, 584 AccessInfo: db.AccessInfo{ 585 UserID: cmd.Creator, 586 RoleID: cmd.Owner, 587 AccountID: cmd.AccountId, 588 }, 589 } 590 if err = h.CacheTxnRequest(ctx, meta, req, 591 new(db.CreateDatabaseResp)); err != nil { 592 return err 593 } 594 } 595 case []catalog.CreateTable: 596 for _, cmd := range cmds { 597 req := &db.CreateRelationReq{ 598 AccessInfo: db.AccessInfo{ 599 UserID: cmd.Creator, 600 RoleID: cmd.Owner, 601 AccountID: cmd.AccountId, 602 }, 603 Name: cmd.Name, 604 RelationId: cmd.TableId, 605 DatabaseName: cmd.DatabaseName, 606 DatabaseID: cmd.DatabaseId, 607 Defs: cmd.Defs, 608 } 609 if err = h.CacheTxnRequest(ctx, meta, req, 610 new(db.CreateRelationResp)); err != nil { 611 return err 612 } 613 } 614 case []catalog.UpdateConstraint: 615 for _, cmd := range cmds { 616 req := &db.UpdateConstraintReq{ 617 TableName: cmd.TableName, 618 TableId: cmd.TableId, 619 DatabaseName: cmd.DatabaseName, 620 DatabaseId: cmd.DatabaseId, 621 Constraint: cmd.Constraint, 622 } 623 if err = h.CacheTxnRequest(ctx, meta, req, 624 new(db.UpdateConstraintResp)); err != nil { 625 return err 626 } 627 } 628 case []catalog.DropDatabase: 629 for _, cmd := range cmds { 630 req := &db.DropDatabaseReq{ 631 Name: cmd.Name, 632 ID: cmd.Id, 633 } 634 if err = h.CacheTxnRequest(ctx, meta, req, 635 new(db.DropDatabaseResp)); err != nil { 636 return err 637 } 638 } 639 case []catalog.DropOrTruncateTable: 640 for _, cmd := range cmds { 641 req := &db.DropOrTruncateRelationReq{ 642 IsDrop: cmd.IsDrop, 643 Name: cmd.Name, 644 ID: cmd.Id, 645 NewId: cmd.NewId, 646 DatabaseName: cmd.DatabaseName, 647 DatabaseID: cmd.DatabaseId, 648 } 649 if err = h.CacheTxnRequest(ctx, meta, req, 650 new(db.DropOrTruncateRelationResp)); err != nil { 651 return err 652 } 653 } 654 case *apipb.Entry: 655 //Handle DML 656 pe := e.(*apipb.Entry) 657 moBat, err := batch.ProtoBatchToBatch(pe.GetBat()) 658 if err != nil { 659 panic(err) 660 } 661 req := &db.WriteReq{ 662 Type: db.EntryType(pe.EntryType), 663 DatabaseId: pe.GetDatabaseId(), 664 TableID: pe.GetTableId(), 665 DatabaseName: pe.GetDatabaseName(), 666 TableName: pe.GetTableName(), 667 FileName: pe.GetFileName(), 668 Batch: moBat, 669 } 670 if req.FileName != "" { 671 rows := catalog.GenRows(req.Batch) 672 for _, row := range rows { 673 if req.Type == db.EntryInsert { 674 //req.Blks[i] = row[catalog.BLOCKMETA_ID_ON_FS_IDX].(uint64) 675 //req.MetaLocs[i] = string(row[catalog.BLOCKMETA_METALOC_ON_FS_IDX].([]byte)) 676 req.MetaLocs = append(req.MetaLocs, 677 string(row[0].([]byte))) 678 } else { 679 //req.DeltaLocs[i] = string(row[0].([]byte)) 680 req.DeltaLocs = append(req.DeltaLocs, 681 string(row[0].([]byte))) 682 } 683 } 684 } 685 if err = h.CacheTxnRequest(ctx, meta, req, 686 new(db.WriteResp)); err != nil { 687 return err 688 } 689 default: 690 panic(moerr.NewNYI(ctx, "")) 691 } 692 } 693 //evaluate all the txn requests. 694 return h.EvaluateTxnRequest(ctx, meta) 695 } 696 697 //Handle DDL commands. 698 699 func (h *Handle) HandleCreateDatabase( 700 ctx context.Context, 701 meta txn.TxnMeta, 702 req *db.CreateDatabaseReq, 703 resp *db.CreateDatabaseResp) (err error) { 704 _, span := trace.Start(ctx, "HandleCreateDatabase") 705 defer span.End() 706 707 txn, err := h.eng.GetOrCreateTxnWithMeta(nil, meta.GetID(), 708 types.TimestampToTS(meta.GetSnapshotTS())) 709 if err != nil { 710 return err 711 } 712 713 logutil.Infof("[precommit] create database: %+v\n txn: %s\n", req, txn.String()) 714 defer func() { 715 logutil.Infof("[precommit] create database end txn: %s\n", txn.String()) 716 }() 717 718 ctx = context.WithValue(ctx, defines.TenantIDKey{}, req.AccessInfo.AccountID) 719 ctx = context.WithValue(ctx, defines.UserIDKey{}, req.AccessInfo.UserID) 720 ctx = context.WithValue(ctx, defines.RoleIDKey{}, req.AccessInfo.RoleID) 721 err = h.eng.CreateDatabaseWithID(ctx, req.Name, req.CreateSql, req.DatabaseId, txn) 722 if err != nil { 723 return 724 } 725 resp.ID = req.DatabaseId 726 return 727 } 728 729 func (h *Handle) HandleDropDatabase( 730 ctx context.Context, 731 meta txn.TxnMeta, 732 req *db.DropDatabaseReq, 733 resp *db.DropDatabaseResp) (err error) { 734 735 txn, err := h.eng.GetOrCreateTxnWithMeta(nil, meta.GetID(), 736 types.TimestampToTS(meta.GetSnapshotTS())) 737 if err != nil { 738 return err 739 } 740 741 logutil.Infof("[precommit] drop database: %+v\n txn: %s\n", req, txn.String()) 742 defer func() { 743 logutil.Infof("[precommit] drop database end: %s\n", txn.String()) 744 }() 745 746 if err = h.eng.DropDatabaseByID(ctx, req.ID, txn); err != nil { 747 return 748 } 749 resp.ID = req.ID 750 return 751 } 752 753 func (h *Handle) HandleCreateRelation( 754 ctx context.Context, 755 meta txn.TxnMeta, 756 req *db.CreateRelationReq, 757 resp *db.CreateRelationResp) (err error) { 758 759 txn, err := h.eng.GetOrCreateTxnWithMeta(nil, meta.GetID(), 760 types.TimestampToTS(meta.GetSnapshotTS())) 761 if err != nil { 762 return 763 } 764 765 logutil.Infof("[precommit] create relation: %+v\n txn: %s\n", req, txn.String()) 766 defer func() { 767 logutil.Infof("[precommit] create relation end txn: %s\n", txn.String()) 768 }() 769 770 ctx = context.WithValue(ctx, defines.TenantIDKey{}, req.AccessInfo.AccountID) 771 ctx = context.WithValue(ctx, defines.UserIDKey{}, req.AccessInfo.UserID) 772 ctx = context.WithValue(ctx, defines.RoleIDKey{}, req.AccessInfo.RoleID) 773 db, err := h.eng.GetDatabase(ctx, req.DatabaseName, txn) 774 if err != nil { 775 return 776 } 777 778 err = db.CreateRelationWithID(ctx, req.Name, req.RelationId, req.Defs) 779 if err != nil { 780 return 781 } 782 783 resp.ID = req.RelationId 784 return 785 } 786 787 func (h *Handle) HandleDropOrTruncateRelation( 788 ctx context.Context, 789 meta txn.TxnMeta, 790 req *db.DropOrTruncateRelationReq, 791 resp *db.DropOrTruncateRelationResp) (err error) { 792 793 txn, err := h.eng.GetOrCreateTxnWithMeta(nil, meta.GetID(), 794 types.TimestampToTS(meta.GetSnapshotTS())) 795 if err != nil { 796 return 797 } 798 799 logutil.Infof("[precommit] drop/truncate relation: %+v\n txn: %s\n", req, txn.String()) 800 defer func() { 801 logutil.Infof("[precommit] drop/truncate relation end txn: %s\n", txn.String()) 802 }() 803 804 db, err := h.eng.GetDatabaseByID(ctx, req.DatabaseID, txn) 805 if err != nil { 806 return 807 } 808 809 if req.IsDrop { 810 err = db.DropRelationByID(ctx, req.ID) 811 if err != nil { 812 return 813 } 814 return 815 } 816 err = db.TruncateRelationByID(ctx, req.ID, req.NewId) 817 return err 818 } 819 820 // HandleWrite Handle DML commands 821 func (h *Handle) HandleWrite( 822 ctx context.Context, 823 meta txn.TxnMeta, 824 req *db.WriteReq, 825 resp *db.WriteResp) (err error) { 826 defer func() { 827 if req.Cancel != nil { 828 req.Cancel() 829 } 830 }() 831 txn, err := h.eng.GetOrCreateTxnWithMeta(nil, meta.GetID(), 832 types.TimestampToTS(meta.GetSnapshotTS())) 833 if err != nil { 834 return 835 } 836 837 logutil.Infof("[precommit] handle write typ: %v, %d-%s, %d-%s\n txn: %s\n", 838 req.Type, req.TableID, 839 req.TableName, req.DatabaseId, req.DatabaseName, 840 txn.String(), 841 ) 842 logutil.Debugf("[precommit] write batch: %s\n", debugMoBatch(req.Batch)) 843 defer func() { 844 logutil.Infof("[precommit] handle write end txn: %s\n", txn.String()) 845 }() 846 847 dbase, err := h.eng.GetDatabaseByID(ctx, req.DatabaseId, txn) 848 if err != nil { 849 return 850 } 851 852 tb, err := dbase.GetRelationByID(ctx, req.TableID) 853 if err != nil { 854 return 855 } 856 857 if req.Type == db.EntryInsert { 858 //Add blocks which had been bulk-loaded into S3 into table. 859 if req.FileName != "" { 860 //wait for loading primary key done. 861 var pkVecs []containers.Vector 862 for i, job := range req.Jobs { 863 req.JobRes[i] = job.WaitDone() 864 if req.JobRes[i].Err != nil { 865 return req.JobRes[i].Err 866 } 867 pkVecs = append( 868 pkVecs, 869 req.JobRes[i].Res.(containers.Vector)) 870 } 871 err = tb.AddBlksWithMetaLoc( 872 ctx, 873 pkVecs, 874 req.FileName, 875 req.MetaLocs, 876 0) 877 return 878 } 879 //Appends a batch of data into table. 880 err = tb.Write(ctx, req.Batch) 881 return 882 } 883 //handle delete 884 if req.FileName != "" { 885 //wait for loading deleted row-id done. 886 for i, job := range req.Jobs { 887 req.JobRes[i] = job.WaitDone() 888 if req.JobRes[i].Err != nil { 889 return req.JobRes[i].Err 890 } 891 rowidVec := req.JobRes[i].Res.(containers.Vector) 892 //FIXME::?? 893 //defer taeVec.Close() 894 //TODO::check whether rowid is generated by DN in debug mode. 895 // IsGeneratedByDN(rowidVec) 896 tb.DeleteByPhyAddrKeys(ctx, containers.UnmarshalToMoVec(rowidVec)) 897 } 898 return 899 } 900 err = tb.DeleteByPhyAddrKeys(ctx, req.Batch.GetVector(0)) 901 return 902 } 903 904 func (h *Handle) HandleUpdateConstraint( 905 ctx context.Context, 906 meta txn.TxnMeta, 907 req *db.UpdateConstraintReq, 908 resp *db.UpdateConstraintResp) (err error) { 909 txn, err := h.eng.GetOrCreateTxnWithMeta(nil, meta.GetID(), 910 types.TimestampToTS(meta.GetSnapshotTS())) 911 if err != nil { 912 return err 913 } 914 915 cstr := req.Constraint 916 req.Constraint = nil 917 logutil.Infof("[precommit] update cstr: %+v cstr %d bytes\n txn: %s\n", req, len(cstr), txn.String()) 918 919 dbase, err := h.eng.GetDatabaseByID(ctx, req.DatabaseId, txn) 920 if err != nil { 921 return 922 } 923 924 tbl, err := dbase.GetRelationByID(ctx, req.TableId) 925 if err != nil { 926 return 927 } 928 929 tbl.UpdateConstraintWithBin(ctx, cstr) 930 931 return nil 932 } 933 934 func vec2Str[T any](vec []T, v *vector.Vector) string { 935 var w bytes.Buffer 936 _, _ = w.WriteString(fmt.Sprintf("[%d]: ", v.Length())) 937 first := true 938 for i := 0; i < len(vec); i++ { 939 if !first { 940 _ = w.WriteByte(',') 941 } 942 if v.Nsp.Contains(uint64(i)) { 943 _, _ = w.WriteString(common.TypeStringValue(v.Typ, types.Null{})) 944 } else { 945 _, _ = w.WriteString(common.TypeStringValue(v.Typ, vec[i])) 946 } 947 first = false 948 } 949 return w.String() 950 } 951 952 func moVec2String(v *vector.Vector, printN int) string { 953 switch v.Typ.Oid { 954 case types.T_bool: 955 return vec2Str(vector.MustTCols[bool](v)[:printN], v) 956 case types.T_int8: 957 return vec2Str(vector.MustTCols[int8](v)[:printN], v) 958 case types.T_int16: 959 return vec2Str(vector.MustTCols[int16](v)[:printN], v) 960 case types.T_int32: 961 return vec2Str(vector.MustTCols[int32](v)[:printN], v) 962 case types.T_int64: 963 return vec2Str(vector.MustTCols[int64](v)[:printN], v) 964 case types.T_uint8: 965 return vec2Str(vector.MustTCols[uint8](v)[:printN], v) 966 case types.T_uint16: 967 return vec2Str(vector.MustTCols[uint16](v)[:printN], v) 968 case types.T_uint32: 969 return vec2Str(vector.MustTCols[uint32](v)[:printN], v) 970 case types.T_uint64: 971 return vec2Str(vector.MustTCols[uint64](v)[:printN], v) 972 case types.T_float32: 973 return vec2Str(vector.MustTCols[float32](v)[:printN], v) 974 case types.T_float64: 975 return vec2Str(vector.MustTCols[float64](v)[:printN], v) 976 case types.T_date: 977 return vec2Str(vector.MustTCols[types.Date](v)[:printN], v) 978 case types.T_datetime: 979 return vec2Str(vector.MustTCols[types.Datetime](v)[:printN], v) 980 case types.T_time: 981 return vec2Str(vector.MustTCols[types.Time](v)[:printN], v) 982 case types.T_timestamp: 983 return vec2Str(vector.MustTCols[types.Timestamp](v)[:printN], v) 984 case types.T_decimal64: 985 return vec2Str(vector.MustTCols[types.Decimal64](v)[:printN], v) 986 case types.T_decimal128: 987 return vec2Str(vector.MustTCols[types.Decimal128](v)[:printN], v) 988 case types.T_uuid: 989 return vec2Str(vector.MustTCols[types.Uuid](v)[:printN], v) 990 case types.T_TS: 991 return vec2Str(vector.MustTCols[types.TS](v)[:printN], v) 992 case types.T_Rowid: 993 return vec2Str(vector.MustTCols[types.Rowid](v)[:printN], v) 994 } 995 if v.Typ.IsVarlen() { 996 return vec2Str(vector.MustBytesCols(v)[:printN], v) 997 } 998 return fmt.Sprintf("unkown type vec... %v", v.Typ) 999 } 1000 1001 func debugMoBatch(moBat *batch.Batch) string { 1002 if !logutil.GetSkip1Logger().Core().Enabled(zap.DebugLevel) { 1003 return "not debug level" 1004 } 1005 printN := moBat.Length() 1006 if printN > logtail.PrintN { 1007 printN = logtail.PrintN 1008 } 1009 buf := new(bytes.Buffer) 1010 for i, vec := range moBat.Vecs { 1011 fmt.Fprintf(buf, "[%v] = %v\n", moBat.Attrs[i], moVec2String(vec, printN)) 1012 } 1013 return buf.String() 1014 } 1015 1016 func openTAE(targetDir string, opt *options.Options) (tae *db.DB, err error) { 1017 1018 if targetDir != "" { 1019 mask := syscall.Umask(0) 1020 if err := os.MkdirAll(targetDir, os.FileMode(0755)); err != nil { 1021 syscall.Umask(mask) 1022 logutil.Infof("Recreate dir error:%v\n", err) 1023 return nil, err 1024 } 1025 syscall.Umask(mask) 1026 tae, err = db.Open(targetDir+"/tae", opt) 1027 if err != nil { 1028 logutil.Infof("Open tae failed. error:%v", err) 1029 return nil, err 1030 } 1031 return tae, nil 1032 } 1033 1034 tae, err = db.Open(targetDir, opt) 1035 if err != nil { 1036 logutil.Infof("Open tae failed. error:%v", err) 1037 return nil, err 1038 } 1039 return 1040 }