package mirror

import (
    "github.com/coreos/etcd/clientv3"
    "golang.org/x/net/context"
)

const (
    batchLimit = 1000
)

// Syncer syncs with the key-value state of an etcd cluster.
type Syncer interface {
    // SyncBase syncs the base state of the key-value state.
    // The key-value state are sent through the returned chan.
    SyncBase(ctx context.Context) (<-chan clientv3.GetResponse, chan error)
    // SyncUpdates syncs the updates of the key-value state.
    // The update events are sent through the returned chan.
    SyncUpdates(ctx context.Context) clientv3.WatchChan
}

// NewSyncer creates a Syncer.
func NewSyncer(c *clientv3.Client, prefix string, rev int64) Syncer {
    return &syncer{c: c, prefix: prefix, rev: rev}
}

type syncer struct {
    c      *clientv3.Client
    rev    int64
    prefix string
}

func (s *syncer) SyncBase(ctx context.Context) (<-chan clientv3.GetResponse, chan error) {
    respchan := make(chan clientv3.GetResponse, 1024)
    errchan := make(chan error, 1)

    // if rev is not specified, we will choose the most recent revision.
    if s.rev == 0 {
        resp, err := s.c.Get(ctx, "foo")
        if err != nil {
            errchan <- err
            close(respchan)
            close(errchan)
            return respchan, errchan
        }
        s.rev = resp.Header.Revision
    }

    go func() {
        defer close(respchan)
        defer close(errchan)

        var key string

        opts := []clientv3.OpOption{clientv3.WithLimit(batchLimit), clientv3.WithRev(s.rev)}

        if len(s.prefix) == 0 {
            // If len(s.prefix) == 0, we will sync the entire key-value space.
            // We then range from the smallest key (0x00) to the end.
            opts = append(opts, clientv3.WithFromKey())
            key = "\x00"
        } else {
            // If len(s.prefix) != 0, we will sync key-value space with given prefix.
            // We then range from the prefix to the next prefix if exists. Or we will
            // range from the prefix to the end if the next prefix does not exists.
            opts = append(opts, clientv3.WithRange(clientv3.GetPrefixRangeEnd(s.prefix)))
            key = s.prefix
        }

        for {
            resp, err := s.c.Get(ctx, key, opts...)
            if err != nil {
                errchan <- err
                return
            }

            respchan <- (clientv3.GetResponse)(*resp)

            if !resp.More {
                return
            }
            // move to next key
            key = string(append(resp.Kvs[len(resp.Kvs)-1].Key, 0))
        }
    }()

    return respchan, errchan
}

func (s *syncer) SyncUpdates(ctx context.Context) clientv3.WatchChan {
    if s.rev == 0 {
        panic("unexpected revision = 0. Calling SyncUpdates before SyncBase finishes?")
    }
    return s.c.Watch(ctx, s.prefix, clientv3.WithPrefix(), clientv3.WithRev(s.rev+1))
}

syncer.go的更多相关文章

  1. TiDB数据库 使用syncer工具同步实时数据

    mysql> select campaign_id ,count(id) from creative_output group by campaign_id; rows min 44.23 se ...

  2. C#中级-常用多线程操作(持续更新)

    一.前言       多线程操作一直是编程的常用操作,掌握好基本的操作可以让程序运行的更加有效.本文不求大而全,只是将我自己工作中常常用到的多线程操作做个分类和总结.平时记性不好的时候还能看看.本文参 ...

  3. Heartbeat+DRBD+MySQL高可用方案

    1.方案简介 本方案采用Heartbeat双机热备软件来保证数据库的高稳定性和连续性,数据的一致性由DRBD这个工具来保证.默认情况下只有一台mysql在工作,当主mysql服务器出现问题后,系统将自 ...

  4. drdb

    Distributed Replicated Block Device(DRBD)是一种基于软件的,无共享,复制的存储解决方案,在服务器之间的对块设备(硬盘,分区,逻辑卷等)进行镜像.DRBD工作在内 ...

  5. Linux 集群

    html,body { } .CodeMirror { height: auto } .CodeMirror-scroll { } .CodeMirror-lines { padding: 4px 0 ...

  6. ZABBIX冗余架构构筑(Centos6.4+pacemaker+corosync+drbd)

    基本构成: 用pacemaker+corosync控制心跳和资源迁移 用drbd同步zabbix配置文件和mysql数据库 所有软件都用yum安装至默认路径 主机的drbd领域挂载至/drbd,备机不 ...

  7. MySQL 系列(五) 多实例、高可用生产环境实战

    MySQL 系列(五) 多实例.高可用生产环境实战   第一篇:MySQL 系列(一) 生产标准线上环境安装配置案例及棘手问题解决 第二篇:MySQL 系列(二) 史上最屌.你不知道的数据库操作 第三 ...

  8. 1 构建Mysql+heartbeat+DRBD+LVS集群应用系统系列之DRBD的搭建

    preface 近来公司利润上升,购买了10几台服务器,趁此机会,把mysql的主从同步的架构进一步扩展,为了适应日益增长的流量.针对mysql架构的扩展,先是咨询前辈,后和同事探讨,准备采用Mysq ...

  9. linux 后台运行命令 nohup命令

    转载:http://if.ustc.edu.cn/~ygwu/blog/archives/000538.html 2005年04月18日 简单而有用的nohup命令在UNIX/LINUX中,普通进程用 ...

随机推荐

  1. Yii2.0源码阅读-PHP如何与redis通信?

    PHP与Redis可以通过socket进行通信,前提是PHP需要实现Redis的协议 RESP协议描述: 字符串 \r\n : 表示一个正确的状态信息,具体信息是'+'后面的字符(Simple Str ...

  2. db2字段修改

    db2表字段修改 1:删除字段非空属性alter table XXX alter column XXX drop not null 2:添加字段非空属性alter table XXX alter co ...

  3. 3 sum closest

    Given an array S of n integers, find three integers in S such that the sum is closest to a given num ...

  4. remove Nth Node from linked list从链表中删除倒数第n个元素

    Given a linked list, remove the nth node from the end of list and return its head. For example, Give ...

  5. 直接执行SQL语句的快捷键是什么啊?嘎嘎

    在查询中输入SQL语句后,执行语句的快捷键~ 分享到: 2009-10-23 10:59网友采纳 左键..嘿嘿,开个玩笑 你把鼠标移动到执行按钮上停一会就能看到了啊

  6. [更新]单线程的JS引擎与 Event Loop

    先来思考一个问题,JS 是单线程的还是多线程的?如果是单线程,为什么JavaScript能让AJAX异步发送和回调请求,还有setTimeout也看起来像是多线程的?还有non-blocking IO ...

  7. gitolite服务器部署中的一些坑

    1.秘钥登录问题可参考< 安装gitolite,并ssh公钥无密码登录>http://www.cnblogs.com/tr0217/p/4517952.html,该文中推荐了阮一峰的< ...

  8. 基于jQuery的AJAX实现三级联动菜单

    最近学习jQuery,所以就写了一个关于中国省市县/区的三级联动菜单,权当相互学习,相互促进,特此记录. 下面是嵌套js的html文件: <!DOCTYPE html> <html ...

  9. Spring JTA multiple resource transactions in Tomcat with Atomikos example

    http://www.byteslounge.com/tutorials/spring-jta-multiple-resource-transactions-in-tomcat-with-atomik ...

  10. java 用ant打包成jar文件

    一.下载ant包,解压放放到你的项目中 二.在ant文件夹下创建一个build.xml文件,内容如下 <?xml version="1.0" encoding="G ...