etcdctl的实现

在上一篇本地启动etcd之后,通过etcdctl命令来进行相关操作。这一篇记录一下etcdctl是如何实现的。

在源码中很容易找到相关目录:https://github.com/etcd-io/etcd/tree/main/etcdctl

目录下的README也有对这个命令行工具的相关介绍,不过我暂时比较感兴趣的是命令行是如何跟服务端进行交互的,因此现在先不对每个命令一个个都看一遍, 还是以基础的 GET/PUT 入手。

从目录下的main.go文件看进去, 命令行的实现都在ctlv3这个文件夹中,文件夹里的ctl.go 是命令行工具的初始化,而具体命令的实现在command文件夹下。

ctl.go 初始化命令行工具

etcdctl 使用cobra来实现命令行工具, 在init函数中解析参数并添加了支持的具体命令。

func init() {
	rootCmd.PersistentFlags().StringSliceVar(&globalFlags.Endpoints, "endpoints", []string{"127.0.0.1:2379"}, "gRPC endpoints")
	rootCmd.PersistentFlags().BoolVar(&globalFlags.Debug, "debug", false, "enable client-side debug logging")

	......

	rootCmd.AddCommand(
		command.NewGetCommand(),
		command.NewPutCommand(),
		command.NewDelCommand(),
		command.NewTxnCommand(),
                ......
	)
}

在执行函数中加载了命令行帮助模板并执行命令。

func usageFunc(c *cobra.Command) error {
	return cobrautl.UsageFunc(c, version.Version, version.APIVersion)
}

func Start() error {
	rootCmd.SetUsageFunc(usageFunc)
	// Make help just show the usage
	rootCmd.SetHelpTemplate(`{{.UsageString}}`)
	return rootCmd.Execute()
}

command 的实现

GetCommand

command/get_command.go 中定义了Get命令的实现,包括命令参数的解析和具体的执行逻辑函数。

cmd := &cobra.Command{
        Use:   "get [options] <key> [range_end]",
        Short: "Gets the key or a range of keys",
        Run:   getCommandFunc,
}

getCommandFunc 中先通过getGetOp解析命令, 得到查询的key 和命令的相关选项,每个操作选项都被封装成一个函数类型, 传入参数为Op的指针并在函数内部对Op的属性进行修改。

// OpOption configures Operations like Get, Put, Delete.
type OpOption func(*Op)

// Op represents an Operation that kv can execute.
type Op struct {
	t   opType
	key []byte
	end []byte

	// for range
	limit        int64
	sort         *SortOption
	serializable bool
	keysOnly     bool
	countOnly    bool
	minModRev    int64
	maxModRev    int64
	minCreateRev int64
	maxCreateRev int64

	// for range, watch
	rev int64

	// for watch, put, delete
	prevKV bool

	// for watch
	// fragmentation should be disabled by default
	// if true, split watch events when total exceeds
	// "--max-request-bytes" flag value + 512-byte
	fragment bool

	// for put
	ignoreValue bool
	ignoreLease bool

	// progressNotify is for progress updates.
	progressNotify bool
	// createdNotify is for created event
	createdNotify bool
	// filters for watchers
	filterPut    bool
	filterDelete bool

	// for put
	val     []byte
	leaseID LeaseID

	// txn
	cmps    []Cmp
	thenOps []Op
	elseOps []Op

	isOptsWithFromKey bool
	isOptsWithPrefix  bool
}

得到key 和 Options的数组后, 会创建grpc client来处理grpc请求, 并通过display将请求结果打印出来。

// getCommandFunc executes the "get" command.
func getCommandFunc(cmd *cobra.Command, args []string) {
    key, opts := getGetOp(args)
    ctx, cancel := commandCtx(cmd)
    resp, err := mustClientFromCmd(cmd).Get(ctx, key, opts...)
    cancel()
	
    ...
        
    display.Get(*resp)
}

针对command文件夹下的其他命令也都是大概差不多的流程:解析命令->grpc请求->展示结果,主要的实现就是通过cobra构建的命令行工具和对应的grpc请求。后面会看一下在服务端, PUT和GET请求究竟是如何做的, 既然GET查询支持排序,键值的内容是否通过什么索引结构进行存储的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值