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. Razor视图

    @{ string name="jerry";} <div> @name </div>     //显示jerry @{ string js="& ...

  2. 使用swagger管理接口

    swagger 配置 1.pom 增加jar包依赖 <dependency> <groupId>io.springfox</groupId> <artifac ...

  3. Xshell 5 配置上传下载命令

    可以在官网https://www.netsarang.com/products/main.html 下载Xshell, 目前最新的版本已经到Xshell 6了 本人记录下安装的目录截图: 安装命令:  ...

  4. FFMpeg编译之路

    为了编译这个东西,快折腾了一个星期了.期间经历了很多痛苦的过程,今天我把整个过程,以及在这个过程的感悟写下来,以备日后查看,也希望能帮到一些像我一样的兄弟姐妹. 在这一个星期里前前后后加起来总共使用了 ...

  5. sudo pip install MySQLdb

    安装数据库第三方包,报错: Could not find a version that satisfies the requirement MySQLdb (from versions: )No ma ...

  6. java之SpringMVC配置!配置!配置!

    工欲善其事,必先利其器,要想使用SpringMVC自然要先把配置文件写好. 1.web.xml文件 新建web项目之后webRoot目录下面会有一个web.xml文件,我们先来对其进行配置. < ...

  7. MyBatis打印SQL执行时间

    1.plugins MyBatis官网对于plugins的描述是这样的: MyBatis allows you to intercept calls to at certain points with ...

  8. 破解linux虚拟机的密码

    虚拟机破解秘密码步骤:          虚拟机(server)的登录通常需要一个本地用户,而本地用户密码假如不知道或者是已经忘记了,也是有办法进入的,在Linux系统内就有可以提供这种可以进入的方案 ...

  9. 源码安装xadmin及使用

    xadmin是django的第三方后台 我们也可以使用pip来安装,但是推荐使用源码安装. 因为有些新功能以及发布在GitHub上,但是还未发布到pypi上,我们就可以提取使用这些功能. 一.安装 1 ...

  10. CentOS 7.4 MySQL 5.7.20主从环境搭建(M-S)

    MySQL主从原理: 一,master记录二进制日志,在每个事务更新数据完成之前,master在二进制日志中记录这些改变.mysql将事务写入二进制日志,即使事务中的语句都是交叉执行的.在事件写入二进 ...