github.com/matrixorigin/matrixone@v1.2.0/pkg/cnservice/server_query.go (about)

     1  // Copyright 2021 - 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 cnservice
    16  
    17  import (
    18  	"context"
    19  
    20  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    21  	"github.com/matrixorigin/matrixone/pkg/defines"
    22  	"github.com/matrixorigin/matrixone/pkg/fileservice"
    23  	"github.com/matrixorigin/matrixone/pkg/lockservice"
    24  	"github.com/matrixorigin/matrixone/pkg/logutil"
    25  	pblock "github.com/matrixorigin/matrixone/pkg/pb/lock"
    26  	"github.com/matrixorigin/matrixone/pkg/pb/query"
    27  	"github.com/matrixorigin/matrixone/pkg/pb/status"
    28  	"github.com/matrixorigin/matrixone/pkg/pb/task"
    29  	"github.com/matrixorigin/matrixone/pkg/pb/txn"
    30  	"github.com/matrixorigin/matrixone/pkg/perfcounter"
    31  	"github.com/matrixorigin/matrixone/pkg/queryservice"
    32  	qclient "github.com/matrixorigin/matrixone/pkg/queryservice/client"
    33  	"github.com/matrixorigin/matrixone/pkg/sql/plan/function/ctl"
    34  	"github.com/matrixorigin/matrixone/pkg/txn/client"
    35  )
    36  
    37  func (s *service) initQueryService() error {
    38  	if s.gossipNode != nil {
    39  		s.gossipNode.SetListenAddrFn(s.gossipListenAddr)
    40  		s.gossipNode.SetServiceAddrFn(s.gossipServiceAddr)
    41  		s.gossipNode.SetCacheServerAddrFn(s.queryServiceServiceAddr)
    42  		if err := s.gossipNode.Create(); err != nil {
    43  			return err
    44  		}
    45  	}
    46  
    47  	var err error
    48  	s.queryService, err = queryservice.NewQueryService(s.cfg.UUID,
    49  		s.queryServiceListenAddr(), s.cfg.RPC)
    50  	if err != nil {
    51  		return err
    52  	}
    53  	s.initQueryCommandHandler()
    54  
    55  	s.queryClient, err = qclient.NewQueryClient(s.cfg.UUID, s.cfg.RPC)
    56  	if err != nil {
    57  		return err
    58  	}
    59  	return nil
    60  }
    61  
    62  func (s *service) initQueryCommandHandler() {
    63  	s.queryService.AddHandleFunc(query.CmdMethod_KillConn, s.handleKillConn, false)
    64  	s.queryService.AddHandleFunc(query.CmdMethod_AlterAccount, s.handleAlterAccount, false)
    65  	s.queryService.AddHandleFunc(query.CmdMethod_TraceSpan, s.handleTraceSpan, false)
    66  	s.queryService.AddHandleFunc(query.CmdMethod_GetLockInfo, s.handleGetLockInfo, false)
    67  	s.queryService.AddHandleFunc(query.CmdMethod_GetTxnInfo, s.handleGetTxnInfo, false)
    68  	s.queryService.AddHandleFunc(query.CmdMethod_GetCacheInfo, s.handleGetCacheInfo, false)
    69  	s.queryService.AddHandleFunc(query.CmdMethod_SyncCommit, s.handleSyncCommit, false)
    70  	s.queryService.AddHandleFunc(query.CmdMethod_GetCommit, s.handleGetCommit, false)
    71  	s.queryService.AddHandleFunc(query.CmdMethod_ShowProcessList, s.handleShowProcessList, false)
    72  	s.queryService.AddHandleFunc(query.CmdMethod_RunTask, s.handleRunTask, false)
    73  	s.queryService.AddHandleFunc(query.CmdMethod_RemoveRemoteLockTable, s.handleRemoveRemoteLockTable, false)
    74  	s.queryService.AddHandleFunc(query.CmdMethod_UnsubscribeTable, s.handleUnsubscribeTable, false)
    75  	s.queryService.AddHandleFunc(query.CmdMethod_GetCacheData, s.handleGetCacheData, false)
    76  	s.queryService.AddHandleFunc(query.CmdMethod_GetStatsInfo, s.handleGetStatsInfo, false)
    77  	s.queryService.AddHandleFunc(query.CmdMethod_GetPipelineInfo, s.handleGetPipelineInfo, false)
    78  	s.queryService.AddHandleFunc(query.CmdMethod_MigrateConnFrom, s.handleMigrateConnFrom, false)
    79  	s.queryService.AddHandleFunc(query.CmdMethod_MigrateConnTo, s.handleMigrateConnTo, false)
    80  }
    81  
    82  func (s *service) handleKillConn(ctx context.Context, req *query.Request, resp *query.Response) error {
    83  	if req == nil || req.KillConnRequest == nil {
    84  		return moerr.NewInternalError(ctx, "bad request")
    85  	}
    86  	rm := s.mo.GetRoutineManager()
    87  	if rm == nil {
    88  		return moerr.NewInternalError(ctx, "routine manager not initialized")
    89  	}
    90  	accountMgr := rm.GetAccountRoutineManager()
    91  	if accountMgr == nil {
    92  		return moerr.NewInternalError(ctx, "account routine manager not initialized")
    93  	}
    94  
    95  	accountMgr.EnKillQueue(req.KillConnRequest.AccountID, req.KillConnRequest.Version)
    96  	return nil
    97  }
    98  
    99  func (s *service) handleAlterAccount(ctx context.Context, req *query.Request, resp *query.Response) error {
   100  	if req == nil || req.AlterAccountRequest == nil {
   101  		return moerr.NewInternalError(ctx, "bad request")
   102  	}
   103  	rm := s.mo.GetRoutineManager()
   104  	if rm == nil {
   105  		return moerr.NewInternalError(ctx, "routine manager not initialized")
   106  	}
   107  	accountMgr := rm.GetAccountRoutineManager()
   108  	if accountMgr == nil {
   109  		return moerr.NewInternalError(ctx, "account routine manager not initialized")
   110  	}
   111  
   112  	accountMgr.AlterRoutineStatue(req.AlterAccountRequest.TenantId, req.AlterAccountRequest.Status)
   113  	return nil
   114  }
   115  
   116  func (s *service) handleTraceSpan(ctx context.Context, req *query.Request, resp *query.Response) error {
   117  	resp.TraceSpanResponse = new(query.TraceSpanResponse)
   118  	resp.TraceSpanResponse.Resp = ctl.SelfProcess(
   119  		req.TraceSpanRequest.Cmd, req.TraceSpanRequest.Spans, req.TraceSpanRequest.Threshold)
   120  	return nil
   121  }
   122  
   123  // handleGetLockInfo sends the lock info on current cn to another cn that needs.
   124  func (s *service) handleGetLockInfo(ctx context.Context, req *query.Request, resp *query.Response) error {
   125  	resp.GetLockInfoResponse = new(query.GetLockInfoResponse)
   126  
   127  	//get lock info from lock service in current cn
   128  	locks := make([]*query.LockInfo, 0)
   129  	getAllLocks := func(tableID uint64, keys [][]byte, lock lockservice.Lock) bool {
   130  		//need copy keys
   131  		info := &query.LockInfo{
   132  			TableId:     tableID,
   133  			Keys:        copyKeys(keys),
   134  			LockMode:    lock.GetLockMode(),
   135  			IsRangeLock: lock.IsRangeLock(),
   136  		}
   137  
   138  		lock.IterHolders(func(holder pblock.WaitTxn) bool {
   139  			info.Holders = append(info.Holders, copyWaitTxn(holder))
   140  			return true
   141  		})
   142  
   143  		lock.IterWaiters(func(waiter pblock.WaitTxn) bool {
   144  			info.Waiters = append(info.Waiters, copyWaitTxn(waiter))
   145  			return true
   146  		})
   147  
   148  		locks = append(locks, info)
   149  		return true
   150  	}
   151  
   152  	s.lockService.IterLocks(getAllLocks)
   153  
   154  	// fill the response
   155  	resp.GetLockInfoResponse.CnId = s.metadata.UUID
   156  	resp.GetLockInfoResponse.LockInfoList = locks
   157  	return nil
   158  }
   159  
   160  func (s *service) handleGetTxnInfo(ctx context.Context, req *query.Request, resp *query.Response) error {
   161  	resp.GetTxnInfoResponse = new(query.GetTxnInfoResponse)
   162  	txns := make([]*query.TxnInfo, 0)
   163  
   164  	s._txnClient.IterTxns(func(view client.TxnOverview) bool {
   165  		info := &query.TxnInfo{
   166  			CreateAt: view.CreateAt,
   167  			Meta:     copyTxnMeta(view.Meta),
   168  			UserTxn:  view.UserTxn,
   169  		}
   170  
   171  		for _, lock := range view.WaitLocks {
   172  			info.WaitLocks = append(info.WaitLocks, copyTxnInfo(lock))
   173  		}
   174  		txns = append(txns, info)
   175  		return true
   176  	})
   177  
   178  	resp.GetTxnInfoResponse.CnId = s.metadata.UUID
   179  	resp.GetTxnInfoResponse.TxnInfoList = txns
   180  	return nil
   181  }
   182  
   183  func (s *service) handleSyncCommit(ctx context.Context, req *query.Request, resp *query.Response) error {
   184  	s._txnClient.SyncLatestCommitTS(req.SycnCommit.LatestCommitTS)
   185  	return nil
   186  }
   187  
   188  func (s *service) handleGetCommit(ctx context.Context, req *query.Request, resp *query.Response) error {
   189  	resp.GetCommit = new(query.GetCommitResponse)
   190  	resp.GetCommit.CurrentCommitTS = s._txnClient.GetLatestCommitTS()
   191  	return nil
   192  }
   193  
   194  func (s *service) handleShowProcessList(ctx context.Context, req *query.Request, resp *query.Response) error {
   195  	if req.ShowProcessListRequest == nil {
   196  		return moerr.NewInternalError(ctx, "bad request")
   197  	}
   198  	sessions, err := s.processList(req.ShowProcessListRequest.Tenant,
   199  		req.ShowProcessListRequest.SysTenant)
   200  	if err != nil {
   201  		resp.WrapError(err)
   202  		return nil
   203  	}
   204  	resp.ShowProcessListResponse = &query.ShowProcessListResponse{
   205  		Sessions: sessions,
   206  	}
   207  	return nil
   208  }
   209  
   210  func (s *service) handleRunTask(ctx context.Context, req *query.Request, resp *query.Response) error {
   211  	if req.RunTask == nil {
   212  		return moerr.NewInternalError(ctx, "bad request")
   213  	}
   214  	s.task.Lock()
   215  	defer s.task.Unlock()
   216  
   217  	code := task.TaskCode(req.RunTask.TaskCode)
   218  	if s.task.runner == nil {
   219  		resp.RunTask = &query.RunTaskResponse{
   220  			Result: "Task Runner Not Ready",
   221  		}
   222  		return nil
   223  	}
   224  	exec := s.task.runner.GetExecutor(code)
   225  	if exec == nil {
   226  		resp.RunTask = &query.RunTaskResponse{
   227  			Result: "Task Not Found",
   228  		}
   229  		return nil
   230  	}
   231  	go func() {
   232  		_ = exec(context.Background(), &task.AsyncTask{
   233  			ID:       0,
   234  			Metadata: task.TaskMetadata{ID: code.String(), Executor: code},
   235  		})
   236  	}()
   237  	resp.RunTask = &query.RunTaskResponse{
   238  		Result: "OK",
   239  	}
   240  	return nil
   241  }
   242  
   243  // processList returns all the sessions. For sys tenant, return all sessions; but for common
   244  // tenant, just return the sessions belong to the tenant.
   245  // It is called "processList" is because it is used in "SHOW PROCESSLIST" statement.
   246  func (s *service) processList(tenant string, sysTenant bool) ([]*status.Session, error) {
   247  	if sysTenant {
   248  		return s.sessionMgr.GetAllStatusSessions(), nil
   249  	}
   250  	return s.sessionMgr.GetStatusSessionsByTenant(tenant), nil
   251  }
   252  
   253  func copyKeys(src [][]byte) [][]byte {
   254  	dst := make([][]byte, 0, len(src))
   255  	for _, s := range src {
   256  		d := make([]byte, len(s))
   257  		copy(d, s)
   258  		dst = append(dst, s)
   259  	}
   260  	return dst
   261  }
   262  
   263  func copyWaitTxn(src pblock.WaitTxn) *pblock.WaitTxn {
   264  	dst := &pblock.WaitTxn{}
   265  	dst.TxnID = make([]byte, len(src.TxnID))
   266  	copy(dst.TxnID, src.GetTxnID())
   267  	dst.CreatedOn = src.GetCreatedOn()
   268  	return dst
   269  }
   270  
   271  func copyBytes(src []byte) []byte {
   272  	dst := make([]byte, len(src))
   273  	copy(dst, src)
   274  	return dst
   275  }
   276  
   277  func copyTxnMeta(src txn.TxnMeta) *txn.TxnMeta {
   278  	dst := &txn.TxnMeta{
   279  		ID:         copyBytes(src.GetID()),
   280  		Status:     src.GetStatus(),
   281  		SnapshotTS: src.GetSnapshotTS(),
   282  		PreparedTS: src.GetPreparedTS(),
   283  		CommitTS:   src.GetCommitTS(),
   284  		Mode:       src.GetMode(),
   285  		Isolation:  src.GetIsolation(),
   286  	}
   287  	return dst
   288  }
   289  
   290  func copyLockOptions(src pblock.LockOptions) *pblock.LockOptions {
   291  	dst := &pblock.LockOptions{
   292  		Granularity: src.GetGranularity(),
   293  		Mode:        src.GetMode(),
   294  	}
   295  	return dst
   296  }
   297  
   298  func copyTxnInfo(src client.Lock) *query.TxnLockInfo {
   299  	dst := &query.TxnLockInfo{
   300  		TableId: src.TableID,
   301  		Rows:    copyKeys(src.Rows),
   302  		Options: copyLockOptions(src.Options),
   303  	}
   304  	return dst
   305  }
   306  
   307  func (s *service) handleGetCacheInfo(ctx context.Context, req *query.Request, resp *query.Response) error {
   308  	resp.GetCacheInfoResponse = new(query.GetCacheInfoResponse)
   309  
   310  	perfcounter.GetCacheStats(func(infos []*query.CacheInfo) {
   311  		for _, info := range infos {
   312  			if info != nil {
   313  				resp.GetCacheInfoResponse.CacheInfoList = append(resp.GetCacheInfoResponse.CacheInfoList, info)
   314  			}
   315  		}
   316  	})
   317  
   318  	return nil
   319  }
   320  
   321  func (s *service) handleRemoveRemoteLockTable(
   322  	ctx context.Context,
   323  	req *query.Request,
   324  	resp *query.Response) error {
   325  	removed, err := s.lockService.CloseRemoteLockTable(
   326  		req.RemoveRemoteLockTable.GroupID,
   327  		req.RemoveRemoteLockTable.TableID,
   328  		req.RemoveRemoteLockTable.Version)
   329  	if err != nil {
   330  		return err
   331  	}
   332  
   333  	resp.RemoveRemoteLockTable = &query.RemoveRemoteLockTableResponse{}
   334  	if removed {
   335  		resp.RemoveRemoteLockTable.Count = 1
   336  	}
   337  	return nil
   338  }
   339  
   340  func (s *service) handleUnsubscribeTable(ctx context.Context, req *query.Request, resp *query.Response) error {
   341  	if req.UnsubscribeTable == nil {
   342  		return moerr.NewInternalError(ctx, "bad request")
   343  	}
   344  	err := s.storeEngine.UnsubscribeTable(ctx, req.UnsubscribeTable.DatabaseID, req.UnsubscribeTable.TableID)
   345  	if err != nil {
   346  		resp.WrapError(err)
   347  		return nil
   348  	}
   349  	resp.UnsubscribeTable = &query.UnsubscribeTableResponse{
   350  		Success: true,
   351  	}
   352  	return nil
   353  }
   354  
   355  // handleGetCacheData reads the cache data from the local data cache in fileservice.
   356  func (s *service) handleGetCacheData(ctx context.Context, req *query.Request, resp *query.Response) error {
   357  	sharedFS, err := fileservice.Get[fileservice.FileService](s.fileService, defines.SharedFileServiceName)
   358  	if err != nil {
   359  		return err
   360  	}
   361  	wr := &query.WrappedResponse{
   362  		Response: resp,
   363  	}
   364  	err = fileservice.HandleRemoteRead(ctx, sharedFS, req, wr)
   365  	if err != nil {
   366  		return err
   367  	}
   368  	s.queryService.SetReleaseFunc(resp, wr.ReleaseFunc)
   369  	return nil
   370  }
   371  
   372  func (s *service) handleGetStatsInfo(ctx context.Context, req *query.Request, resp *query.Response) error {
   373  	if req.GetStatsInfoRequest == nil {
   374  		return moerr.NewInternalError(ctx, "bad request")
   375  	}
   376  	// The parameter sync is false, as the read request is from remote node,
   377  	// and we do not need wait for the data sync.
   378  	resp.GetStatsInfoResponse = &query.GetStatsInfoResponse{
   379  		StatsInfo: s.storeEngine.Stats(ctx, *req.GetStatsInfoRequest.StatsInfoKey, false),
   380  	}
   381  	return nil
   382  }
   383  
   384  // handleGetPipelineInfo handles the GetPipelineInfoRequest and respond with
   385  // the pipeline info in the server.
   386  func (s *service) handleGetPipelineInfo(ctx context.Context, req *query.Request, resp *query.Response) error {
   387  	if req.GetPipelineInfoRequest == nil {
   388  		return moerr.NewInternalError(ctx, "bad request")
   389  	}
   390  	count := s.pipelines.counter.Load()
   391  	resp.GetPipelineInfoResponse = &query.GetPipelineInfoResponse{
   392  		Count: count,
   393  	}
   394  	return nil
   395  }
   396  
   397  func (s *service) handleMigrateConnFrom(
   398  	ctx context.Context, req *query.Request, resp *query.Response,
   399  ) error {
   400  	if req.MigrateConnFromRequest == nil {
   401  		return moerr.NewInternalError(ctx, "bad request")
   402  	}
   403  	rm := s.mo.GetRoutineManager()
   404  	resp.MigrateConnFromResponse = &query.MigrateConnFromResponse{}
   405  	if err := rm.MigrateConnectionFrom(req.MigrateConnFromRequest, resp.MigrateConnFromResponse); err != nil {
   406  		logutil.Errorf("failed to migrate conn from: %v", err)
   407  		return err
   408  	}
   409  	return nil
   410  }
   411  
   412  func (s *service) handleMigrateConnTo(
   413  	ctx context.Context, req *query.Request, resp *query.Response,
   414  ) error {
   415  	if req.MigrateConnToRequest == nil {
   416  		return moerr.NewInternalError(ctx, "bad request")
   417  	}
   418  	rm := s.mo.GetRoutineManager()
   419  	if err := rm.MigrateConnectionTo(ctx, req.MigrateConnToRequest); err != nil {
   420  		logutil.Errorf("failed to migrate conn to: %v", err)
   421  		return err
   422  	}
   423  	logutil.Infof("migrate ok, conn ID: %d, DB: %s, prepared stmt count: %d",
   424  		req.MigrateConnToRequest.ConnID, req.MigrateConnToRequest.DB, len(req.MigrateConnToRequest.PrepareStmts))
   425  	for _, stmt := range req.MigrateConnToRequest.PrepareStmts {
   426  		logutil.Infof("migrated prepare stmt on conn %d, %s, %s", req.MigrateConnToRequest.ConnID, stmt.Name, stmt.SQL)
   427  	}
   428  	resp.MigrateConnToResponse = &query.MigrateConnToResponse{
   429  		Success: true,
   430  	}
   431  	return nil
   432  }