[etcd] WithMaxCreateRev 和 WithRev 的区别

阅读 etcd 分布式锁 mutex 的源码时,遇到 waitDeletes 函数

func waitDeletes(ctx context.Context, client *v3.Client, pfx string, maxCreateRev int64) (*pb.ResponseHeader, error) {
     
	getOpts := append(v3.WithLastCreate(), v3.WithMaxCreateRev(maxCreateRev))
	for {
     
		resp, err := client.Get(ctx, pfx, getOpts...)
		if err != nil {
     
			return nil, err
		}
		if len(resp.Kvs) == 0 {
     
			return resp.Header, nil
		}
		lastKey := string(resp.Kvs[0].Key)
		if err = waitDelete(ctx, client, lastKey, resp.Header.Revision); err != nil {
     
			return nil, err
		}
	}
}

getOpts := append(v3.WithLastCreate(), v3.WithMaxCreateRev(maxCreateRev)) 这个语句不是特别理解


etcd 中插入原始数据

$ etcdctl --endpoints=http://127.0.0.1:10001 put k1 v1 -w json
{
     "header":{
     "cluster_id":18293669711776909085,"member_id":8241799522139745222,"revision":2,"raft_term":2}}
$ etcdctl --endpoints=http://127.0.0.1:10001 put k2 v2 -w json
{
     "header":{
     "cluster_id":18293669711776909085,"member_id":8241799522139745222,"revision":3,"raft_term":2}}
$ etcdctl --endpoints=http://127.0.0.1:10001 put k3 v3 -w json
{
     "header":{
     "cluster_id":18293669711776909085,"member_id":8241799522139745222,"revision":4,"raft_term":2}}
$ etcdctl --endpoints=http://127.0.0.1:10001 put k4 v4 -w json
{
     "header":{
     "cluster_id":18293669711776909085,"member_id":8241799522139745222,"revision":5,"raft_term":2}}
$ etcdctl --endpoints=http://127.0.0.1:10001 put k5 v5 -w json
{
     "header":{
     "cluster_id":18293669711776909085,"member_id":8241799522139745222,"revision":6,"raft_term":2}}
$ tcdctl --endpoints=http://127.0.0.1:10001 get k --prefix --keys-only
k1

k2

k3

k4

k5

包含 WithMaxCreateRev 的测试代码如下

package main

import (
	"context"
	"fmt"
	"go.etcd.io/etcd/clientv3"
	"log"
)

func main() {
     

	endpoints := []string{
     "127.0.0.1:10001", "127.0.0.1:10002", "127.0.0.1:10003"}
	cli, err := clientv3.New(clientv3.Config{
     Endpoints: endpoints})
	if err != nil {
     
		log.Fatal(err)
	}
	defer cli.Close()

	getOps := append(clientv3.WithLastCreate(), clientv3.WithMaxCreateRev(5))
	resp, err := cli.Get(context.TODO(), "k", getOps...)
	if err != nil {
     
		log.Fatal(err)
	}
	if len(resp.Kvs) != 0 {
     
		fmt.Printf("%s -> %s, create rev=%d, head rev=%d\n",
			string(resp.Kvs[0].Key),
			string(resp.Kvs[0].Value),
			resp.Kvs[0].CreateRevision,
			resp.Header.Revision)
	}

}

结合前述的 put 语句, k4 对应的 revision 值为 5,测试代码的 WithMaxCreateRev 也为 5,测试程序输出结果如下:

k4 -> v4, create rev=5, head rev=6

etcd 中删除 k4

$ etcdctl --endpoints=http://127.0.0.1:10001 del k4 -w json            
{
     "header":{
     "cluster_id":18293669711776909085,"member_id":8241799522139745222,"revision":7,"raft_term":2},"deleted":1}

重新运行测试程序运行结果如下"

k3 -> v3, create rev=4, head rev=7

据此可以得到以下结论

  1. 单纯 WithMaxCreateRev 是在当前 etcd 最新的 revision 上进行查询
  2. 要求被查询记录的 CreateRev 不能超过WithMaxCreateRev 设定值
  3. 当前最新的 revision7,测试对应的 k4 已经被删除了,所以 WithLastCreate 返回 k3 的结果

为了验证我们的结论,可以在测试程序的 getOps := append(clientv3.WithLastCreate(), clientv3.WithMaxCreateRev(5)) 添加 clientv3.WithRev(6),完整测试代码如下:

package main

import (
	"context"
	"fmt"
	"go.etcd.io/etcd/clientv3"
	"log"
)

func main() {
     

	endpoints := []string{
     "127.0.0.1:10001", "127.0.0.1:10002", "127.0.0.1:10003"}
	cli, err := clientv3.New(clientv3.Config{
     Endpoints: endpoints})
	if err != nil {
     
		log.Fatal(err)
	}
	defer cli.Close()

	getOps := append(clientv3.WithLastCreate(), clientv3.WithMaxCreateRev(5), clientv3.WithRev(6))
	resp, err := cli.Get(context.TODO(), "k", getOps...)
	if err != nil {
     
		log.Fatal(err)
	}
	if len(resp.Kvs) != 0 {
     
		fmt.Printf("%s -> %s, create rev=%d, head rev=%d\n",
			string(resp.Kvs[0].Key),
			string(resp.Kvs[0].Value),
			resp.Kvs[0].CreateRevision,
			resp.Header.Revision)
	}
	
}

程序输出结果如下:

k4 -> v4, create rev=5, head rev=7

在新的测试程序中,指定在 revision6 上进行查询,这个条件下 k4 并没有被删除,所以 WithLastCreate 返回 k4


结论

  1. WithMaxCreateRevWithRev 没有任何关系,这是两个不同维度的参数
  2. WithRev 指定了在哪个 snapshot 上进行查询
  3. WithMaxCreateRev 过滤当前 snapshotCreateRev 不大于 WithMaxCreateRev 的记录

你可能感兴趣的:(etcd,go,Linux)