github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/function/ctl/cmd_rpc_version.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 ctl
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strconv"
    21  	"strings"
    22  	"time"
    23  
    24  	"github.com/matrixorigin/matrixone/pkg/clusterservice"
    25  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    26  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    27  	querypb "github.com/matrixorigin/matrixone/pkg/pb/query"
    28  	qclient "github.com/matrixorigin/matrixone/pkg/queryservice/client"
    29  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    30  )
    31  
    32  func handleGetProtocolVersion(proc *process.Process,
    33  	service serviceType,
    34  	parameter string,
    35  	sender requestSender) (Result, error) {
    36  	qt := proc.QueryClient
    37  	mc := clusterservice.GetMOCluster()
    38  	var addrs []string
    39  	var nodeIds []string
    40  	mc.GetCNService(
    41  		clusterservice.NewSelector(),
    42  		func(c metadata.CNService) bool {
    43  			addrs = append(addrs, c.QueryAddress)
    44  			nodeIds = append(nodeIds, c.ServiceID)
    45  			return true
    46  		})
    47  	mc.GetTNService(
    48  		clusterservice.NewSelector(),
    49  		func(d metadata.TNService) bool {
    50  			if d.QueryAddress != "" {
    51  				addrs = append(addrs, d.QueryAddress)
    52  				nodeIds = append(nodeIds, d.ServiceID)
    53  			}
    54  			return true
    55  		})
    56  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
    57  	defer cancel()
    58  
    59  	versions := make([]string, 0, len(addrs))
    60  	for i, addr := range addrs {
    61  		req := qt.NewRequest(querypb.CmdMethod_GetProtocolVersion)
    62  		req.GetProtocolVersion = &querypb.GetProtocolVersionRequest{}
    63  		resp, err := qt.SendMessage(ctx, addr, req)
    64  		if err != nil {
    65  			return Result{}, err
    66  		}
    67  		versions = append(versions, fmt.Sprintf("%s:%d", nodeIds[i], resp.GetProtocolVersion.Version))
    68  		qt.Release(resp)
    69  	}
    70  
    71  	return Result{
    72  		Method: GetProtocolVersionMethod,
    73  		Data:   strings.Join(versions, ", "),
    74  	}, nil
    75  }
    76  
    77  // handleSetProtocolVersion sets the version of mo components' protocol versions
    78  //
    79  // the cmd format for CN service:
    80  //
    81  //	mo_ctl("cn", "SetProtocolVersion" "uuids of cn:protocol version")
    82  //
    83  // examples as below:
    84  //
    85  //	mo_ctl("cn", "SetProtocolVersion", "cn_uuid1:1")
    86  //	mo_ctl("cn", "SetProtocolVersion", "cn_uuid1,cn_uuid2,...:2")
    87  //
    88  // the cmd format for TN service:
    89  //
    90  //	mo_ctl("dn", "SetProtocolVersion", "protocol version")
    91  //
    92  // (because there only exist one dn service, so we don't need to specify the uuid,
    93  //
    94  //	but, the uuid will be ignored and will not check its validation even though it is specified.)
    95  //
    96  // examples as below:
    97  // mo_ctl("dn", "SetProtocolVersion", "1")
    98  func handleSetProtocolVersion(proc *process.Process,
    99  	service serviceType,
   100  	parameter string,
   101  	sender requestSender) (Result, error) {
   102  	qt := proc.QueryClient
   103  	targets, version, err := checkProtocolParameter(parameter)
   104  	if err != nil {
   105  		return Result{}, err
   106  	}
   107  	if service == tn && targets == nil {
   108  		// set protocol version for tn node
   109  		// there only exist one tn node, so we don't need to specify the uuid
   110  		return transferToTN(qt, version)
   111  	}
   112  
   113  	if service == cn && targets != nil {
   114  		versions := make([]string, 0, len(targets))
   115  		for _, target := range targets {
   116  			resp, err := transferToCN(qt, target, version)
   117  			if err != nil {
   118  				return Result{}, err
   119  			}
   120  			if resp == nil {
   121  				return Result{}, moerr.NewInternalErrorNoCtx("no such cn service")
   122  			}
   123  			versions = append(versions, fmt.Sprintf("%s:%d", target, resp.SetProtocolVersion.Version))
   124  		}
   125  
   126  		return Result{
   127  			Method: SetProtocolVersionMethod,
   128  			Data:   strings.Join(versions, ", "),
   129  		}, nil
   130  	}
   131  
   132  	return Result{}, moerr.NewInternalError(proc.Ctx, "unsupported cmd")
   133  }
   134  
   135  func checkProtocolParameter(param string) ([]string, int64, error) {
   136  	param = strings.ToLower(param)
   137  	// [uuids]:version
   138  	args := strings.Split(param, ":")
   139  	if len(args) > 2 {
   140  		return nil, 0, moerr.NewInternalErrorNoCtx("cmd invalid, too many ':'")
   141  	}
   142  	version, err := strconv.ParseInt(args[len(args)-1], 10, 64)
   143  	if err != nil {
   144  		return nil, 0, moerr.NewInternalErrorNoCtx("cmd invalid, expected version number")
   145  	}
   146  
   147  	if len(args) == 2 {
   148  		arg := args[0]
   149  		targets := strings.Split(arg, ",")
   150  		return targets, version, nil
   151  	}
   152  
   153  	return nil, version, nil
   154  }
   155  
   156  func transferToTN(qt qclient.QueryClient, version int64) (Result, error) {
   157  	var addr string
   158  	var resp *querypb.Response
   159  	var err error
   160  	clusterservice.GetMOCluster().GetTNService(
   161  		clusterservice.NewSelector(),
   162  		func(t metadata.TNService) bool {
   163  			if t.QueryAddress == "" {
   164  				return true
   165  			}
   166  			ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   167  			defer cancel()
   168  			req := qt.NewRequest(querypb.CmdMethod_SetProtocolVersion)
   169  			req.SetProtocolVersion = &querypb.SetProtocolVersionRequest{
   170  				Version: version,
   171  			}
   172  			resp, err = qt.SendMessage(ctx, addr, req)
   173  			return true
   174  		})
   175  	if err != nil {
   176  		return Result{}, err
   177  	}
   178  	if resp == nil {
   179  		return Result{}, moerr.NewInternalErrorNoCtx("no such tn service")
   180  	}
   181  	defer qt.Release(resp)
   182  	return Result{
   183  		Method: SetProtocolVersionMethod,
   184  		Data:   strconv.FormatInt(resp.SetProtocolVersion.Version, 10),
   185  	}, nil
   186  }
   187  
   188  func transferToCN(qt qclient.QueryClient, target string, version int64) (resp *querypb.Response, err error) {
   189  	clusterservice.GetMOCluster().GetCNService(
   190  		clusterservice.NewServiceIDSelector(target),
   191  		func(cn metadata.CNService) bool {
   192  			req := qt.NewRequest(querypb.CmdMethod_SetProtocolVersion)
   193  			req.SetProtocolVersion = &querypb.SetProtocolVersionRequest{
   194  				Version: version,
   195  			}
   196  			ctx, cancel := context.WithTimeout(context.Background(), time.Second)
   197  			defer cancel()
   198  
   199  			resp, err = qt.SendMessage(ctx, cn.QueryAddress, req)
   200  			return true
   201  		})
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  	return resp, nil
   206  }