github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/colexec/table_function/system_view.go (about)

     1  // Copyright 2023 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  	"encoding/hex"
    20  	"fmt"
    21  	qclient "github.com/matrixorigin/matrixone/pkg/queryservice/client"
    22  	"strconv"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/matrixorigin/matrixone/pkg/clusterservice"
    27  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    28  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    29  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    30  	"github.com/matrixorigin/matrixone/pkg/container/vector"
    31  	pblock "github.com/matrixorigin/matrixone/pkg/pb/lock"
    32  	logservicepb "github.com/matrixorigin/matrixone/pkg/pb/logservice"
    33  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    34  	"github.com/matrixorigin/matrixone/pkg/pb/query"
    35  	"github.com/matrixorigin/matrixone/pkg/queryservice"
    36  	plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan"
    37  	"github.com/matrixorigin/matrixone/pkg/vm"
    38  	"github.com/matrixorigin/matrixone/pkg/vm/engine/disttae"
    39  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    40  )
    41  
    42  const (
    43  	lockStatusWait     = "wait"     // nobody holds the lock but somebody waits on it
    44  	lockStatusAcquired = "acquired" // somebody holds the lock
    45  	lockStatusNone     = "none"     // nobody waits and holds the lock
    46  )
    47  
    48  func getLockStatus(li *query.LockInfo) string {
    49  	hasHolders := len(li.GetHolders()) != 0
    50  	hasWaiters := len(li.GetWaiters()) != 0
    51  	if !hasHolders && !hasWaiters {
    52  		return lockStatusNone
    53  	} else if hasHolders {
    54  		return lockStatusAcquired
    55  	} else {
    56  		return lockStatusWait
    57  	}
    58  }
    59  
    60  func getRangeKeys(li *query.LockInfo) ([]byte, []byte) {
    61  	keys := li.GetKeys()
    62  	llen := len(keys)
    63  	if llen >= 2 {
    64  		return keys[0], keys[1]
    65  	} else if llen >= 1 {
    66  		return keys[0], []byte{}
    67  	} else {
    68  		return []byte{}, []byte{}
    69  	}
    70  }
    71  
    72  func getPointKey(li *query.LockInfo) []byte {
    73  	keys := li.GetKeys()
    74  	llen := len(keys)
    75  	if llen >= 1 {
    76  		return keys[0]
    77  	}
    78  	return []byte{}
    79  }
    80  
    81  func moLocksPrepare(proc *process.Process, arg *Argument) error {
    82  	arg.ctr.state = dataProducing
    83  	if len(arg.Args) > 0 {
    84  		return moerr.NewInvalidInput(proc.Ctx, "moConfigurations: no argument is required")
    85  	}
    86  	for i := range arg.Attrs {
    87  		arg.Attrs[i] = strings.ToUpper(arg.Attrs[i])
    88  	}
    89  	return nil
    90  }
    91  
    92  func moLocksCall(_ int, proc *process.Process, arg *Argument, result *vm.CallResult) (bool, error) {
    93  	switch arg.ctr.state {
    94  	case dataProducing:
    95  
    96  		rsps, err := getLocks(proc)
    97  		if err != nil {
    98  			return false, err
    99  		}
   100  
   101  		//alloc batch
   102  		bat := batch.NewWithSize(len(arg.Attrs))
   103  		for i, col := range arg.Attrs {
   104  			col = strings.ToLower(col)
   105  			idx, ok := plan2.MoLocksColName2Index[col]
   106  			if !ok {
   107  				return false, moerr.NewInternalError(proc.Ctx, "bad input select columns name %v", col)
   108  			}
   109  
   110  			tp := plan2.MoLocksColTypes[idx]
   111  			bat.Vecs[i] = proc.GetVector(tp)
   112  		}
   113  		bat.Attrs = arg.Attrs
   114  
   115  		//fill batch from lock info
   116  		for _, rsp := range rsps {
   117  			if rsp == nil || len(rsp.LockInfoList) == 0 {
   118  				continue
   119  			}
   120  			for _, lock := range rsp.LockInfoList {
   121  				if lock == nil {
   122  					continue
   123  				}
   124  				cnId := rsp.GetCnId()
   125  				//sessionId := ""
   126  				txnId := ""
   127  				tableId := fmt.Sprintf("%d", lock.GetTableId())
   128  
   129  				//table name
   130  				//tableName := ""
   131  				//lock key
   132  				lockKey := "point"
   133  				if lock.GetIsRangeLock() {
   134  					lockKey = "range"
   135  				}
   136  
   137  				//lock content
   138  				lockContent := ""
   139  				if lock.GetIsRangeLock() {
   140  					k1, k2 := getRangeKeys(lock)
   141  					lockContent = hex.EncodeToString(k1) + "," + hex.EncodeToString(k2)
   142  				} else {
   143  					lockContent = hex.EncodeToString(getPointKey(lock))
   144  				}
   145  
   146  				//lock mode
   147  				lockMode := lock.GetLockMode().String()
   148  				//lock status
   149  				lockStatus := getLockStatus(lock)
   150  				//lock wait
   151  				lockWait := ""
   152  
   153  				hList := lock.GetHolders()
   154  				hLen := len(hList)
   155  				wList := lock.GetWaiters()
   156  				wLen := len(wList)
   157  
   158  				record := make([][]byte, len(plan2.MoLocksColNames))
   159  				record[plan2.MoLocksColTypeCnId] = []byte(cnId)
   160  				//record[plan2.MoLocksColTypeSessionId] = []byte(sessionId)
   161  				record[plan2.MoLocksColTypeTxnId] = []byte(txnId)
   162  				record[plan2.MoLocksColTypeTableId] = []byte(tableId)
   163  				//record[plan2.MoLocksColTypeTableName] = []byte(tableName)
   164  				record[plan2.MoLocksColTypeLockKey] = []byte(lockKey)
   165  				record[plan2.MoLocksColTypeLockContent] = []byte(lockContent)
   166  				record[plan2.MoLocksColTypeLockMode] = []byte(lockMode)
   167  				record[plan2.MoLocksColTypeLockStatus] = []byte(lockStatus)
   168  				record[plan2.MoLocksColTypeLockWait] = []byte(lockWait)
   169  
   170  				if hLen == 0 && wLen == 0 {
   171  					//one record
   172  					if err := fillLockRecord(proc, arg.Attrs, bat, record); err != nil {
   173  						return false, err
   174  					}
   175  				} else if hLen == 0 && wLen != 0 {
   176  					//wLen records
   177  					for j := 0; j < wLen; j++ {
   178  						record[plan2.MoLocksColTypeLockWait] = []byte(hex.EncodeToString(wList[j].GetTxnID()))
   179  						if err := fillLockRecord(proc, arg.Attrs, bat, record); err != nil {
   180  							return false, err
   181  						}
   182  					}
   183  				} else if hLen != 0 && wLen == 0 {
   184  					//hLen records
   185  					for j := 0; j < hLen; j++ {
   186  						record[plan2.MoLocksColTypeTxnId] = []byte(hex.EncodeToString(hList[j].GetTxnID()))
   187  						if err := fillLockRecord(proc, arg.Attrs, bat, record); err != nil {
   188  							return false, err
   189  						}
   190  					}
   191  				} else {
   192  					//hLen * wLen records
   193  					for j := 0; j < hLen; j++ {
   194  						for k := 0; k < wLen; k++ {
   195  							record[plan2.MoLocksColTypeTxnId] = []byte(hex.EncodeToString(hList[j].GetTxnID()))
   196  							record[plan2.MoLocksColTypeLockWait] = []byte(hex.EncodeToString(wList[k].GetTxnID()))
   197  							if err := fillLockRecord(proc, arg.Attrs, bat, record); err != nil {
   198  								return false, err
   199  							}
   200  						}
   201  					}
   202  				}
   203  			}
   204  		}
   205  
   206  		bat.SetRowCount(bat.Vecs[0].Length())
   207  		result.Batch = bat
   208  		arg.ctr.state = dataFinished
   209  		return false, nil
   210  
   211  	case dataFinished:
   212  		result.Batch = nil
   213  		return true, nil
   214  	default:
   215  		return false, moerr.NewInternalError(proc.Ctx, "unknown state %v", arg.ctr.state)
   216  	}
   217  }
   218  
   219  func fillLockRecord(proc *process.Process, attrs []string, bat *batch.Batch, record [][]byte) error {
   220  	for colIdx, attr := range attrs {
   221  		realColIdx := plan2.MoLocksColName2Index[strings.ToLower(attr)]
   222  		if err := vector.AppendBytes(bat.Vecs[colIdx], record[realColIdx], false, proc.GetMPool()); err != nil {
   223  			return err
   224  		}
   225  	}
   226  	return nil
   227  }
   228  
   229  // getLocks get lock info from all cn
   230  func getLocks(proc *process.Process) ([]*query.GetLockInfoResponse, error) {
   231  	var err error
   232  	var nodes []string
   233  
   234  	selectSuperTenant(clusterservice.NewSelector(), "root", nil,
   235  		func(s *metadata.CNService) {
   236  			nodes = append(nodes, s.QueryAddress)
   237  		})
   238  
   239  	genRequest := func() *query.Request {
   240  		req := proc.QueryClient.NewRequest(query.CmdMethod_GetLockInfo)
   241  		req.GetLockInfoRequest = &query.GetLockInfoRequest{}
   242  		return req
   243  	}
   244  
   245  	rsps := make([]*query.GetLockInfoResponse, 0)
   246  
   247  	handleValidResponse := func(nodeAddr string, rsp *query.Response) {
   248  		if rsp != nil && rsp.GetLockInfoResponse != nil {
   249  			rsps = append(rsps, rsp.GetLockInfoResponse)
   250  		}
   251  	}
   252  
   253  	err = requestMultipleCn(proc.Ctx, nodes, proc.QueryClient, genRequest, handleValidResponse, nil)
   254  	return rsps, err
   255  }
   256  
   257  func moConfigurationsPrepare(proc *process.Process, arg *Argument) error {
   258  	arg.ctr.state = dataProducing
   259  	if len(arg.Args) > 0 {
   260  		return moerr.NewInvalidInput(proc.Ctx, "moConfigurations: no argument is required")
   261  	}
   262  	for i := range arg.Attrs {
   263  		arg.Attrs[i] = strings.ToUpper(arg.Attrs[i])
   264  	}
   265  	return nil
   266  }
   267  
   268  func moConfigurationsCall(_ int, proc *process.Process, arg *Argument, result *vm.CallResult) (bool, error) {
   269  	switch arg.ctr.state {
   270  	case dataProducing:
   271  
   272  		if proc.Hakeeper == nil {
   273  			return false, moerr.NewInternalError(proc.Ctx, "hakeeper is nil")
   274  		}
   275  
   276  		//get cluster details
   277  		details, err := proc.Hakeeper.GetClusterDetails(proc.Ctx)
   278  		if err != nil {
   279  			return false, err
   280  		}
   281  
   282  		//alloc batch
   283  		bat := batch.NewWithSize(len(arg.Attrs))
   284  		for i, col := range arg.Attrs {
   285  			col = strings.ToLower(col)
   286  			idx, ok := plan2.MoConfigColName2Index[col]
   287  			if !ok {
   288  				return false, moerr.NewInternalError(proc.Ctx, "bad input select columns name %v", col)
   289  			}
   290  
   291  			tp := plan2.MoConfigColTypes[idx]
   292  			bat.Vecs[i] = proc.GetVector(tp)
   293  		}
   294  		bat.Attrs = arg.Attrs
   295  
   296  		mp := proc.GetMPool()
   297  
   298  		//fill batch for cn
   299  		for _, cnStore := range details.GetCNStores() {
   300  			if cnStore.GetConfigData() != nil {
   301  				err = fillMapToBatch("cn", cnStore.GetUUID(), arg.Attrs, cnStore.GetConfigData().GetContent(), bat, mp)
   302  				if err != nil {
   303  					return false, err
   304  				}
   305  			}
   306  		}
   307  
   308  		//fill batch for tn
   309  		for _, tnStore := range details.GetTNStores() {
   310  			if tnStore.GetConfigData() != nil {
   311  				err = fillMapToBatch("tn", tnStore.GetUUID(), arg.Attrs, tnStore.GetConfigData().GetContent(), bat, mp)
   312  				if err != nil {
   313  					return false, err
   314  				}
   315  			}
   316  		}
   317  
   318  		//fill batch for log
   319  		for _, logStore := range details.GetLogStores() {
   320  			if logStore.GetConfigData() != nil {
   321  				err = fillMapToBatch("log", logStore.GetUUID(), arg.Attrs, logStore.GetConfigData().GetContent(), bat, mp)
   322  				if err != nil {
   323  					return false, err
   324  				}
   325  			}
   326  		}
   327  
   328  		// fill batch for proxy
   329  		for _, proxyStore := range details.GetProxyStores() {
   330  			if proxyStore.GetConfigData() != nil {
   331  				err = fillMapToBatch(
   332  					"proxy",
   333  					proxyStore.GetUUID(),
   334  					arg.Attrs,
   335  					proxyStore.GetConfigData().GetContent(),
   336  					bat,
   337  					mp,
   338  				)
   339  				if err != nil {
   340  					return false, err
   341  				}
   342  			}
   343  		}
   344  
   345  		bat.SetRowCount(bat.Vecs[0].Length())
   346  		result.Batch = bat
   347  		arg.ctr.state = dataFinished
   348  		return false, nil
   349  
   350  	case dataFinished:
   351  		result.Batch = nil
   352  		return true, nil
   353  	default:
   354  		return false, moerr.NewInternalError(proc.Ctx, "unknown state %v", arg.ctr.state)
   355  	}
   356  }
   357  
   358  func fillMapToBatch(nodeType, nodeId string, attrs []string, kvs map[string]*logservicepb.ConfigItem, bat *batch.Batch, mp *mpool.MPool) error {
   359  	var err error
   360  	for _, value := range kvs {
   361  		for i, col := range attrs {
   362  			col = strings.ToLower(col)
   363  			switch plan2.MoConfigColType(plan2.MoConfigColName2Index[col]) {
   364  			case plan2.MoConfigColTypeNodeType:
   365  				if err = vector.AppendBytes(bat.Vecs[i], []byte(nodeType), false, mp); err != nil {
   366  					return err
   367  				}
   368  			case plan2.MoConfigColTypeNodeId:
   369  				if err = vector.AppendBytes(bat.Vecs[i], []byte(nodeId), false, mp); err != nil {
   370  					return err
   371  				}
   372  			case plan2.MoConfigColTypeName:
   373  				if err = vector.AppendBytes(bat.Vecs[i], []byte(value.GetName()), false, mp); err != nil {
   374  					return err
   375  				}
   376  			case plan2.MoConfigColTypeCurrentValue:
   377  				if err = vector.AppendBytes(bat.Vecs[i], []byte(value.GetCurrentValue()), false, mp); err != nil {
   378  					return err
   379  				}
   380  			case plan2.MoConfigColTypeDefaultValue:
   381  				if err = vector.AppendBytes(bat.Vecs[i], []byte(value.GetDefaultValue()), false, mp); err != nil {
   382  					return err
   383  				}
   384  			case plan2.MoConfigColTypeInternal:
   385  				if err = vector.AppendBytes(bat.Vecs[i], []byte(value.GetInternal()), false, mp); err != nil {
   386  					return err
   387  				}
   388  			}
   389  		}
   390  	}
   391  	return err
   392  }
   393  
   394  func moTransactionsPrepare(proc *process.Process, arg *Argument) error {
   395  	arg.ctr.state = dataProducing
   396  	if len(arg.Args) > 0 {
   397  		return moerr.NewInvalidInput(proc.Ctx, "moTransactions: no argument is required")
   398  	}
   399  	for i := range arg.Attrs {
   400  		arg.Attrs[i] = strings.ToUpper(arg.Attrs[i])
   401  	}
   402  	return nil
   403  }
   404  
   405  func getRangeContent(li *query.TxnLockInfo) ([]byte, []byte) {
   406  	keys := li.GetRows()
   407  	llen := len(keys)
   408  	if llen >= 2 {
   409  		return keys[0], keys[1]
   410  	} else if llen >= 1 {
   411  		return keys[0], []byte{}
   412  	} else {
   413  		return []byte{}, []byte{}
   414  	}
   415  }
   416  
   417  func getPointContent(li *query.TxnLockInfo) []byte {
   418  	keys := li.GetRows()
   419  	llen := len(keys)
   420  	if llen >= 1 {
   421  		return keys[0]
   422  	}
   423  	return []byte{}
   424  }
   425  
   426  func moTransactionsCall(_ int, proc *process.Process, arg *Argument, result *vm.CallResult) (bool, error) {
   427  	switch arg.ctr.state {
   428  	case dataProducing:
   429  
   430  		rsps, err := getTxns(proc)
   431  		if err != nil {
   432  			return false, err
   433  		}
   434  
   435  		//alloc batch
   436  		bat := batch.NewWithSize(len(arg.Attrs))
   437  		for i, col := range arg.Attrs {
   438  			col = strings.ToLower(col)
   439  			idx, ok := plan2.MoTransactionsColName2Index[col]
   440  			if !ok {
   441  				return false, moerr.NewInternalError(proc.Ctx, "bad input select columns name %v", col)
   442  			}
   443  
   444  			tp := plan2.MoTransactionsColTypes[idx]
   445  			bat.Vecs[i] = proc.GetVector(tp)
   446  		}
   447  		bat.Attrs = arg.Attrs
   448  		for _, rsp := range rsps {
   449  			if rsp == nil || len(rsp.TxnInfoList) == 0 {
   450  				continue
   451  			}
   452  
   453  			for _, txn := range rsp.TxnInfoList {
   454  				if txn == nil {
   455  					continue
   456  				}
   457  
   458  				cnId := rsp.GetCnId()
   459  				txnId := ""
   460  				if txn.GetMeta() != nil {
   461  					txnId = hex.EncodeToString(txn.GetMeta().GetID())
   462  				}
   463  				createTs := txn.GetCreateAt().Format(time.RFC3339Nano)
   464  				snapshotTs := ""
   465  				if txn.GetMeta() != nil {
   466  					snapshotTs = txn.GetMeta().GetSnapshotTS().DebugString()
   467  				}
   468  				preparedTs := ""
   469  				if txn.GetMeta() != nil {
   470  					preparedTs = txn.GetMeta().GetPreparedTS().DebugString()
   471  				}
   472  				commitTs := ""
   473  				if txn.GetMeta() != nil {
   474  					commitTs = txn.GetMeta().GetCommitTS().DebugString()
   475  				}
   476  				txnMode := ""
   477  				if txn.GetMeta() != nil {
   478  					txnMode = txn.GetMeta().GetMode().String()
   479  				}
   480  				isolation := ""
   481  				if txn.GetMeta() != nil {
   482  					isolation = txn.GetMeta().GetIsolation().String()
   483  				}
   484  				userTxn := strconv.FormatBool(txn.GetUserTxn())
   485  				txnStatus := ""
   486  				if txn.GetMeta() != nil {
   487  					txnStatus = txn.GetMeta().GetStatus().String()
   488  				}
   489  
   490  				waitLocksCnt := len(txn.GetWaitLocks())
   491  				record := make([][]byte, len(plan2.MoTransactionsColNames))
   492  				record[plan2.MoTransactionsColTypeCnId] = []byte(cnId)
   493  				record[plan2.MoTransactionsColTypeTxnId] = []byte(txnId)
   494  				record[plan2.MoTransactionsColTypeCreateTs] = []byte(createTs)
   495  				record[plan2.MoTransactionsColTypeSnapshotTs] = []byte(snapshotTs)
   496  				record[plan2.MoTransactionsColTypePreparedTs] = []byte(preparedTs)
   497  				record[plan2.MoTransactionsColTypeCommitTs] = []byte(commitTs)
   498  				record[plan2.MoTransactionsColTypeTxnMode] = []byte(txnMode)
   499  				record[plan2.MoTransactionsColTypeIsolation] = []byte(isolation)
   500  				record[plan2.MoTransactionsColTypeUserTxn] = []byte(userTxn)
   501  				record[plan2.MoTransactionsColTypeTxnStatus] = []byte(txnStatus)
   502  
   503  				if waitLocksCnt == 0 {
   504  					//one record
   505  					record[plan2.MoTransactionsColTypeTableId] = []byte{}
   506  					record[plan2.MoTransactionsColTypeLockKey] = []byte{}
   507  					record[plan2.MoTransactionsColTypeLockContent] = []byte{}
   508  					record[plan2.MoTransactionsColTypeLockMode] = []byte{}
   509  
   510  					if err := fillTxnRecord(proc, arg.Attrs, bat, record); err != nil {
   511  						return false, err
   512  					}
   513  				} else {
   514  					//multiple records
   515  
   516  					for _, lock := range txn.GetWaitLocks() {
   517  						options := lock.GetOptions()
   518  						if options == nil {
   519  							continue
   520  						}
   521  
   522  						//table id
   523  						tableId := fmt.Sprintf("%d", lock.GetTableId())
   524  						record[plan2.MoTransactionsColTypeTableId] = []byte(tableId)
   525  
   526  						//lock key
   527  						lockKey := "point"
   528  						if options.GetGranularity() == pblock.Granularity_Range {
   529  							lockKey = "range"
   530  						}
   531  						record[plan2.MoTransactionsColTypeLockKey] = []byte(lockKey)
   532  
   533  						//lock content
   534  						lockContent := ""
   535  						if options.GetGranularity() == pblock.Granularity_Range {
   536  							//first range
   537  							k1, k2 := getRangeContent(lock)
   538  							lockContent = hex.EncodeToString(k1) + "," + hex.EncodeToString(k2)
   539  						} else {
   540  							lockContent = hex.EncodeToString(getPointContent(lock))
   541  						}
   542  						record[plan2.MoTransactionsColTypeLockContent] = []byte(lockContent)
   543  
   544  						//lock mode
   545  						lockMode := options.GetMode().String()
   546  						record[plan2.MoTransactionsColTypeLockMode] = []byte(lockMode)
   547  
   548  						if err := fillTxnRecord(proc, arg.Attrs, bat, record); err != nil {
   549  							return false, err
   550  						}
   551  					}
   552  				}
   553  
   554  			}
   555  		}
   556  
   557  		bat.SetRowCount(bat.Vecs[0].Length())
   558  		result.Batch = bat
   559  		arg.ctr.state = dataFinished
   560  		return false, nil
   561  
   562  	case dataFinished:
   563  		return true, nil
   564  	default:
   565  		return false, moerr.NewInternalError(proc.Ctx, "unknown state %v", arg.ctr.state)
   566  	}
   567  }
   568  
   569  func fillTxnRecord(proc *process.Process, attrs []string, bat *batch.Batch, record [][]byte) error {
   570  	for colIdx, attr := range attrs {
   571  		realColIdx := plan2.MoTransactionsColName2Index[strings.ToLower(attr)]
   572  		if err := vector.AppendBytes(bat.Vecs[colIdx], record[realColIdx], false, proc.GetMPool()); err != nil {
   573  			return err
   574  		}
   575  	}
   576  	return nil
   577  }
   578  
   579  // getTxns get txn info from all cn
   580  func getTxns(proc *process.Process) ([]*query.GetTxnInfoResponse, error) {
   581  	var err error
   582  	var nodes []string
   583  
   584  	selectSuperTenant(clusterservice.NewSelector(), "root", nil,
   585  		func(s *metadata.CNService) {
   586  			nodes = append(nodes, s.QueryAddress)
   587  		})
   588  
   589  	genRequest := func() *query.Request {
   590  		req := proc.QueryClient.NewRequest(query.CmdMethod_GetTxnInfo)
   591  		req.GetTxnInfoRequest = &query.GetTxnInfoRequest{}
   592  		return req
   593  	}
   594  
   595  	rsps := make([]*query.GetTxnInfoResponse, 0)
   596  
   597  	handleValidResponse := func(nodeAddr string, rsp *query.Response) {
   598  		if rsp != nil && rsp.GetTxnInfoResponse != nil {
   599  			rsps = append(rsps, rsp.GetTxnInfoResponse)
   600  		}
   601  	}
   602  
   603  	err = requestMultipleCn(proc.Ctx, nodes, proc.QueryClient, genRequest, handleValidResponse, nil)
   604  	return rsps, err
   605  }
   606  
   607  func moCachePrepare(proc *process.Process, arg *Argument) error {
   608  	arg.ctr.state = dataProducing
   609  	if len(arg.Args) > 0 {
   610  		return moerr.NewInvalidInput(proc.Ctx, "moCache: no argument is required")
   611  	}
   612  	for i := range arg.Attrs {
   613  		arg.Attrs[i] = strings.ToUpper(arg.Attrs[i])
   614  	}
   615  	return nil
   616  }
   617  
   618  func moCacheCall(_ int, proc *process.Process, arg *Argument, result *vm.CallResult) (bool, error) {
   619  	switch arg.ctr.state {
   620  	case dataProducing:
   621  
   622  		rsps, err := getCacheStats(proc)
   623  		if err != nil {
   624  			return false, err
   625  		}
   626  
   627  		//alloc batch
   628  		bat := batch.NewWithSize(len(arg.Attrs))
   629  		for i, col := range arg.Attrs {
   630  			col = strings.ToLower(col)
   631  			idx, ok := plan2.MoCacheColName2Index[col]
   632  			if !ok {
   633  				return false, moerr.NewInternalError(proc.Ctx, "bad input select columns name %v", col)
   634  			}
   635  
   636  			tp := plan2.MoCacheColTypes[idx]
   637  			bat.Vecs[i] = proc.GetVector(tp)
   638  		}
   639  		bat.Attrs = arg.Attrs
   640  		for _, rsp := range rsps {
   641  			if rsp == nil || len(rsp.CacheInfoList) == 0 {
   642  				continue
   643  			}
   644  
   645  			for _, cache := range rsp.CacheInfoList {
   646  				if cache == nil {
   647  					continue
   648  				}
   649  
   650  				if err = fillCacheRecord(proc, arg.Attrs, bat, cache); err != nil {
   651  					return false, err
   652  				}
   653  			}
   654  		}
   655  
   656  		bat.SetRowCount(bat.Vecs[0].Length())
   657  		result.Batch = bat
   658  		arg.ctr.state = dataFinished
   659  		return false, nil
   660  
   661  	case dataFinished:
   662  		result.Batch = nil
   663  		return true, nil
   664  	default:
   665  		return false, moerr.NewInternalError(proc.Ctx, "unknown state %v", arg.ctr.state)
   666  	}
   667  }
   668  
   669  func fillCacheRecord(proc *process.Process, attrs []string, bat *batch.Batch, cache *query.CacheInfo) error {
   670  	var err error
   671  	for colIdx, attr := range attrs {
   672  		switch plan2.MoCacheColType(plan2.MoCacheColName2Index[strings.ToLower(attr)]) {
   673  		case plan2.MoCacheColTypeNodeType:
   674  			if err = vector.AppendBytes(bat.Vecs[colIdx], []byte(cache.GetNodeType()), false, proc.GetMPool()); err != nil {
   675  				return err
   676  			}
   677  		case plan2.MoCacheColTypeNodeId:
   678  			if err = vector.AppendBytes(bat.Vecs[colIdx], []byte(cache.GetNodeId()), false, proc.GetMPool()); err != nil {
   679  				return err
   680  			}
   681  		case plan2.MoCacheColTypeType:
   682  			if err = vector.AppendBytes(bat.Vecs[colIdx], []byte(cache.GetCacheType()), false, proc.GetMPool()); err != nil {
   683  				return err
   684  			}
   685  		case plan2.MoCacheColTypeUsed:
   686  			if err = vector.AppendFixed(bat.Vecs[colIdx], cache.GetUsed(), false, proc.GetMPool()); err != nil {
   687  				return err
   688  			}
   689  		case plan2.MoCacheColTypeFree:
   690  			if err = vector.AppendFixed(bat.Vecs[colIdx], cache.GetFree(), false, proc.GetMPool()); err != nil {
   691  				return err
   692  			}
   693  		case plan2.MoCacheColTypeHitRatio:
   694  			if err = vector.AppendFixed(bat.Vecs[colIdx], cache.GetHitRatio(), false, proc.GetMPool()); err != nil {
   695  				return err
   696  			}
   697  		}
   698  	}
   699  
   700  	return err
   701  }
   702  
   703  // getCacheStats get txn info from all cn, tn
   704  func getCacheStats(proc *process.Process) ([]*query.GetCacheInfoResponse, error) {
   705  	var err error
   706  	var nodes []string
   707  
   708  	selectSuperTenant(clusterservice.NewSelector(), "root", nil,
   709  		func(s *metadata.CNService) {
   710  			nodes = append(nodes, s.QueryAddress)
   711  		})
   712  
   713  	listTnService(func(s *metadata.TNService) {
   714  		nodes = append(nodes, s.QueryAddress)
   715  	})
   716  
   717  	genRequest := func() *query.Request {
   718  		req := proc.QueryClient.NewRequest(query.CmdMethod_GetCacheInfo)
   719  		req.GetCacheInfoRequest = &query.GetCacheInfoRequest{}
   720  		return req
   721  	}
   722  
   723  	rsps := make([]*query.GetCacheInfoResponse, 0)
   724  
   725  	handleValidResponse := func(nodeAddr string, rsp *query.Response) {
   726  		if rsp != nil && rsp.GetCacheInfoResponse != nil {
   727  			rsps = append(rsps, rsp.GetCacheInfoResponse)
   728  		}
   729  	}
   730  
   731  	err = requestMultipleCn(proc.Ctx, nodes, proc.QueryClient, genRequest, handleValidResponse, nil)
   732  	return rsps, err
   733  }
   734  
   735  var selectSuperTenant = func(selector clusterservice.Selector,
   736  	username string,
   737  	filter func(string) bool,
   738  	appendFn func(service *metadata.CNService)) {
   739  	clusterservice.GetMOCluster().GetCNService(
   740  		clusterservice.NewSelectAll(), func(s metadata.CNService) bool {
   741  			appendFn(&s)
   742  			return true
   743  		})
   744  }
   745  
   746  var listTnService = func(appendFn func(service *metadata.TNService)) {
   747  	disttae.ListTnService(appendFn)
   748  }
   749  
   750  var requestMultipleCn = func(ctx context.Context, nodes []string, qc qclient.QueryClient, genRequest func() *query.Request, handleValidResponse func(string, *query.Response), handleInvalidResponse func(string)) error {
   751  	return queryservice.RequestMultipleCn(ctx, nodes, qc, genRequest, handleValidResponse, handleInvalidResponse)
   752  }