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. Spring Boot Kafka

    1.创建集群 http://kafka.apache.org/documentation/#quickstart 有一句我觉得特别重要: For Kafka, a single broker is j ...

  2. CXF 5参考资料

    下载 描述 名字 大小 下载方法 本教程示例应用程序的源代码 CXF_Spring_Survey_Src.war 10 KB HTTP 关于下载方法的信息 学习 Apache CXF 的官方站点:提供 ...

  3. Angular为什么选择TypeScript?

    原文地址:https://vsavkin.com/writing-angular-2-in-typescript-1fa77c78d8e8 本文转自:http://www.chinacion.cn/a ...

  4. ubuntu导入公钥的方法

    导入公钥的办法: #方法1: gpg --keyserver subkeys.pgp.NET --recv 6E871C4A881574DEgpg --export --armor 6E871C4A8 ...

  5. 走进netty

    三月份开始看公司RPC框架的源码,发现如果要折腾明白,网络通讯这块知识必不可少.于是从如下几点开始逐步研究. 一.基础知识篇 1.Unix下5种I/O模型 Linux的内核将所有外部设备都看作一个文件 ...

  6. python3学习笔记3---引用http://python3-cookbook.readthedocs.io/zh_CN/latest/

    2018-03-01数据结构和算法(3) 1.11 命名切片 假定你有一段代码要从一个记录字符串中几个固定位置提取出特定的数据字段(比如文件或类似格式): ###### 012345678901234 ...

  7. JAVA 语法2

    1.算术运算符 运算符 运算规则 范例 结果 + 正号 +3 3 + 加 2+3 5 + 连接字符串 "中"+"国" "中国" - 负号 i ...

  8. for循环之后的return

    <C++primer>第五版中文版,201页: 在含有return语句的循环后面应该也有一条return语句,如果没有的话该程序就是错误的. 前几天编写一个函数,for循环查找某个值,找到 ...

  9. asp.net MVC 框架中控制器里使用Newtonsoft.Json对前端传过来的字符串进行解析

    下面我用一个实例来和大家分享一下我的经验,asp.net MVC 框架中控制器里使用Newtonsoft.Json对前端传过来的字符串进行解析. using Newtonsoft.Json; usin ...

  10. leetCode刷题(找到两个数组拼接后的中间数)

    There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two ...