github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/table_function/processlist.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 table_function 16 17 import ( 18 "context" 19 "sort" 20 "strings" 21 "time" 22 23 "github.com/matrixorigin/matrixone/pkg/clusterservice" 24 "github.com/matrixorigin/matrixone/pkg/common/moerr" 25 "github.com/matrixorigin/matrixone/pkg/container/batch" 26 "github.com/matrixorigin/matrixone/pkg/container/vector" 27 "github.com/matrixorigin/matrixone/pkg/pb/metadata" 28 "github.com/matrixorigin/matrixone/pkg/pb/query" 29 "github.com/matrixorigin/matrixone/pkg/pb/status" 30 "github.com/matrixorigin/matrixone/pkg/queryservice" 31 qclient "github.com/matrixorigin/matrixone/pkg/queryservice/client" 32 plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" 33 "github.com/matrixorigin/matrixone/pkg/vm" 34 "github.com/matrixorigin/matrixone/pkg/vm/process" 35 ) 36 37 func processlistPrepare(proc *process.Process, arg *Argument) error { 38 arg.ctr.state = dataProducing 39 if len(arg.Args) > 0 { 40 return moerr.NewInvalidInput(proc.Ctx, "processlist: no argument is required") 41 } 42 for i := range arg.Attrs { 43 arg.Attrs[i] = strings.ToUpper(arg.Attrs[i]) 44 } 45 return nil 46 } 47 48 func processlist(_ int, proc *process.Process, arg *Argument, result *vm.CallResult) (bool, error) { 49 switch arg.ctr.state { 50 case dataProducing: 51 sessions, err := fetchSessions(proc.Ctx, proc.SessionInfo.Account, proc.QueryClient) 52 if err != nil { 53 return false, err 54 } 55 bat := batch.NewWithSize(len(arg.Attrs)) 56 for i, a := range arg.Attrs { 57 idx, ok := status.SessionField_value[a] 58 if !ok { 59 return false, moerr.NewInternalError(proc.Ctx, "bad input select columns name %v", a) 60 } 61 62 tp := plan2.SessionsColTypes[idx] 63 bat.Vecs[i] = proc.GetVector(tp) 64 } 65 bat.Attrs = arg.Attrs 66 67 mp := proc.GetMPool() 68 for _, session := range sessions { 69 for i, col := range arg.Attrs { 70 switch status.SessionField(status.SessionField_value[col]) { 71 case status.SessionField_NODE_ID: 72 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.NodeID), false, mp); err != nil { 73 return false, err 74 } 75 case status.SessionField_CONN_ID: 76 if err := vector.AppendFixed(bat.Vecs[i], session.ConnID, false, mp); err != nil { 77 return false, err 78 } 79 case status.SessionField_SESSION_ID: 80 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.SessionID), false, mp); err != nil { 81 return false, err 82 } 83 case status.SessionField_ACCOUNT: 84 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.Account), false, mp); err != nil { 85 return false, err 86 } 87 case status.SessionField_USER: 88 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.User), false, mp); err != nil { 89 return false, err 90 } 91 case status.SessionField_HOST: 92 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.Host), false, mp); err != nil { 93 return false, err 94 } 95 case status.SessionField_DB: 96 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.DB), false, mp); err != nil { 97 return false, err 98 } 99 case status.SessionField_SESSION_START: 100 if err := vector.AppendBytes(bat.Vecs[i], 101 []byte(session.SessionStart.Format("2006-01-02 15:04:05.000000")), 102 false, mp); err != nil { 103 return false, err 104 } 105 case status.SessionField_COMMAND: 106 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.Command), false, mp); err != nil { 107 return false, err 108 } 109 case status.SessionField_INFO: 110 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.Info), false, mp); err != nil { 111 return false, err 112 } 113 case status.SessionField_TXN_ID: 114 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.TxnID), false, mp); err != nil { 115 return false, err 116 } 117 case status.SessionField_STATEMENT_ID: 118 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.StatementID), false, mp); err != nil { 119 return false, err 120 } 121 case status.SessionField_STATEMENT_TYPE: 122 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.StatementType), false, mp); err != nil { 123 return false, err 124 } 125 case status.SessionField_QUERY_TYPE: 126 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.QueryType), false, mp); err != nil { 127 return false, err 128 } 129 case status.SessionField_SQL_SOURCE_TYPE: 130 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.SQLSourceType), false, mp); err != nil { 131 return false, err 132 } 133 case status.SessionField_QUERY_START: 134 var queryStart string 135 if !session.QueryStart.Equal(time.Time{}) { 136 queryStart = session.QueryStart.Format("2006-01-02 15:04:05.000000") 137 } 138 if err := vector.AppendBytes(bat.Vecs[i], []byte(queryStart), 139 false, mp); err != nil { 140 return false, err 141 } 142 case status.SessionField_CLIENT_HOST: 143 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.GetClientHost()), false, mp); err != nil { 144 return false, err 145 } 146 case status.SessionField_ROLE: 147 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.GetRole()), false, mp); err != nil { 148 return false, err 149 } 150 case status.SessionField_PROXY_HOST: 151 if err := vector.AppendBytes(bat.Vecs[i], []byte(session.GetProxyHost()), false, mp); err != nil { 152 return false, err 153 } 154 } 155 } 156 } 157 bat.SetRowCount(bat.Vecs[0].Length()) 158 result.Batch = bat 159 arg.ctr.state = dataFinished 160 return false, nil 161 162 case dataFinished: 163 result.Batch = nil 164 return true, nil 165 default: 166 return false, moerr.NewInternalError(proc.Ctx, "unknown state %v", arg.ctr.state) 167 } 168 } 169 170 // isSysTenant return true if the tenant is sys. 171 func isSysTenant(tenant string) bool { 172 return strings.ToLower(tenant) == "sys" 173 } 174 175 // fetchSessions get sessions all nodes which the tenant has privilege to access. 176 func fetchSessions(ctx context.Context, tenant string, qc qclient.QueryClient) ([]*status.Session, error) { 177 var nodes []string 178 sysTenant := isSysTenant(tenant) 179 clusterservice.GetMOCluster().GetCNService(clusterservice.NewSelector(), 180 func(s metadata.CNService) bool { 181 nodes = append(nodes, s.QueryAddress) 182 return true 183 }) 184 185 var retErr error 186 var sessions []*status.Session 187 188 genRequest := func() *query.Request { 189 req := qc.NewRequest(query.CmdMethod_ShowProcessList) 190 req.ShowProcessListRequest = &query.ShowProcessListRequest{ 191 Tenant: tenant, 192 SysTenant: sysTenant, 193 } 194 return req 195 } 196 197 handleValidResponse := func(nodeAddr string, rsp *query.Response) { 198 if rsp != nil && rsp.ShowProcessListResponse != nil { 199 for _, ss := range rsp.ShowProcessListResponse.Sessions { 200 if sysTenant || strings.EqualFold(ss.Account, tenant) { 201 sessions = append(sessions, ss) 202 } 203 } 204 } 205 } 206 207 retErr = queryservice.RequestMultipleCn(ctx, nodes, qc, genRequest, handleValidResponse, nil) 208 209 // Sort by session start time. 210 sort.Slice(sessions, func(i, j int) bool { 211 return sessions[i].SessionStart.Before(sessions[j].SessionStart) 212 }) 213 214 return sessions, retErr 215 }