github.com/matrixorigin/matrixone@v1.2.0/pkg/txn/trace/service_statement.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 "time" 22 23 "github.com/matrixorigin/matrixone/pkg/common/moerr" 24 "github.com/matrixorigin/matrixone/pkg/container/vector" 25 "github.com/matrixorigin/matrixone/pkg/txn/client" 26 "github.com/matrixorigin/matrixone/pkg/util/executor" 27 "github.com/matrixorigin/matrixone/pkg/util/toml" 28 ) 29 30 func (s *service) AddStatement( 31 op client.TxnOperator, 32 sql string, 33 cost time.Duration, 34 ) { 35 if !s.Enabled(FeatureTraceStatement) { 36 return 37 } 38 39 if s.atomic.closed.Load() { 40 return 41 } 42 43 txnFilters := s.atomic.txnFilters.Load() 44 if skipped := txnFilters.filter(op); skipped { 45 return 46 } 47 48 statementFilters := s.atomic.statementFilters.Load() 49 if skipped := statementFilters.filter(op, sql, cost); skipped { 50 return 51 } 52 53 sql = truncateSQL(sql) 54 s.statementC <- event{ 55 csv: newStatement( 56 op.Txn().ID, 57 sql, 58 cost, 59 ), 60 } 61 } 62 63 func (s *service) AddStatementFilter( 64 method, value string, 65 ) error { 66 switch method { 67 case statementCostMethod: 68 cost := &toml.Duration{} 69 if err := cost.UnmarshalText([]byte(value)); err != nil { 70 return err 71 } 72 case statementContainsMethod: 73 default: 74 return moerr.NewNotSupportedNoCtx("method %s not support", method) 75 } 76 77 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 78 defer cancel() 79 80 now, _ := s.clock.Now() 81 return s.executor.ExecTxn( 82 ctx, 83 func(txn executor.TxnExecutor) error { 84 r, err := txn.Exec(addStatementFilterSQL(method, value), executor.StatementOption{}) 85 if err != nil { 86 return err 87 } 88 r.Close() 89 return nil 90 }, 91 executor.Options{}. 92 WithDatabase(DebugDB). 93 WithMinCommittedTS(now). 94 WithWaitCommittedLogApplied(). 95 WithDisableTrace()) 96 } 97 98 func (s *service) ClearStatementFilters() error { 99 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 100 defer cancel() 101 102 now, _ := s.clock.Now() 103 err := s.executor.ExecTxn( 104 ctx, 105 func(txn executor.TxnExecutor) error { 106 txn.Use(DebugDB) 107 res, err := txn.Exec( 108 fmt.Sprintf("truncate table %s", 109 TraceStatementFilterTable), 110 executor.StatementOption{}) 111 if err != nil { 112 return err 113 } 114 res.Close() 115 return nil 116 }, 117 executor.Options{}. 118 WithDisableTrace(). 119 WithMinCommittedTS(now). 120 WithWaitCommittedLogApplied()) 121 if err != nil { 122 return err 123 } 124 125 return s.RefreshTableFilters() 126 } 127 128 func (s *service) RefreshStatementFilters() error { 129 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 130 defer cancel() 131 132 var filters []StatementFilter 133 var methods []string 134 var values []string 135 now, _ := s.clock.Now() 136 err := s.executor.ExecTxn( 137 ctx, 138 func(txn executor.TxnExecutor) error { 139 txn.Use(DebugDB) 140 res, err := txn.Exec( 141 fmt.Sprintf("select method, value from %s", 142 TraceStatementFilterTable), 143 executor.StatementOption{}) 144 if err != nil { 145 return err 146 } 147 defer res.Close() 148 149 res.ReadRows(func(rows int, cols []*vector.Vector) bool { 150 for i := 0; i < rows; i++ { 151 methods = append(methods, cols[0].GetStringAt(i)) 152 values = append(values, cols[1].GetStringAt(i)) 153 } 154 return true 155 }) 156 return nil 157 }, 158 executor.Options{}. 159 WithDisableTrace(). 160 WithMinCommittedTS(now). 161 WithWaitCommittedLogApplied()) 162 if err != nil { 163 return err 164 } 165 166 for i, method := range methods { 167 switch method { 168 case statementCostMethod: 169 cost := &toml.Duration{} 170 if err := cost.UnmarshalText([]byte(values[i])); err != nil { 171 panic(err) 172 } 173 filters = append(filters, 174 &costFilter{target: cost.Duration}) 175 case statementContainsMethod: 176 filters = append(filters, 177 &sqlContainsFilter{ 178 value: values[i], 179 }) 180 } 181 } 182 183 s.atomic.statementFilters.Store(&statementFilters{filters: filters}) 184 return nil 185 } 186 187 func (s *service) handleStatements(ctx context.Context) { 188 s.handleEvent( 189 ctx, 190 s.slowStatementCSVFile, 191 4, 192 TraceStatementTable, 193 s.statementC, 194 ) 195 } 196 197 func addStatementFilterSQL( 198 method string, 199 value string, 200 ) string { 201 return fmt.Sprintf("insert into %s (method, value) values ('%s', '%s')", 202 TraceStatementFilterTable, 203 method, 204 value) 205 } 206 207 func (s *service) slowStatementCSVFile() string { 208 return filepath.Join(s.dir, fmt.Sprintf("slow-%d.csv", s.seq.Add(1))) 209 }