package clusterinfo

import (
    "encoding/json"
    "fmt"
    "sort"
    "strings"
    "time"

    "github.com/blang/semver"
    "github.com/nsqio/nsq/internal/quantile"
)

type ProducerTopic struct {
    Topic      string `json:"topic"`
    Tombstoned bool   `json:"tombstoned"`
}

type ProducerTopics []ProducerTopic

func (pt ProducerTopics) Len() int           { return len(pt) }
func (pt ProducerTopics) Swap(i, j int)      { pt[i], pt[j] = pt[j], pt[i] }
func (pt ProducerTopics) Less(i, j int) bool { return pt[i].Topic < pt[j].Topic }

type Producer struct {
    RemoteAddresses  []string       `json:"remote_addresses"`
    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"`
    VersionObj       semver.Version `json:"-"`
    Topics           ProducerTopics `json:"topics"`
    OutOfDate        bool           `json:"out_of_date"`
}

// UnmarshalJSON implements json.Unmarshaler and postprocesses of ProducerTopics and VersionObj
func (p *Producer) UnmarshalJSON(b []byte) error {
    var r struct {
        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"`
        Topics           []string `json:"topics"`
        Tombstoned       []bool   `json:"tombstones"`
    }
    if err := json.Unmarshal(b, &r); err != nil {
        return err
    }
    *p = Producer{
        RemoteAddress:    r.RemoteAddress,
        Hostname:         r.Hostname,
        BroadcastAddress: r.BroadcastAddress,
        TCPPort:          r.TCPPort,
        HTTPPort:         r.HTTPPort,
        Version:          r.Version,
    }
    for i, t := range r.Topics {
        p.Topics = append(p.Topics, ProducerTopic{Topic: t, Tombstoned: r.Tombstoned[i]})
    }
    version, err := semver.Parse(p.Version)
    if err != nil {
        version, _ = semver.Parse("0.0.0")
    }
    p.VersionObj = version
    return nil
}

func (p *Producer) Address() string {
    if p.RemoteAddress == "" {
        return "N/A"
    }
    return p.RemoteAddress
}

func (p *Producer) HTTPAddress() string {
    return fmt.Sprintf("%s:%d", p.BroadcastAddress, p.HTTPPort)
}

func (p *Producer) TCPAddress() string {
    return fmt.Sprintf("%s:%d", p.BroadcastAddress, p.TCPPort)
}

// IsInconsistent checks for cases where an unexpected number of nsqd connections are
// reporting the same information to nsqlookupd (ie: multiple instances are using the
// same broadcast address), or cases where some nsqd are not reporting to all nsqlookupd.
func (p *Producer) IsInconsistent(numLookupd int) bool {
    return len(p.RemoteAddresses) != numLookupd
}

type TopicStats struct {
    Node         string          `json:"node"`
    Hostname     string          `json:"hostname"`
    TopicName    string          `json:"topic_name"`
    Depth        int64           `json:"depth"`
    MemoryDepth  int64           `json:"memory_depth"`
    BackendDepth int64           `json:"backend_depth"`
    MessageCount int64           `json:"message_count"`
    NodeStats    []*TopicStats   `json:"nodes"`
    Channels     []*ChannelStats `json:"channels"`
    Paused       bool            `json:"paused"`

    E2eProcessingLatency *quantile.E2eProcessingLatencyAggregate `json:"e2e_processing_latency"`
}

func (t *TopicStats) Add(a *TopicStats) {
    t.Node = "*"
    t.Depth += a.Depth
    t.MemoryDepth += a.MemoryDepth
    t.BackendDepth += a.BackendDepth
    t.MessageCount += a.MessageCount
    if a.Paused {
        t.Paused = a.Paused
    }
    found := false
    for _, aChannelStats := range a.Channels {
        for _, channelStats := range t.Channels {
            if aChannelStats.ChannelName == channelStats.ChannelName {
                found = true
                channelStats.Add(aChannelStats)
            }
        }
        if !found {
            t.Channels = append(t.Channels, aChannelStats)
        }
    }
    t.NodeStats = append(t.NodeStats, a)
    sort.Sort(TopicStatsByHost{t.NodeStats})
    if t.E2eProcessingLatency == nil {
        t.E2eProcessingLatency = &quantile.E2eProcessingLatencyAggregate{
            Addr:  t.Node,
            Topic: t.TopicName,
        }
    }
    t.E2eProcessingLatency.Add(a.E2eProcessingLatency)
}

type ChannelStats struct {
    Node          string          `json:"node"`
    Hostname      string          `json:"hostname"`
    TopicName     string          `json:"topic_name"`
    ChannelName   string          `json:"channel_name"`
    Depth         int64           `json:"depth"`
    MemoryDepth   int64           `json:"memory_depth"`
    BackendDepth  int64           `json:"backend_depth"`
    InFlightCount int64           `json:"in_flight_count"`
    DeferredCount int64           `json:"deferred_count"`
    RequeueCount  int64           `json:"requeue_count"`
    TimeoutCount  int64           `json:"timeout_count"`
    MessageCount  int64           `json:"message_count"`
    ClientCount   int             `json:"-"`
    Selected      bool            `json:"-"`
    NodeStats     []*ChannelStats `json:"nodes"`
    Clients       []*ClientStats  `json:"clients"`
    Paused        bool            `json:"paused"`

    E2eProcessingLatency *quantile.E2eProcessingLatencyAggregate `json:"e2e_processing_latency"`
}

func (c *ChannelStats) Add(a *ChannelStats) {
    c.Node = "*"
    c.Depth += a.Depth
    c.MemoryDepth += a.MemoryDepth
    c.BackendDepth += a.BackendDepth
    c.InFlightCount += a.InFlightCount
    c.DeferredCount += a.DeferredCount
    c.RequeueCount += a.RequeueCount
    c.TimeoutCount += a.TimeoutCount
    c.MessageCount += a.MessageCount
    c.ClientCount += a.ClientCount
    if a.Paused {
        c.Paused = a.Paused
    }
    c.NodeStats = append(c.NodeStats, a)
    sort.Sort(ChannelStatsByHost{c.NodeStats})
    if c.E2eProcessingLatency == nil {
        c.E2eProcessingLatency = &quantile.E2eProcessingLatencyAggregate{
            Addr:    c.Node,
            Topic:   c.TopicName,
            Channel: c.ChannelName,
        }
    }
    c.E2eProcessingLatency.Add(a.E2eProcessingLatency)
    c.Clients = append(c.Clients, a.Clients...)
    sort.Sort(ClientsByHost{c.Clients})
}

type ClientStats struct {
    Node              string        `json:"node"`
    RemoteAddress     string        `json:"remote_address"`
    Name              string        `json:"name"` // TODO: deprecated, remove in 1.0
    Version           string        `json:"version"`
    ClientID          string        `json:"client_id"`
    Hostname          string        `json:"hostname"`
    UserAgent         string        `json:"user_agent"`
    ConnectTs         int64         `json:"connect_ts"`
    ConnectedDuration time.Duration `json:"connected"`
    InFlightCount     int           `json:"in_flight_count"`
    ReadyCount        int           `json:"ready_count"`
    FinishCount       int64         `json:"finish_count"`
    RequeueCount      int64         `json:"requeue_count"`
    MessageCount      int64         `json:"message_count"`
    SampleRate        int32         `json:"sample_rate"`
    Deflate           bool          `json:"deflate"`
    Snappy            bool          `json:"snappy"`
    Authed            bool          `json:"authed"`
    AuthIdentity      string        `json:"auth_identity"`
    AuthIdentityURL   string        `json:"auth_identity_url"`

    TLS                           bool   `json:"tls"`
    CipherSuite                   string `json:"tls_cipher_suite"`
    TLSVersion                    string `json:"tls_version"`
    TLSNegotiatedProtocol         string `json:"tls_negotiated_protocol"`
    TLSNegotiatedProtocolIsMutual bool   `json:"tls_negotiated_protocol_is_mutual"`
}

// UnmarshalJSON implements json.Unmarshaler and postprocesses ConnectedDuration
func (s *ClientStats) UnmarshalJSON(b []byte) error {
    type locaClientStats ClientStats // re-typed to prevent recursion from json.Unmarshal
    var ss locaClientStats
    if err := json.Unmarshal(b, &ss); err != nil {
        return err
    }
    *s = ClientStats(ss)
    s.ConnectedDuration = time.Now().Truncate(time.Second).Sub(time.Unix(s.ConnectTs, 0))

    if s.ClientID == "" {
        // TODO: deprecated, remove in 1.0
        remoteAddressParts := strings.Split(s.RemoteAddress, ":")
        port := remoteAddressParts[len(remoteAddressParts)-1]
        if len(remoteAddressParts) < 2 {
            port = "NA"
        }
        s.ClientID = fmt.Sprintf("%s:%s", s.Name, port)
    }
    return nil
}

func (c *ClientStats) HasUserAgent() bool {
    return c.UserAgent != ""
}

func (c *ClientStats) HasSampleRate() bool {
    return c.SampleRate > 0
}

type ChannelStatsList []*ChannelStats

func (c ChannelStatsList) Len() int      { return len(c) }
func (c ChannelStatsList) Swap(i, j int) { c[i], c[j] = c[j], c[i] }

type ChannelStatsByHost struct {
    ChannelStatsList
}

func (c ChannelStatsByHost) Less(i, j int) bool {
    return c.ChannelStatsList[i].Hostname < c.ChannelStatsList[j].Hostname
}

type ClientStatsList []*ClientStats

func (c ClientStatsList) Len() int      { return len(c) }
func (c ClientStatsList) Swap(i, j int) { c[i], c[j] = c[j], c[i] }

type ClientsByHost struct {
    ClientStatsList
}

func (c ClientsByHost) Less(i, j int) bool {
    return c.ClientStatsList[i].Hostname < c.ClientStatsList[j].Hostname
}

type TopicStatsList []*TopicStats

func (t TopicStatsList) Len() int      { return len(t) }
func (t TopicStatsList) Swap(i, j int) { t[i], t[j] = t[j], t[i] }

type TopicStatsByHost struct {
    TopicStatsList
}

func (c TopicStatsByHost) Less(i, j int) bool {
    return c.TopicStatsList[i].Hostname < c.TopicStatsList[j].Hostname
}

type Producers []*Producer

func (t Producers) Len() int      { return len(t) }
func (t Producers) Swap(i, j int) { t[i], t[j] = t[j], t[i] }

func (t Producers) HTTPAddrs() []string {
    var addrs []string
    for _, p := range t {
        addrs = append(addrs, p.HTTPAddress())
    }
    return addrs
}

func (t Producers) Search(needle string) *Producer {
    for _, producer := range t {
        if needle == producer.HTTPAddress() {
            return producer
        }
    }
    return nil
}

type ProducersByHost struct {
    Producers
}

func (c ProducersByHost) Less(i, j int) bool {
    return c.Producers[i].Hostname < c.Producers[j].Hostname
}

types.go的更多相关文章

  1. AutoMapper:Unmapped members were found. Review the types and members below. Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type

    异常处理汇总-后端系列 http://www.cnblogs.com/dunitian/p/4523006.html 应用场景:ViewModel==>Mode映射的时候出错 AutoMappe ...

  2. Programming Contest Problem Types

        Programming Contest Problem Types Hal Burch conducted an analysis over spring break of 1999 and ...

  3. iOS 打开本地 其他应用程序(URL Types)

    iOS 打开本地其他应用程序(URL Types) /*前言废话:Xcode是神奇的,是我所见到的编译器中最为神奇的,如:它可以同时运行两个甚至更多Project到我们模拟器上,可以同时使用一个模拟器 ...

  4. Django模型的Field Types总结

    转:http://blog.csdn.net/devil_2009/article/details/41735611 Field Types 常用参数: null 如果设置为 True , Djang ...

  5. C and SQL data types for ODBC and CLI

    C and SQL data types for ODBC and CLI   This topic lists the C and SQL data types for ODBC and CLI a ...

  6. allow zero datetime=true导致datetime转换失败:MySql.Data.Types.MySqlDateTime”的对象无法转换为类型“System.Nullable`1[System.DateTime]

    allow zero datetime=true导致datetime转换失败:MySql.Data.Types.MySqlDateTime”的对象无法转换为类型“System.Nullable`1[S ...

  7. "SQL Server does not handle comparison of NText, Text, Xml, or Image data types."

    "SQL Server does not handle comparison of NText, Text, Xml, or Image data types." sql2000 ...

  8. 编译器出现conflicting types for 某某的错误原因总结

    直译就是xxxx 发生了一种冲突!比如今天发现的这个错误,实属低级! 本次错误的原因是:函数没有先声明,便写在了主函数后面!应该是先声明,后定义,如果只有定义,则定义必须写在主函数上方.通过查资料,有 ...

  9. EF中的实体类型【Types of Entity in Entity】(EF基础系列篇8)

    We created EDM for existing database in the previous section. As you have learned in the previous se ...

  10. mybatis报错invalid types () or values ()解决方法

      原因: Pojo类User没提供无参数构造方法, 加上该构造方法后,问题解决 ### Cause: org.apache.ibatis.reflection.ReflectionException ...

随机推荐

  1. 【模板】最近公共祖先(LCA)

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  2. 使用oracle sqldr命令导入文件后出现中文乱码问题

    1:导入命令 sqlldr userid=$DB_USER/$DB_PASS@@DB_SERVICE control=text.ctl errors=10000000  说明:username/pas ...

  3. Java 8 Stream

    1.关于Java8部分新特性介绍 Java8的新特性很多,在此就不一一介绍了,这里只说一下我自己在工作用用得比较多的几点: 1.1.Lambda表达式 Lambda允许把函数作为一个方法的参数(函数作 ...

  4. php namespace与use

    实验代码 ~/aa.php ~/bb.php 1.命名空间与文件加载的关系 本人在命名空间与文件加载上一直有一个误区,用了命名空间文件不用加载了? 实验1:去掉requre语句 可以看到就算使用命名空 ...

  5. Apache Solr vs Elasticsearch

    http://solr-vs-elasticsearch.com/ Apache Solr vs Elasticsearch The Feature Smackdown API Feature Sol ...

  6. 学习Timer定时器

    原文地址:http://www.cppblog.com/ivenher/articles/19969.html setTimer函数用于创建一个计时器,KillTimer函数用于销毁一个计时器.计时器 ...

  7. sql server 多行数据合并成一列

    首先是源数据: ),cip.CheckIn_StartTime, )),cip.CheckIn_EndTime, )),cip.Rental_Price)) as content from Check ...

  8. 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 使用FairyGUI (一)

    我们的热更新脚本在实际使用中,当然也要支持常用的第三方组件,例如这里介绍一个非常实用的第三方UI库:FairyGUI. 什么是FairyGUI 这里照搬FaiyGUI官网的介绍: 重新定义 UI 制作 ...

  9. 2、前端学习笔记之——css

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. ubuntu18.04安装搜狗拼音

    1.下载好搜狗安装包http://pinyin.sogou.com/linux/ ,注意位数! 2.打开终端安装依赖    sudo apt install libfcitx-qt0 3.提取下载好的 ...