kv.go


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
}
				
时间: 2024-10-13 19:04:54

kv.go的相关文章

数据存储方案评估标准RDBMS or KV

作者:zhanhailiang 日期:2014-12-11 本文主要介绍常见的数据存储方案及相应选型的评估标准的介绍. Guideline:针对不同应用场景,针对性选择存储方式. 1. 数据存储方案 SQL: MySQL 5.5/5.6/MariaDB(对于Dev绝大多数场景下透明): Oracle|MS SQL暂不考虑: NoSQL: Memcached 1.4.21: Redis 2.8: MongoDB 2.6.6: Hbase 0.96/0.98: 2. 评估标准 RDBMS:(MySQ

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

一.前言 Tair支撑了淘宝几乎所有系统的缓存信息(Tair = Taobao Pair,Pair即Key-Value键值对),内置了三个存储引擎:mdb(默认,类似于Memcache).rdb(类似于Redis).ldb(高性能KV存储),其中前2者定位于cache缓存,ldb则定位于持久化存储.Tair属于分布式系统,由一个中心控制节点(Config Server)和一系列的服务节点(Data Server)组成,Config Server负责管理维护所有的Data Server状态信息.D

使用 entrySet 遍历 Map 类集合 KV ,而不是 keySet 方式进行遍历的好处

使用 entrySet 遍历 Map 类集合 KV ,而不是 keySet 方式进行遍历.说明: keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出key 所对应的 value .而 entrySet 只是遍历了一次就把 key 和 value 都放到了 entry 中,效率更高.如果是 JDK 8,使用 Map . foreach 方法.正例: values() 返回的是 V 值集合,是一个 list 集合对象 :keySet() 返回的

浅析LRU(K-V)缓存

LRU(Least Recently Used)算法是缓存技术中的一种常见思想,顾名思义,最近最少使用,也就是说有两个维度来衡量,一个是时间(最近),一个频率(最少).如果需要按优先级来对缓存中的K-V实体进行排序的话,需要考虑这两个维度,在LRU中,最近使用频率最高的排在前面,也可以简单的说最近访问的排在前面.这就是LRU的大体思想. 在操作系统中,LRU是用来进行内存管理的页面置换算法,对于在内存中但又不用的数据块(内存块)叫做LRU,操作系统会根据哪些数据属于LRU而将其移出内存而腾出空间

hbase kv特性 列式存储 查询接口

KV数据库: 只是key有多个层级: 表 + rowkey + column family + column 可以扫一个表的所有记录, 可以查一个表内,一个rowkey的所有column family + column对应value 可以查一个表内,一个rowkey,一个column family 内所有column对应value 可以查一个表内,一个rowkey,一个column family ,一个column对应的value 列式存储: 定义hbase表的时候,只需要知道table名和哪几

后端程序员之路 8、一种内存kv数据库的实现

键值(Key-Value)存储数据库,这是一种NoSQL(非关系型数据库)模型,其数据按照键值对的形式进行组织.索引和存储.KV存储非常适合不涉及过多数据关系业务关系的业务数据,同时能有效减少读写磁盘的次数,比SQL数据库存储拥有更好的读写性能.kv数据库有leveldb.redis.rocksdb等一大堆应用广泛又很可靠的开源实现,然而这里还是有一份自己的超简单实现. 1.对外接口,基本跟redis常用接口一致get.put.del.save.size 2.提供db_manager负责解析配置

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

Redis与KV存储(RocksDB)融合之编码方式 简介 Redis 是目前 NoSQL 领域的当红炸子鸡,它象一把瑞士军刀,小巧.锋利.实用,特别适合解决一些使用传统关系数据库难以解决的问题.Redis 作为内存数据库,所有的数据全部都存在内存中,特别适合处理少量的热数据.当有巨量数据超过内存大小需要落盘保存时,就需要使用 Redis + KV存储的方案了. 本文涉及的Ardb就是一个完全兼容Redis协议的NoSQL的存储服务.其存储基于现有成熟的KV存储引擎实现,理论上任何类似B-Tre

ssd-cache 不错的kv系统总结

Table of Contents 1   需求 1.1   why 1.2   具体需求 2   index 3   ssd 特性 3.1   成本 3.2   接口 3.3   比较典型的ssd参数 3.4   小结 4   现有系统调研 4.1   基于redis修改 4.1.1   redis-vm 4.1.2   redis-storage 4.1.3   小结 4.2   单机存储引擎 4.2.1   LevelDB 4.2.2   RocksDB(facebook) 4.2.3  

【Java】提取JSON数值时遇到数组集合时使用的K-V方式转换

1.实体类转换方法 参照文章:http://www.cnblogs.com/dflmg/p/6933811.html 2.K-V方法(此方法比较笨,但是没有办法,我现在不知道有没有相关的简单API,只能自己手动拼出一个方法.import org.apache.commons.lang.StringUtils;) String s = "{'request': {'enterpriseid': 55,'ownerCode': 'SunEee01','item': [{'itemName': '1熊

谈谈KV存储集群的设计要点

版权声明:本文由廖念波原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/150 来源:腾云阁 https://www.qcloud.com/community Key-value存储系统,是非常普遍的需求,几乎每个在线的互联网后台服务都需要KV存储,我们团队在KV存储方面,经历过几个时期,我自己深感要做好不容易. 这里扯远一点,展开说一下: 第一个时期,很早期的时候,我们的数据存储在mysql表里,按照用户账号简单的分库分