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. C语言有哪些鲜为人知的特性?

    译注:本文摘编自 Quora 的一个热门问答贴. 请在linux系统下测试本文中出现的代码 Andrew Weimholt 的回复: switch语句中的case 关键词可以放在if-else或者是循 ...

  2. Mac OS 的属性列表文件plist装换

    Mac OS系统自身包含有转换plist的工具:plutil.其中-p是以human可读方式显示plist文件,而convert就是转换参数,其中支持的格式有:xml,二进制和json.下面拿一个实际 ...

  3. azkaban报错记录

    问题信息:Failed to build job executor for job o2o_get_file_ftp1Job type 'command ' is unrecognized. Coul ...

  4. 途牛java实习面试(失败)

    一进去让自己介绍.简单介绍了一下.然后让我自己说说框架.问题太大一紧张卡住了. 然后面试官开始问,让我介绍多线程,我就简单介绍了多线程.然后问我有没有做过多线程的项目,我说没有. 问了MySQL的锁和 ...

  5. OSGI介绍

    OSGI介绍 OSGI简介 OSGI (Open Service Gateway Initiative)联盟成立于1999 年,它是一个非盈利的国际组织,旨在建立一个开放的服务规范,为通过网络向设备提 ...

  6. Day4_闭包含数

    闭包函数: 闭包函数是在作用域的前提下 闭包含数:定义在函数内部的函数,包含对外部作用域名字的引用,而不是对全局作用域名字的引用,那么该内部函数就称为闭包含数. eg: x=1 def f1(): x ...

  7. 【读书笔记】C++Primer---第二章

    1.C++基本数据类型:字符型.整型.浮点型等: 2.算术类型如下表,下表只是表示C++要求的最小储存空间,但是一般编译器使用的都比所要求的储存空间大,以前类型所能表示的最大值也因机器的不同而有不同的 ...

  8. hadoop配置文件详解系列(二)-hdfs-site.xml篇

    上一篇介绍了core-site.xml的配置,本篇继续介绍hdfs-site.xml的配置. 属性名称 属性值 描述 hadoop.hdfs.configuration.version 1 配置文件的 ...

  9. codeforces——961B. Lecture Sleep

    本文为博主原创文章,未经允许不得转载. 我在csdn也同步发布了此文,链接 https://blog.csdn.net/umbrellalalalala/article/details/7989196 ...

  10. Java并发-线程安全性

    首先了解一下多线程的概念 多线程:两段或以上的代码同时进行,多个顺序执行流. 并发和并行的区别 并发:做一下这个做一下那个. 并行:同时进行. 线程和进程的区别 进程:资源分配的基本单位,运行中的程序 ...