package nsqlookupd

import (
    "fmt"
    "sync"
    "sync/atomic"
    "time"
)
//db(注册中心--内存数据库map)结构体
type RegistrationDB struct {
    sync.RWMutex  //读写锁
    registrationMap map[Registration]Producers //
}
//代表一个生产者  主题 通道    
type Registration struct {
    Category string  //主题
    Key      string  //通道
    SubKey   string  //
}
type Registrations []Registration
//代表客户端nsqd 的配置信息
type PeerInfo struct {
    lastUpdate       int64
    id               string
    RemoteAddress    string `json:"remote_address"`
    Hostname         string `json:"hostname"`
    BroadcastAddress string `json:"broadcast_address"`
    TCPPort          int    `json:"tcp_port"`
    HTTPPort         int    `json:"http_port"`
    Version          string `json:"version"`
}
//生产者
type Producer struct {
    peerInfo     *PeerInfo
    tombstoned   bool
    tombstonedAt time.Time
}

type Producers []*Producer

func (p *Producer) String() string {
    return fmt.Sprintf("%s [%d, %d]", p.peerInfo.BroadcastAddress, p.peerInfo.TCPPort, p.peerInfo.HTTPPort)
}

func (p *Producer) Tombstone() {
    p.tombstoned = true
    p.tombstonedAt = time.Now()
}

func (p *Producer) IsTombstoned(lifetime time.Duration) bool {
    return p.tombstoned && time.Now().Sub(p.tombstonedAt) < lifetime
}

func NewRegistrationDB() *RegistrationDB {
    return &RegistrationDB{
        registrationMap: make(map[Registration]Producers),
    }
}

// add a registration key
func (r *RegistrationDB) AddRegistration(k Registration) {
    r.Lock()
    defer r.Unlock()
    _, ok := r.registrationMap[k]
    if !ok {
        r.registrationMap[k] = Producers{}
    }
}

// add a producer to a registration
func (r *RegistrationDB) AddProducer(k Registration, p *Producer) bool {
    r.Lock()
    defer r.Unlock()
    producers := r.registrationMap[k]
    found := false
    for _, producer := range producers {
        if producer.peerInfo.id == p.peerInfo.id {
            found = true
        }
    }
    if found == false {
        r.registrationMap[k] = append(producers, p)
    }
    return !found
}

// remove a producer from a registration
func (r *RegistrationDB) RemoveProducer(k Registration, id string) (bool, int) {
    r.Lock()
    defer r.Unlock()
    producers, ok := r.registrationMap[k]
    if !ok {
        return false, 0
    }
    removed := false
    cleaned := Producers{}
    for _, producer := range producers {
        if producer.peerInfo.id != id {
            cleaned = append(cleaned, producer)
        } else {
            removed = true
        }
    }
    // Note: this leaves keys in the DB even if they have empty lists
    r.registrationMap[k] = cleaned
    return removed, len(cleaned)
}

// remove a Registration and all it's producers
func (r *RegistrationDB) RemoveRegistration(k Registration) {
    r.Lock()
    defer r.Unlock()
    delete(r.registrationMap, k)
}

func (r *RegistrationDB) needFilter(key string, subkey string) bool {
    return key == "*" || subkey == "*"
}

func (r *RegistrationDB) FindRegistrations(category string, key string, subkey string) Registrations {
    r.RLock()
    defer r.RUnlock()
    if !r.needFilter(key, subkey) {
        k := Registration{category, key, subkey}
        if _, ok := r.registrationMap[k]; ok {
            return Registrations{k}
        }
        return Registrations{}
    }
    results := Registrations{}
    for k := range r.registrationMap {
        if !k.IsMatch(category, key, subkey) {
            continue
        }
        results = append(results, k)
    }
    return results
}

func (r *RegistrationDB) FindProducers(category string, key string, subkey string) Producers {
    r.RLock()
    defer r.RUnlock()
    if !r.needFilter(key, subkey) {
        k := Registration{category, key, subkey}
        return r.registrationMap[k]
    }

    results := Producers{}
    for k, producers := range r.registrationMap {
        if !k.IsMatch(category, key, subkey) {
            continue
        }
        for _, producer := range producers {
            found := false
            for _, p := range results {
                if producer.peerInfo.id == p.peerInfo.id {
                    found = true
                }
            }
            if found == false {
                results = append(results, producer)
            }
        }
    }
    return results
}

func (r *RegistrationDB) LookupRegistrations(id string) Registrations {
    r.RLock()
    defer r.RUnlock()
    results := Registrations{}
    for k, producers := range r.registrationMap {
        for _, p := range producers {
            if p.peerInfo.id == id {
                results = append(results, k)
                break
            }
        }
    }
    return results
}

func (k Registration) IsMatch(category string, key string, subkey string) bool {
    if category != k.Category {
        return false
    }
    if key != "*" && k.Key != key {
        return false
    }
    if subkey != "*" && k.SubKey != subkey {
        return false
    }
    return true
}

func (rr Registrations) Filter(category string, key string, subkey string) Registrations {
    output := Registrations{}
    for _, k := range rr {
        if k.IsMatch(category, key, subkey) {
            output = append(output, k)
        }
    }
    return output
}

func (rr Registrations) Keys() []string {
    keys := make([]string, len(rr))
    for i, k := range rr {
        keys[i] = k.Key
    }
    return keys
}

func (rr Registrations) SubKeys() []string {
    subkeys := make([]string, len(rr))
    for i, k := range rr {
        subkeys[i] = k.SubKey
    }
    return subkeys
}

func (pp Producers) FilterByActive(inactivityTimeout time.Duration, tombstoneLifetime time.Duration) Producers {
    now := time.Now()
    results := Producers{}
    for _, p := range pp {
        cur := time.Unix(0, atomic.LoadInt64(&p.peerInfo.lastUpdate))
        if now.Sub(cur) > inactivityTimeout || p.IsTombstoned(tombstoneLifetime) {
            continue
        }
        results = append(results, p)
    }
    return results
}

func (pp Producers) PeerInfo() []*PeerInfo {
    results := []*PeerInfo{}
    for _, p := range pp {
        results = append(results, p.peerInfo)
    }
    return results
}

registration_db.go的更多相关文章

  1. go语言nsq源码解读五 nsqlookupd源码registration_db.go

    本篇将讲解registration_db.go文件. 1234567891011121314151617181920212223242526272829303132333435363738394041 ...

  2. flume的使用

    1.flume的安装和配置 1.1 配置java_home,修改/opt/cdh/flume-1.5.0-cdh5.3.6/conf/flume-env.sh文件

  3. go语言nsq源码解读七 lookup_protocol_v1.go

    本篇将解读nsqlookup处理tcp请求的核心代码文件lookup_protocol_v1.go. 1234567891011121314151617181920212223242526272829 ...

  4. go语言 nsq源码解读三 nsqlookupd源码nsqlookupd.go

    从本节开始,将逐步阅读nsq各模块的代码. 读一份代码,我的思路一般是: 1.了解用法,知道了怎么使用,对理解代码有宏观上有很大帮助. 2.了解各大模块的功能特点,同时再想想,如果让自己来实现这些模块 ...

随机推荐

  1. 解密for循环工作机制之迭代器,以及生成器、三元表达式与列表解析、解压序列

    本节内容 1.迭代器协议与for循环 2.三元表达式 3.解压序列 4.列表解析 5.生成器 迭代器协议与for循环 1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中下一项, ...

  2. Scala编程入门---函数式编程之集合操作

    集合的函数式编程: 实战常用: //map案例实战:为List中的每个元素都添加一个前缀. List("leo","Jen","peter" ...

  3. Python2和Python3比较分析

    一直有看到网上有讨论Python2和Python3的比较,最近公司也在考虑是否在spark-python大数据开发环境中升级到python3.通过本篇博文记录Python2.7.13和Pthon3.5 ...

  4. memcached usage

    https://github.com/ragnor/simple-spring-memcached/wiki/Getting-Started 1) maven <dependency> & ...

  5. Java开源生鲜电商平台-订单表的设计(源码可下载)

    Java开源生鲜电商平台-订单表的设计(源码可下载) 场景分析说明: 买家(餐馆)用户,通过APP进行选菜,放入购物车,然后下单,最终支付的流程,我们称为下单过程. 买家可以在张三家买茄子,李四家买萝 ...

  6. ImportError: cannot import name webdriver

    遇到问题: 学习selenium过程中为了方便自己知道学习的脚本的存放路径,以selenium命名 起初.py文件都在selenium文件夹下面,使用 from selenium import web ...

  7. 【转】数据库事务ACID以及事务隔离

      本篇讲诉数据库中事务的四大特性(ACID),并且将会详细地说明事务的隔离级别. 如果一个数据库声称支持事务的操作,那么该数据库必须要具备以下四个特性: ⑴ 原子性(Atomicity) 原子性是指 ...

  8. jenkins+gitlab自动化编译部署方案探索及服务端编译webpack实战

    一. 背景 之前我们的开发流程为在本地进行webpack打包编译,然后svn提交源代码和编译后的代码.同时每次提交前也会从svn更新源代码和编译后的代码.这样做有几个缺点: 1. svn 更新和提交编 ...

  9. Centos7 环境下 tty 终端 中文乱码 问题

    最近有同学问我 Centos 方面的一些操作,  由于我已经好多年不用Centos了所以比较生疏,这些年来一直都是用Ubuntu的,不得不说Ubuntu是我用过的这么多Linux系统中操作最舒服的了, ...

  10. Ubuntu系统下解决“YourUserName不在sudoers文件中。此事将被报告”的问题

    本文由荒原之梦原创,原文链接:http://zhaokaifeng.com/?p=624 问题描述: 之前在使用Fedora系统时遇到过在使用 sudo 时提示"YourUserName不在 ...