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. ruby通过telnet读取互联网时间

    在前面的博文ntp服务器也谈逆向工程中,本猫曾经武断的认为telnet是无法连接到ntp服务器的.因为当时是这样连接的: telnet time.nist.gov 123,端口号123是在/etc/s ...

  2. 【作业2.0】HansBug的5-7次OO作业分析与小结,以及一些个人体会

    不知不觉又做了三次作业,容我在本文胡言乱语几句2333. 第五次作业 第五次作业是前面的电梯作业的多线程版本,难度也有了一些提升.(点击就送指导书) 类图 程序的类图结构如下: UML时序图 程序的逻 ...

  3. was上的应用程序部分启动的原因

    最近几天为了方便联调,我把两个项目配置到was测试环境上,前几天还好好的,昨天忽然有一个项目反复安装后都呈现部分启动的状态,打开节点一看,偏偏没启动的那个节点就是我需要用的79节点. 这让我很郁闷,硬 ...

  4. Objective-C 空指针和野指针

    一.什么是空指针和野指针 1.空指针 1> 没有存储任何内存地址的指针就称为空指针(NULL指针) 2> 空指针就是被赋值为0的指针,在没有被具体初始化之前,其值为0. 下面两个都是空指针 ...

  5. java并发编程——通过ReentrantLock,Condition实现银行存取款

         java.util.concurrent.locks包为锁和等待条件提供一个框架的接口和类,它不同于内置同步和监视器.该框架允许更灵活地使用锁和条件,但以更难用的语法为代价. Lock 接口 ...

  6. XML 和 java对象相互转换

    XML 和 java对象相互转换 博客分类: XML 和 JSON   下面使用的是JDK自带的类,没有引用任何第三方jar包. Unmarshaller 类使客户端应用程序能够将 XML 数据转换为 ...

  7. python---生成器、迭代器

    # -*- coding:utf-8 -*- # LC # 列表生成式 def func(x): print(x) return 2*x print([ func(i) for i in range( ...

  8. Pivotal开源基于PostgreSQL的数据库Greenplum

    http://www.infoq.com/cn/news/2015/11/PostgreSQL-Pivotal 近日,Pivotal宣布开源大规模并行处理(MPP)数据库Greenplum,其架构是针 ...

  9. Neo4j安装后的密码修改

    首先默认用户名/密码是neo4j/neo4j. 在安全验证打开的时候,你访问服务器/db/data之类的地址可能会提示您以下信息: { "password_change" : &q ...

  10. 使用ASP.NET SignalR实现一个简单的聊天室

    前言 距离我写上一篇博客已经又过了一年半载了,时间过得很快,一眨眼,就把人变得沧桑了许多.青春是短暂的,知识是无限的.要用短暂的青春,去学无穷无尽的知识,及时当勉励,岁月不待人.今天写个随笔小结记录一 ...