package clientv3

import (
    pb "github.com/coreos/etcd/etcdserver/etcdserverpb"   //protobuffer  
    "golang.org/x/net/context"  
    "google.golang.org/grpc"   //google  rpc 框架
)

type (
    CompactResponse pb.CompactionResponse  //带压缩的响应
    PutResponse     pb.PutResponse   //添加响应
    GetResponse     pb.RangeResponse  // 带区间的响应
    DeleteResponse  pb.DeleteRangeResponse  // 删除带区间数据的响应
    TxnResponse     pb.TxnResponse    //带事务的响应
)

type KV interface {
    // Put puts a key-value pair into etcd.
        //添加键值对到etcd中
    // Note that key,value can be plain bytes array and string is
    // an immutable representation of that bytes array.
       //注意:键值对可以是字节数组或者字符串  字符串是原子性的字节数组
    // To get a string of bytes, do string([]byte(0x10, 0x20)).
        //
    Put(ctx context.Context, key, val string, opts ...OpOption) (*PutResponse, error)

    // Get retrieves keys.
        //获取键对应的值
    // By default, Get will return the value for "key", if any.
        //默认 获取键对应的值  在任何情况下
    // When passed WithRange(end), Get will return the keys in the range [key, end).
        //当opts 使用了 WithRange(end),将得到键对应的区间[key, end)之间的值
    // When passed WithFromKey(), Get returns keys greater than or equal to key.
             //opts 使用了WithFromKey(),得到大于等于当前key 对应的value
    // When passed WithRev(rev) with rev > 0, Get retrieves keys at the given revision;
                //当opts 使用了 WithRev(rev),如果版本号rev>0 获取指定的版本号对应的value
    // if the required revision is compacted, the request will fail with ErrCompacted .
    // When passed WithLimit(limit), the number of returned keys is bounded by limit.
             //当opts 使用了 WithLimit(limit),将得到键对应的区间[key最小值  默认的   end [limit   )的值   例如:  key为 foo   实际的key为 fooN。。。。到foolimit  之间对应的value
    // When passed WithSort(), the keys will be sorted.
             //当opts 使用了 WithSort(),得到的值将排序  按照字典的顺序来排序
    Get(ctx context.Context, key string, opts ...OpOption) (*GetResponse, error)

    // Delete deletes a key, or optionally using WithRange(end), [key, end).
       //  删除一个键值对    更常使用 WithRange(end), [key, end).
    Delete(ctx context.Context, key string, opts ...OpOption) (*DeleteResponse, error)

    // Compact compacts etcd KV history before the given rev.
               // 压缩etcd kv历史数据  通常再给出版本号之前
    Compact(ctx context.Context, rev int64, opts ...CompactOption) (*CompactResponse, error)

    // Do applies a single Op on KV without a transaction.
        //do应用于单一kv操作项,通常是没有事务的
    // Do is useful when declaring operations to be issued at a later time
       //
    // whereas Get/Put/Delete are for better suited for when the operation
    // should be immediately issued at time of declaration.

    // Do applies a single Op on KV without a transaction.
    // Do is useful when creating arbitrary operations to be issued at a
    // later time; the user can range over the operations, calling Do to
    // execute them. Get/Put/Delete, on the other hand, are best suited
    // for when the operation should be issued at the time of declaration.
    Do(ctx context.Context, op Op) (OpResponse, error)

    // Txn creates a transaction.
        //创建事务
    Txn(ctx context.Context) Txn
}
//响应结构体
type OpResponse struct {
    put *PutResponse
    get *GetResponse
    del *DeleteResponse
}

func (op OpResponse) Put() *PutResponse    { return op.put }
func (op OpResponse) Get() *GetResponse    { return op.get }
func (op OpResponse) Del() *DeleteResponse { return op.del }
//kv存储服务客户端的包装
type kv struct {
    remote pb.KVClient
}
//创建kv 服务  带着指定的客户端
func NewKV(c *Client) KV {
    return &kv{remote: RetryKVClient(c)}
}
//创建一个kv服务客户端  带着指定的protobuffer 客户端
func NewKVFromKVClient(remote pb.KVClient) KV {
    return &kv{remote: remote}
}
//kv结构体实现了 kv接口
func (kv *kv) Put(ctx context.Context, key, val string, opts ...OpOption) (*PutResponse, error) {
    r, err := kv.Do(ctx, OpPut(key, val, opts...))
    return r.put, toErr(ctx, err)
}

func (kv *kv) Get(ctx context.Context, key string, opts ...OpOption) (*GetResponse, error) {
    r, err := kv.Do(ctx, OpGet(key, opts...))
    return r.get, toErr(ctx, err)
}

func (kv *kv) Delete(ctx context.Context, key string, opts ...OpOption) (*DeleteResponse, error) {
    r, err := kv.Do(ctx, OpDelete(key, opts...))
    return r.del, toErr(ctx, err)
}

func (kv *kv) Compact(ctx context.Context, rev int64, opts ...CompactOption) (*CompactResponse, error) {
    resp, err := kv.remote.Compact(ctx, OpCompact(rev, opts...).toRequest())
    if err != nil {
        return nil, toErr(ctx, err)
    }
    return (*CompactResponse)(resp), err
}

func (kv *kv) Txn(ctx context.Context) Txn {
    return &txn{
        kv:  kv,
        ctx: ctx,
    }
}

func (kv *kv) Do(ctx context.Context, op Op) (OpResponse, error) {
    for {
        resp, err := kv.do(ctx, op)
        if err == nil {
            return resp, nil
        }

        if isHaltErr(ctx, err) {
            return resp, toErr(ctx, err)
        }
        // do not retry on modifications
        if op.isWrite() {
            return resp, toErr(ctx, err)
        }
    }
}

func (kv *kv) do(ctx context.Context, op Op) (OpResponse, error) {
    var err error
    switch op.t {
    // TODO: handle other ops
    case tRange:
        var resp *pb.RangeResponse
        resp, err = kv.remote.Range(ctx, op.toRangeRequest(), grpc.FailFast(false))
        if err == nil {
            return OpResponse{get: (*GetResponse)(resp)}, nil
        }
    case tPut:
        var resp *pb.PutResponse
        r := &pb.PutRequest{Key: op.key, Value: op.val, Lease: int64(op.leaseID), PrevKv: op.prevKV}
        resp, err = kv.remote.Put(ctx, r)
        if err == nil {
            return OpResponse{put: (*PutResponse)(resp)}, nil
        }
    case tDeleteRange:
        var resp *pb.DeleteRangeResponse
        r := &pb.DeleteRangeRequest{Key: op.key, RangeEnd: op.end, PrevKv: op.prevKV}
        resp, err = kv.remote.DeleteRange(ctx, r)
        if err == nil {
            return OpResponse{del: (*DeleteResponse)(resp)}, nil
        }
    default:
        panic("Unknown op")
    }
    return OpResponse{}, err
}

kv.go的更多相关文章

  1. KV存储系统

    现在的KV存储系统都是分布式的,首先介绍Zookeeper——针对大型分布式系统的高可靠的协调系统. 开发分布式系统是件很困难的事情,其中的困难主要体现在分布式系统的“部分失败”.“部分失败”是指信息 ...

  2. 计算机程序的思维逻辑 (60) - 随机读写文件及其应用 - 实现一个简单的KV数据库

    57节介绍了字节流, 58节介绍了字符流,它们都是以流的方式读写文件,流的方式有几个限制: 要么读,要么写,不能同时读和写 不能随机读写,只能从头读到尾,且不能重复读,虽然通过缓冲可以实现部分重读,但 ...

  3. Redis与KV存储(RocksDB)融合之编码方式

    Redis与KV存储(RocksDB)融合之编码方式 简介 Redis 是目前 NoSQL 领域的当红炸子鸡,它象一把瑞士军刀,小巧.锋利.实用,特别适合解决一些使用传统关系数据库难以解决的问题.Re ...

  4. 从零开始山寨Caffe·柒:KV数据库

    你说你会关系数据库?你说你会Hadoop? 忘掉它们吧,我们既不需要网络支持,也不需要复杂关系模式,只要读写够快就行.    ——论数据存储的本质 浅析数据库技术 内存数据库——STL的map容器 关 ...

  5. Ping CAP CTO、Codis作者谈redis分布式解决方案和分布式KV存储

    此文根据[QCON高可用架构群]分享内容,由群内[编辑组]志愿整理,转发请注明出处. 苏东旭,Ping CAP CTO,Codis作者 开源项目Codis的co-author黄东旭,之前在豌豆荚从事i ...

  6. Red KV数据 庫设計模式

    转:http://blog.nosqlfan.com/html/3033.html NoSQL带给我们的东西很多,高性能,水平扩展性,还有不一样的思维方式.本文来自@hoterran的个人博客运维与开 ...

  7. 浅析LRU(K-V)缓存

    LRU(Least Recently Used)算法是缓存技术中的一种常见思想,顾名思义,最近最少使用,也就是说有两个维度来衡量,一个是时间(最近),一个频率(最少).如果需要按优先级来对缓存中的K- ...

  8. 基于KV Data Model实现Table Data Model

    HBase对外暴露出来的是一个表格数据模型,如下图所示 rowkey应用程序可以自己设计.每一个Cell可以保存多个版本的数据,由timestamp标示版本.应用程序可以自己指定timestamp,如 ...

  9. 基于淘宝开源Tair分布式KV存储引擎的整合部署

    一.前言 Tair支撑了淘宝几乎所有系统的缓存信息(Tair = Taobao Pair,Pair即Key-Value键值对),内置了三个存储引擎:mdb(默认,类似于Memcache).rdb(类似 ...

  10. KV总结

    今天没事又重新写了一遍.很多注释是自己犯糊涂后来又终于跨过去的备忘. // ImgEff.js function ImgEff(div,time){ //构造函数,需要传入参数div的id和时间 // ...

随机推荐

  1. JAVA程序员面试宝典

    程序员面试之葵花宝典 面向对象的特征有哪些方面    1. 抽象:抽象就是忽略一个主题中与当前目标2. 无关的那些方面,3. 以便更充分地注意与当前目标4. 有关的方面.抽象并不5. 打算了解全部问题 ...

  2. WebRequestHelper

    老是浪费时间写这个类,干脆记录在博客里: public class WebRequestHelper { #region Post public static CookieContainer GetC ...

  3. Dubbo基本特性之泛化调用

    Dubbo 是支持泛化调用的,什么是泛化调用呢?泛化调用的好处是什么呢,泛化调用说白一点就是服务消费者并没有服务的接口. 在<Dubbo入门-搭建一个最简单的Demo框架>一文中,我们已完 ...

  4. JVM笔记9-Class类文件结构

    1.Class类文件结构  Class 文件是一组以 8 位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在 Class 文件之中,中间没有添加任何分隔符,这使得整个 Class 文件中 ...

  5. PyCOn2013大会笔记

    DAE的设计 By洪强宁 hongon@douban.com 3个aaS服务都不能模块化灵活组合服务 DAE的起因:代码横向拆分模块化,重用基础设施 最佳实践对新App复用    Scale SA D ...

  6. pymongo "ServerSelectionTimeoutError: No servers found yet" 错误的解决

    系统转移过程中,擅自把aptitude安装的mongoengine换成了pip安装,系统启动以后,报这个错误 报错提示: File "/usr/local/lib/python2.7/dis ...

  7. ubuntu 14.04 安装svn server (subversionedge )

    ubuntu 14.04 安装subversionedge 请仔细阅读安装包自带的readme文件! 1.先去官网,找安装包: http://subversion.apache.org/ http:/ ...

  8. git添加本地的项目到git远程管理仓库

    目标:将本地存在的项目添加到git远程仓库管理 步骤: 1. 需要一个git远程仓库管理地址 例如:https://github.com/xingfupeng/test.git git@github. ...

  9. Apache Flink 流处理实例

    维基百科在 IRC 频道上记录 Wiki 被修改的日志,我们可以通过监听这个 IRC 频道,来实时监控给定时间窗口内的修改事件.Apache Flink 作为流计算引擎,非常适合处理流数据,并且,类似 ...

  10. Angular4.x通过路由守卫进行路由重定向,实现根据条件跳转到相应的页面

    需求: 最近在做一个网上商城的项目,技术用的是Angular4.x.有一个很常见的需求是:用户在点击"我的"按钮时读取cookie,如果有数据,则跳转到个人信息页面,否则跳转到注册 ...