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. Error filterStart的问题

    今天出现这个问题 严重: Error filterStart org.apache.catalina.core.StandardContext start 严重: Context startup fa ...

  2. JS(作用域和闭包)

    1.对变量提升的理解 1.变量定义(上下文) 2.函数声明 2.说明 this 几种不同的使用场景 常见用法 1.作为构造函数执行 2.作为对象属性执行 3.作为普通函数执行(this === win ...

  3. 数据库scheme设计(9.4 小结)

    通过这一章的内容,希望能够让大家明白一个道理,“数据库系统的性能不是优化出来的,更多的是设计出来的”.数据库Schema 的设计并不如很多人想象的那样只是一个简单的对象对应实现,而是一个系统工程.要想 ...

  4. JavaScript验证和数据处理的干货(经典)

    在开发web项目的时候,难免遇到各种对网页数据的处理,比如对用户在表单中输入的电话号码.邮箱.金额.身份证号.密码长度和复杂程度等等的验证,以及对后台返回数据的格式化比如金额,返回的值为null,还有 ...

  5. 全屏slider--swiper

    这两年,这种滑动器技术在互联网产品介绍页设计上非常常用,最近某个项目需要这种设计,在网上找了一下,有个老外产的这种设计组件swiper已经非常成熟,原来这个东西设计初衷是pad之类的移动触摸交互设备, ...

  6. linux 系统centOS 7 怎么在线安装mysql

    以下操作,注意空格,为避免出错,可以选择直接copy 第一步: 输入命令行      yum list installed | grep mysql       检查是否已经安装mysql 已安装输入 ...

  7. Ocelot中文文档-Raft(实验功能不能用于生产环境)

    Ocelot最近整合了Rafty,这是我在去年一直研究的Raft的一个实现. 这个项目实验性非常强,所以在我认为它没问题之前,请不要在生产环境中使用Ocelot的这个功能. Raft是一种分布式一致性 ...

  8. JavaScript程序的执行顺序

    JavaScript程序的执行顺序:同步==>异步==>回调 同步是阻塞模式,异步是非阻塞模式.     同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个 ...

  9. java之Spring(AOP)前奏-动态代理设计模式(上)

    我们常常会遇到这样的事,项目经理让你为一个功能类再加一个功能A,然后你加班为这个类加上了功能A: 过了两天又来了新需求,再在A功能后面加上一个新功能B,你加班写好了这个功能B,加在了A后面:又过 了几 ...

  10. Spring使用 --- 基本概念(二):AOP,面向方面编程

    Table of Contents 什么是面向方面编程 怎样使用 什么时候使用 好处 本文讲述sprint的第二个基本概念: AOP,即面向方面编程 什么是面向方面编程 软件项目中,日志系统等服务系统 ...