github.com/matrixorigin/matrixone@v1.2.0/pkg/txn/trace/service_txn_event.go (about) 1 // Copyright 2024 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 trace 16 17 import ( 18 "context" 19 "fmt" 20 "path/filepath" 21 "strings" 22 "time" 23 24 "github.com/fagongzi/util/format" 25 "github.com/matrixorigin/matrixone/pkg/common/moerr" 26 "github.com/matrixorigin/matrixone/pkg/common/reuse" 27 "github.com/matrixorigin/matrixone/pkg/common/util" 28 "github.com/matrixorigin/matrixone/pkg/container/batch" 29 "github.com/matrixorigin/matrixone/pkg/container/vector" 30 "github.com/matrixorigin/matrixone/pkg/pb/api" 31 "github.com/matrixorigin/matrixone/pkg/pb/timestamp" 32 "github.com/matrixorigin/matrixone/pkg/txn/client" 33 "github.com/matrixorigin/matrixone/pkg/util/executor" 34 "go.uber.org/zap" 35 ) 36 37 func (s *service) TxnCreated(op client.TxnOperator) { 38 if s.atomic.closed.Load() { 39 return 40 } 41 42 if !s.atomic.txnEventEnabled.Load() && 43 !s.atomic.txnActionEventEnabled.Load() { 44 return 45 } 46 47 filters := s.atomic.txnFilters.Load() 48 if skipped := filters.filter(op); skipped { 49 return 50 } 51 52 register := false 53 if s.atomic.txnEventEnabled.Load() { 54 register = true 55 s.txnC <- event{ 56 csv: newTxnCreated(op.Txn()), 57 } 58 } 59 60 if s.atomic.txnActionEventEnabled.Load() { 61 register = true 62 s.doAddTxnAction( 63 op.Txn().ID, 64 client.OpenEvent.Name, 65 0, 66 0, 67 0, 68 "", 69 nil) 70 } 71 72 if register { 73 op.AppendEventCallback(client.WaitActiveEvent, s.handleTxnActive) 74 op.AppendEventCallback(client.UpdateSnapshotEvent, s.handleTxnUpdateSnapshot) 75 op.AppendEventCallback(client.CommitEvent, s.handleTxnCommit) 76 op.AppendEventCallback(client.RollbackEvent, s.handleTxnRollback) 77 78 op.AppendEventCallback(client.CommitResponseEvent, s.handleTxnActionEvent) 79 op.AppendEventCallback(client.CommitWaitApplyEvent, s.handleTxnActionEvent) 80 op.AppendEventCallback(client.UnlockEvent, s.handleTxnActionEvent) 81 op.AppendEventCallback(client.RangesEvent, s.handleTxnActionEvent) 82 op.AppendEventCallback(client.BuildPlanEvent, s.handleTxnActionEvent) 83 op.AppendEventCallback(client.ExecuteSQLEvent, s.handleTxnActionEvent) 84 op.AppendEventCallback(client.CompileEvent, s.handleTxnActionEvent) 85 op.AppendEventCallback(client.TableScanEvent, s.handleTxnActionEvent) 86 op.AppendEventCallback(client.WorkspaceWriteEvent, s.handleTxnActionEvent) 87 op.AppendEventCallback(client.WorkspaceAdjustEvent, s.handleTxnActionEvent) 88 } 89 } 90 91 func (s *service) TxnExecSQL( 92 op client.TxnOperator, 93 sql string) { 94 if !s.Enabled(FeatureTraceTxn) { 95 return 96 } 97 98 if s.atomic.closed.Load() { 99 return 100 } 101 102 filters := s.atomic.txnFilters.Load() 103 if skipped := filters.filter(op); skipped { 104 return 105 } 106 107 sql = truncateSQL(sql) 108 s.txnC <- event{ 109 csv: newTxnInfoEvent(op.Txn(), txnExecuteEvent, sql), 110 } 111 } 112 113 func (s *service) TxnConflictChanged( 114 op client.TxnOperator, 115 tableID uint64, 116 lastCommitAt timestamp.Timestamp, 117 ) { 118 if !s.Enabled(FeatureTraceTxn) { 119 return 120 } 121 122 if s.atomic.closed.Load() { 123 return 124 } 125 126 filters := s.atomic.txnFilters.Load() 127 if skipped := filters.filter(op); skipped { 128 return 129 } 130 131 buf := reuse.Alloc[buffer](nil) 132 table := buf.writeUint(tableID) 133 ts := buf.writeTimestamp(lastCommitAt) 134 135 idx := buf.buf.GetWriteIndex() 136 buf.buf.WriteString("table:") 137 buf.buf.WriteString(table) 138 buf.buf.WriteString(", new-min-snapshot-ts: ") 139 buf.buf.WriteString(ts) 140 info := buf.buf.RawSlice(idx, buf.buf.GetWriteIndex()) 141 s.txnC <- event{ 142 csv: newTxnInfoEvent( 143 op.Txn(), 144 txnConflictChanged, 145 util.UnsafeBytesToString(info), 146 ), 147 } 148 s.txnC <- event{ 149 buffer: buf, 150 } 151 } 152 153 func (s *service) TxnNoConflictChanged( 154 op client.TxnOperator, 155 tableID uint64, 156 lockedAt, newSnapshotTS timestamp.Timestamp, 157 ) { 158 if !s.Enabled(FeatureTraceTxn) { 159 return 160 } 161 162 if s.atomic.closed.Load() { 163 return 164 } 165 166 filters := s.atomic.txnFilters.Load() 167 if skipped := filters.filter(op); skipped { 168 return 169 } 170 171 buf := reuse.Alloc[buffer](nil) 172 table := buf.writeUint(tableID) 173 locked := buf.writeTimestamp(lockedAt) 174 newSnapshot := buf.writeTimestamp(newSnapshotTS) 175 176 idx := buf.buf.GetWriteIndex() 177 buf.buf.WriteString("table:") 178 buf.buf.WriteString(table) 179 buf.buf.WriteString(", locked-ts: ") 180 buf.buf.WriteString(locked) 181 buf.buf.WriteString(", new-min-snapshot-ts: ") 182 buf.buf.WriteString(newSnapshot) 183 info := buf.buf.RawSlice(idx, buf.buf.GetWriteIndex()) 184 s.txnC <- event{ 185 csv: newTxnInfoEvent( 186 op.Txn(), 187 txnNoConflictChanged, 188 util.UnsafeBytesToString(info), 189 ), 190 } 191 s.txnC <- event{ 192 buffer: buf, 193 } 194 } 195 196 func (s *service) TxnUpdateSnapshot( 197 op client.TxnOperator, 198 tableID uint64, 199 why string) { 200 if !s.Enabled(FeatureTraceTxn) { 201 return 202 } 203 204 if s.atomic.closed.Load() { 205 return 206 } 207 208 filters := s.atomic.txnFilters.Load() 209 if skipped := filters.filter(op); skipped { 210 return 211 } 212 213 buf := reuse.Alloc[buffer](nil) 214 table := buf.writeUint(tableID) 215 216 idx := buf.buf.GetWriteIndex() 217 buf.buf.WriteString(why) 218 buf.buf.WriteString(" table:") 219 buf.buf.WriteString(table) 220 info := buf.buf.RawSlice(idx, buf.buf.GetWriteIndex()) 221 s.txnC <- event{ 222 csv: newTxnInfoEvent( 223 op.Txn(), 224 txnUpdateSnapshotReasonEvent, 225 util.UnsafeBytesToString(info), 226 ), 227 } 228 s.txnC <- event{ 229 buffer: buf, 230 } 231 } 232 233 func (s *service) TxnCommit( 234 op client.TxnOperator, 235 entries []*api.Entry) { 236 if !s.Enabled(FeatureTraceTxn) { 237 return 238 } 239 240 if s.atomic.closed.Load() { 241 return 242 } 243 244 txnFilters := s.atomic.txnFilters.Load() 245 if skipped := txnFilters.filter(op); skipped { 246 return 247 } 248 249 ts := time.Now().UnixNano() 250 buf := reuse.Alloc[buffer](nil) 251 var entryData *EntryData 252 defer func() { 253 entryData.close() 254 }() 255 256 tableFilters := s.atomic.tableFilters.Load() 257 258 n := 0 259 for _, entry := range entries { 260 if entryData == nil { 261 entryData = newEntryData(entry, -1, ts) 262 } else { 263 entryData.reset() 264 entryData.init(entry, -1, ts) 265 } 266 267 if skipped := tableFilters.filter(entryData); skipped { 268 continue 269 } 270 271 entryData.createCommit( 272 op.Txn().ID, 273 buf, 274 func(e dataEvent) { 275 s.entryC <- event{ 276 csv: e, 277 } 278 }, 279 &s.atomic.complexPKTables) 280 n++ 281 } 282 283 if n == 0 { 284 buf.close() 285 return 286 } 287 s.entryC <- event{ 288 buffer: buf, 289 } 290 } 291 292 func (s *service) TxnRead( 293 op client.TxnOperator, 294 snapshotTS timestamp.Timestamp, 295 tableID uint64, 296 columns []string, 297 bat *batch.Batch) { 298 if !s.Enabled(FeatureTraceData) { 299 return 300 } 301 302 if s.atomic.closed.Load() { 303 return 304 } 305 306 filters := s.atomic.txnFilters.Load() 307 if skipped := filters.filter(op); skipped { 308 return 309 } 310 311 entryData := newReadEntryData(tableID, snapshotTS, bat, columns, time.Now().UnixNano()) 312 defer func() { 313 entryData.close() 314 }() 315 316 tableFilters := s.atomic.tableFilters.Load() 317 if skipped := tableFilters.filter(entryData); skipped { 318 return 319 } 320 321 buf := reuse.Alloc[buffer](nil) 322 entryData.createRead( 323 op.Txn().ID, 324 buf, 325 func(e dataEvent) { 326 s.entryC <- event{ 327 csv: e, 328 } 329 }, 330 &s.atomic.complexPKTables) 331 s.entryC <- event{ 332 buffer: buf, 333 } 334 } 335 336 func (s *service) TxnReadBlock( 337 op client.TxnOperator, 338 tableID uint64, 339 block []byte) { 340 if !s.Enabled(FeatureTraceTxn) { 341 return 342 } 343 344 if s.atomic.closed.Load() { 345 return 346 } 347 348 filters := s.atomic.txnFilters.Load() 349 if skipped := filters.filter(op); skipped { 350 return 351 } 352 353 entryData := newTableOnlyEntryData(tableID) 354 defer func() { 355 entryData.close() 356 }() 357 358 tableFilters := s.atomic.tableFilters.Load() 359 if skipped := tableFilters.filter(entryData); skipped { 360 return 361 } 362 363 buf := reuse.Alloc[buffer](nil) 364 s.entryC <- event{ 365 csv: newReadBlockEvent( 366 time.Now().UnixNano(), 367 op.Txn().ID, 368 tableID, 369 buf.writeHexWithBytes(block), 370 ), 371 } 372 s.entryC <- event{ 373 buffer: buf, 374 } 375 } 376 377 func (s *service) TxnWrite( 378 op client.TxnOperator, 379 tableID uint64, 380 typ string, 381 bat *batch.Batch, 382 ) { 383 if !s.Enabled(FeatureTraceTxnWorkspace) { 384 return 385 } 386 387 if s.atomic.closed.Load() { 388 return 389 } 390 391 filters := s.atomic.txnFilters.Load() 392 if skipped := filters.filter(op); skipped { 393 return 394 } 395 396 entryData := newWriteEntryData(tableID, bat, time.Now().UnixNano()) 397 defer func() { 398 entryData.close() 399 }() 400 401 tableFilters := s.atomic.tableFilters.Load() 402 if skipped := tableFilters.filter(entryData); skipped { 403 return 404 } 405 406 buf := reuse.Alloc[buffer](nil) 407 entryData.createWrite( 408 op.Txn().ID, 409 buf, 410 typ, 411 func(e dataEvent) { 412 s.entryC <- event{ 413 csv: e, 414 } 415 }, 416 &s.atomic.complexPKTables) 417 s.entryC <- event{ 418 buffer: buf, 419 } 420 } 421 422 func (s *service) TxnAdjustWorkspace( 423 op client.TxnOperator, 424 adjustCount int, 425 writes func() (tableID uint64, typ string, bat *batch.Batch, more bool), 426 ) { 427 if !s.Enabled(FeatureTraceTxnWorkspace) { 428 return 429 } 430 431 if s.atomic.closed.Load() { 432 return 433 } 434 435 filters := s.atomic.txnFilters.Load() 436 if skipped := filters.filter(op); skipped { 437 return 438 } 439 440 at := time.Now().UnixNano() 441 442 offsetCount := 0 443 for { 444 tableID, typ, bat, more := writes() 445 if !more { 446 return 447 } 448 449 func() { 450 entryData := newWorkspaceEntryData(tableID, bat, at) 451 defer func() { 452 entryData.close() 453 }() 454 455 tableFilters := s.atomic.tableFilters.Load() 456 if skipped := tableFilters.filter(entryData); skipped { 457 return 458 } 459 460 buf := reuse.Alloc[buffer](nil) 461 entryData.createWorkspace( 462 op.Txn().ID, 463 buf, 464 typ, 465 adjustCount, 466 offsetCount, 467 func(e dataEvent) { 468 s.entryC <- event{ 469 csv: e, 470 } 471 }, 472 &s.atomic.complexPKTables) 473 s.entryC <- event{ 474 buffer: buf, 475 } 476 }() 477 offsetCount++ 478 } 479 } 480 481 func (s *service) TxnEventEnabled() bool { 482 return s.atomic.txnEventEnabled.Load() 483 } 484 485 func (s *service) handleTxnActive(e client.TxnEvent) { 486 if s.atomic.closed.Load() { 487 return 488 } 489 490 if !e.CostEvent && s.atomic.txnEventEnabled.Load() { 491 s.txnC <- event{ 492 csv: newTxnActive(e.Txn), 493 } 494 } 495 496 if s.atomic.txnActionEventEnabled.Load() { 497 s.doTxnEventAction(e) 498 } 499 } 500 501 func (s *service) handleTxnUpdateSnapshot(e client.TxnEvent) { 502 if s.atomic.closed.Load() { 503 return 504 } 505 506 if e.CostEvent && s.atomic.txnEventEnabled.Load() { 507 s.txnC <- event{ 508 csv: newTxnSnapshotUpdated(e.Txn), 509 } 510 } 511 512 if s.atomic.txnActionEventEnabled.Load() { 513 s.doTxnEventAction(e) 514 } 515 } 516 517 func (s *service) handleTxnCommit(e client.TxnEvent) { 518 if s.atomic.closed.Load() { 519 return 520 } 521 522 if e.CostEvent && s.atomic.txnEventEnabled.Load() { 523 s.txnC <- event{ 524 csv: newTxnClosed(e.Txn), 525 } 526 if e.Err != nil { 527 s.doAddTxnError(e.Txn.ID, e.Err) 528 } 529 } 530 531 if s.atomic.txnActionEventEnabled.Load() { 532 s.doTxnEventAction(e) 533 } 534 } 535 536 func (s *service) handleTxnRollback(e client.TxnEvent) { 537 if s.atomic.closed.Load() { 538 return 539 } 540 541 if e.CostEvent && s.atomic.txnEventEnabled.Load() { 542 s.txnC <- event{ 543 csv: newTxnClosed(e.Txn), 544 } 545 if e.Err != nil { 546 s.doAddTxnError(e.Txn.ID, e.Err) 547 } 548 } 549 550 if s.atomic.txnActionEventEnabled.Load() { 551 s.doTxnEventAction(e) 552 } 553 } 554 555 func (s *service) handleTxnActionEvent(event client.TxnEvent) { 556 if s.atomic.closed.Load() { 557 return 558 } 559 560 if s.atomic.txnActionEventEnabled.Load() { 561 s.doTxnEventAction(event) 562 } 563 } 564 565 func (s *service) TxnError( 566 op client.TxnOperator, 567 value error) { 568 if s.atomic.closed.Load() { 569 return 570 } 571 572 if op.TxnOptions().TraceDisabled() { 573 return 574 } 575 576 if !s.atomic.txnEventEnabled.Load() { 577 return 578 } 579 580 s.doAddTxnError(op.Txn().ID, value) 581 } 582 583 func (s *service) doAddTxnError( 584 txnID []byte, 585 value error) { 586 ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 587 defer cancel() 588 589 ts := time.Now().UnixNano() 590 msg := value.Error() 591 if me, ok := value.(*moerr.Error); ok { 592 msg += ": " + me.Detail() 593 } 594 595 sql := fmt.Sprintf("insert into %s (ts, txn_id, error_info) values (%d, '%x', '%s')", 596 EventErrorTable, 597 ts, 598 txnID, 599 escape(msg)) 600 601 now, _ := s.clock.Now() 602 err := s.executor.ExecTxn( 603 ctx, 604 func(txn executor.TxnExecutor) error { 605 res, err := txn.Exec(sql, 606 executor.StatementOption{}) 607 if err != nil { 608 return err 609 } 610 res.Close() 611 return nil 612 }, 613 executor.Options{}. 614 WithDatabase(DebugDB). 615 WithMinCommittedTS(now). 616 WithWaitCommittedLogApplied(). 617 WithDisableTrace()) 618 if err != nil { 619 s.logger.Error("exec txn error trace failed", 620 zap.String("sql", sql), 621 zap.Error(err)) 622 } 623 } 624 625 func (s *service) TxnStatementStart( 626 op client.TxnOperator, 627 sql string, 628 seq uint64, 629 ) { 630 if !s.Enabled(FeatureTraceTxnAction) && 631 !s.Enabled(FeatureTraceTxn) { 632 return 633 } 634 635 s.TxnExecSQL(op, sql) 636 s.AddTxnDurationAction( 637 op, 638 client.ExecuteSQLEvent, 639 seq, 640 0, 641 0, 642 nil) 643 } 644 645 func (s *service) TxnStatementCompleted( 646 op client.TxnOperator, 647 sql string, 648 cost time.Duration, 649 seq uint64, 650 affectRows int, 651 err error, 652 ) { 653 if !s.Enabled(FeatureTraceTxnAction) && 654 !s.Enabled(FeatureTraceTxn) && 655 !s.Enabled(FeatureTraceStatement) { 656 return 657 } 658 659 buf := reuse.Alloc[buffer](nil) 660 if err == nil { 661 err = infoErr{ 662 info: buf.writeInt(int64(affectRows)), 663 } 664 } 665 666 s.AddTxnDurationAction( 667 op, 668 client.ExecuteSQLEvent, 669 seq, 670 0, 671 cost, 672 err) 673 674 s.AddStatement( 675 op, 676 sql, 677 cost) 678 679 s.txnActionC <- event{ 680 buffer: buf, 681 } 682 } 683 684 func (s *service) AddTxnDurationAction( 685 op client.TxnOperator, 686 eventType client.EventType, 687 seq uint64, 688 tableID uint64, 689 value time.Duration, 690 err error, 691 ) { 692 s.AddTxnAction( 693 op, 694 eventType, 695 seq, 696 tableID, 697 value.Microseconds(), 698 "us", 699 err) 700 } 701 702 func (s *service) AddTxnAction( 703 op client.TxnOperator, 704 eventType client.EventType, 705 seq uint64, 706 tableID uint64, 707 value int64, 708 unit string, 709 err error, 710 ) { 711 if !s.Enabled(FeatureTraceTxnAction) { 712 return 713 } 714 715 if s.atomic.closed.Load() { 716 return 717 } 718 719 filters := s.atomic.txnFilters.Load() 720 if skipped := filters.filter(op); skipped { 721 return 722 } 723 724 s.doAddTxnAction( 725 op.Txn().ID, 726 eventType.Name, 727 seq, 728 tableID, 729 value, 730 unit, 731 err) 732 } 733 734 func (s *service) AddTxnActionInfo( 735 op client.TxnOperator, 736 eventType client.EventType, 737 seq uint64, 738 tableID uint64, 739 value func(Writer), 740 ) { 741 if !s.Enabled(FeatureTraceTxnAction) { 742 return 743 } 744 745 if s.atomic.closed.Load() { 746 return 747 } 748 749 filters := s.atomic.txnFilters.Load() 750 if skipped := filters.filter(op); skipped { 751 return 752 } 753 754 buf := reuse.Alloc[buffer](nil) 755 w := writer{ 756 buf: buf.buf, 757 dst: buf.alloc(1024), 758 idx: buf.buf.GetWriteIndex(), 759 } 760 value(w) 761 762 s.txnActionC <- event{ 763 csv: actionEvent{ 764 ts: time.Now().UnixNano(), 765 action: eventType.Name, 766 actionSeq: seq, 767 tableID: tableID, 768 value: 0, 769 unit: w.data(), 770 txnID: op.Txn().ID, 771 err: "", 772 }, 773 } 774 s.txnActionC <- event{ 775 buffer: buf, 776 } 777 } 778 779 func (s *service) doTxnEventAction(event client.TxnEvent) { 780 unit := "" 781 if event.CostEvent { 782 unit = "us" 783 } 784 s.doAddTxnAction( 785 event.Txn.ID, 786 event.Event.Name, 787 event.Sequence, 788 0, 789 event.Cost.Microseconds(), 790 unit, 791 event.Err) 792 } 793 794 func (s *service) doAddTxnAction( 795 txnID []byte, 796 action string, 797 actionSequence uint64, 798 tableID uint64, 799 value int64, 800 unit string, 801 err error, 802 ) { 803 e := "" 804 if err != nil { 805 e = err.Error() 806 } 807 s.txnActionC <- event{ 808 csv: actionEvent{ 809 ts: time.Now().UnixNano(), 810 action: action, 811 actionSeq: actionSequence, 812 tableID: tableID, 813 value: int64(value), 814 unit: unit, 815 txnID: txnID, 816 err: e, 817 }, 818 } 819 } 820 821 func (s *service) AddTxnFilter(method, value string) error { 822 switch method { 823 case sessionMethod, connectionMethod, tenantMethod, userMethod: 824 default: 825 return moerr.NewNotSupportedNoCtx("method %s not support", method) 826 } 827 828 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 829 defer cancel() 830 831 now, _ := s.clock.Now() 832 return s.executor.ExecTxn( 833 ctx, 834 func(txn executor.TxnExecutor) error { 835 r, err := txn.Exec(addTxnFilterSQL(method, value), executor.StatementOption{}) 836 if err != nil { 837 return err 838 } 839 r.Close() 840 return nil 841 }, 842 executor.Options{}. 843 WithDatabase(DebugDB). 844 WithMinCommittedTS(now). 845 WithWaitCommittedLogApplied(). 846 WithDisableTrace()) 847 } 848 849 func (s *service) ClearTxnFilters() error { 850 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 851 defer cancel() 852 853 now, _ := s.clock.Now() 854 err := s.executor.ExecTxn( 855 ctx, 856 func(txn executor.TxnExecutor) error { 857 txn.Use(DebugDB) 858 res, err := txn.Exec( 859 fmt.Sprintf("truncate table %s", 860 TraceTxnFilterTable), 861 executor.StatementOption{}) 862 if err != nil { 863 return err 864 } 865 res.Close() 866 return nil 867 }, 868 executor.Options{}. 869 WithDisableTrace(). 870 WithMinCommittedTS(now). 871 WithWaitCommittedLogApplied()) 872 if err != nil { 873 return err 874 } 875 876 return s.RefreshTxnFilters() 877 } 878 879 func (s *service) RefreshTxnFilters() error { 880 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 881 defer cancel() 882 883 var filters []TxnFilter 884 var methods []string 885 var values []string 886 now, _ := s.clock.Now() 887 err := s.executor.ExecTxn( 888 ctx, 889 func(txn executor.TxnExecutor) error { 890 txn.Use(DebugDB) 891 res, err := txn.Exec( 892 fmt.Sprintf("select method, value from %s", 893 TraceTxnFilterTable), 894 executor.StatementOption{}) 895 if err != nil { 896 return err 897 } 898 defer res.Close() 899 900 res.ReadRows(func(rows int, cols []*vector.Vector) bool { 901 for i := 0; i < rows; i++ { 902 methods = append(methods, cols[0].GetStringAt(i)) 903 values = append(values, cols[1].GetStringAt(i)) 904 } 905 return true 906 }) 907 return nil 908 }, 909 executor.Options{}. 910 WithDisableTrace(). 911 WithMinCommittedTS(now). 912 WithWaitCommittedLogApplied()) 913 if err != nil { 914 return err 915 } 916 917 filters = append(filters, &disableFilter{}) 918 for i, method := range methods { 919 switch method { 920 case sessionMethod: 921 filters = append(filters, &sessionIDFilter{sessionID: values[i]}) 922 case connectionMethod: 923 params := strings.Split(values[i], ",") 924 filters = append(filters, 925 &connectionIDFilter{ 926 sessionID: params[0], 927 connectionID: format.MustParseStringUint32(params[1]), 928 }) 929 case tenantMethod: 930 params := strings.Split(values[i], ",") 931 filters = append(filters, 932 &tenantFilter{ 933 accountID: format.MustParseStringUint32(params[0]), 934 userName: params[1], 935 }) 936 case userMethod: 937 filters = append(filters, 938 &userFilter{ 939 userName: values[i], 940 }) 941 } 942 } 943 944 s.atomic.txnFilters.Store(&txnFilters{filters: filters}) 945 return nil 946 } 947 948 func (s *service) handleTxnEvents(ctx context.Context) { 949 s.handleEvent( 950 ctx, 951 s.txnCSVFile, 952 8, 953 EventTxnTable, 954 s.txnC, 955 ) 956 } 957 958 func (s *service) handleTxnActionEvents(ctx context.Context) { 959 s.handleEvent( 960 ctx, 961 s.txnActionCSVFile, 962 9, 963 EventTxnActionTable, 964 s.txnActionC, 965 ) 966 } 967 968 func (s *service) txnCSVFile() string { 969 return filepath.Join(s.dir, fmt.Sprintf("txn-%d.csv", s.seq.Add(1))) 970 } 971 972 func (s *service) txnActionCSVFile() string { 973 return filepath.Join(s.dir, fmt.Sprintf("txn-action-%d.csv", s.seq.Add(1))) 974 } 975 976 func addTxnFilterSQL( 977 method string, 978 value string, 979 ) string { 980 return fmt.Sprintf("insert into %s (method, value) values ('%s', '%s')", 981 TraceTxnFilterTable, 982 method, 983 value) 984 } 985 986 type infoErr struct { 987 info string 988 } 989 990 func (e infoErr) Error() string { 991 return e.info 992 }