package nsqd

import (
    "bytes"
    "encoding/json"
    "net"
    "os"
    "strconv"
    "time"

    "github.com/nsqio/go-nsq"
    "github.com/nsqio/nsq/internal/version"
)

func connectCallback(n *NSQD, hostname string, syncTopicChan chan *lookupPeer) func(*lookupPeer) {
    return func(lp *lookupPeer) {
        ci := make(map[string]interface{})
        ci["version"] = version.Binary
        ci["tcp_port"] = n.RealTCPAddr().Port
        ci["http_port"] = n.RealHTTPAddr().Port
        ci["hostname"] = hostname
        ci["broadcast_address"] = n.getOpts().BroadcastAddress

        cmd, err := nsq.Identify(ci)
        if err != nil {
            lp.Close()
            return
        }
        resp, err := lp.Command(cmd)
        if err != nil {
            n.logf("LOOKUPD(%s): ERROR %s - %s", lp, cmd, err)
        } else if bytes.Equal(resp, []byte("E_INVALID")) {
            n.logf("LOOKUPD(%s): lookupd returned %s", lp, resp)
        } else {
            err = json.Unmarshal(resp, &lp.Info)
            if err != nil {
                n.logf("LOOKUPD(%s): ERROR parsing response - %s", lp, resp)
            } else {
                n.logf("LOOKUPD(%s): peer info %+v", lp, lp.Info)
            }
        }

        go func() {
            syncTopicChan <- lp
        }()
    }
}

func (n *NSQD) lookupLoop() {
    var lookupPeers []*lookupPeer
    var lookupAddrs []string
    syncTopicChan := make(chan *lookupPeer)
    connect := true

    hostname, err := os.Hostname()
    if err != nil {
        n.logf("FATAL: failed to get hostname - %s", err)
        os.Exit(1)
    }

    // for announcements, lookupd determines the host automatically
    ticker := time.Tick(15 * time.Second)
    for {
        if connect {
            for _, host := range n.getOpts().NSQLookupdTCPAddresses {
                if in(host, lookupAddrs) {
                    continue
                }
                n.logf("LOOKUP(%s): adding peer", host)
                lookupPeer := newLookupPeer(host, n.getOpts().MaxBodySize, n.getOpts().Logger,
                    connectCallback(n, hostname, syncTopicChan))
                lookupPeer.Command(nil) // start the connection
                lookupPeers = append(lookupPeers, lookupPeer)
                lookupAddrs = append(lookupAddrs, host)
            }
            n.lookupPeers.Store(lookupPeers)
            connect = false
        }

        select {
        case <-ticker:
            // send a heartbeat and read a response (read detects closed conns)
            for _, lookupPeer := range lookupPeers {
                n.logf("LOOKUPD(%s): sending heartbeat", lookupPeer)
                cmd := nsq.Ping()
                _, err := lookupPeer.Command(cmd)
                if err != nil {
                    n.logf("LOOKUPD(%s): ERROR %s - %s", lookupPeer, cmd, err)
                }
            }
        case val := <-n.notifyChan:
            var cmd *nsq.Command
            var branch string

            switch val.(type) {
            case *Channel:
                // notify all nsqlookupds that a new channel exists, or that it's removed
                branch = "channel"
                channel := val.(*Channel)
                if channel.Exiting() == true {
                    cmd = nsq.UnRegister(channel.topicName, channel.name)
                } else {
                    cmd = nsq.Register(channel.topicName, channel.name)
                }
            case *Topic:
                // notify all nsqlookupds that a new topic exists, or that it's removed
                branch = "topic"
                topic := val.(*Topic)
                if topic.Exiting() == true {
                    cmd = nsq.UnRegister(topic.name, "")
                } else {
                    cmd = nsq.Register(topic.name, "")
                }
            }

            for _, lookupPeer := range lookupPeers {
                n.logf("LOOKUPD(%s): %s %s", lookupPeer, branch, cmd)
                _, err := lookupPeer.Command(cmd)
                if err != nil {
                    n.logf("LOOKUPD(%s): ERROR %s - %s", lookupPeer, cmd, err)
                }
            }
        case lookupPeer := <-syncTopicChan:
            var commands []*nsq.Command
            // build all the commands first so we exit the lock(s) as fast as possible
            n.RLock()
            for _, topic := range n.topicMap {
                topic.RLock()
                if len(topic.channelMap) == 0 {
                    commands = append(commands, nsq.Register(topic.name, ""))
                } else {
                    for _, channel := range topic.channelMap {
                        commands = append(commands, nsq.Register(channel.topicName, channel.name))
                    }
                }
                topic.RUnlock()
            }
            n.RUnlock()

            for _, cmd := range commands {
                n.logf("LOOKUPD(%s): %s", lookupPeer, cmd)
                _, err := lookupPeer.Command(cmd)
                if err != nil {
                    n.logf("LOOKUPD(%s): ERROR %s - %s", lookupPeer, cmd, err)
                    break
                }
            }
        case <-n.optsNotificationChan:
            var tmpPeers []*lookupPeer
            var tmpAddrs []string
            for _, lp := range lookupPeers {
                if in(lp.addr, n.getOpts().NSQLookupdTCPAddresses) {
                    tmpPeers = append(tmpPeers, lp)
                    tmpAddrs = append(tmpAddrs, lp.addr)
                    continue
                }
                n.logf("LOOKUP(%s): removing peer", lp)
                lp.Close()
            }
            lookupPeers = tmpPeers
            lookupAddrs = tmpAddrs
            connect = true
        case <-n.exitChan:
            goto exit
        }
    }

exit:
    n.logf("LOOKUP: closing")
}

func in(s string, lst []string) bool {
    for _, v := range lst {
        if s == v {
            return true
        }
    }
    return false
}

func (n *NSQD) lookupdHTTPAddrs() []string {
    var lookupHTTPAddrs []string
    lookupPeers := n.lookupPeers.Load()
    if lookupPeers == nil {
        return nil
    }
    for _, lp := range lookupPeers.([]*lookupPeer) {
        if len(lp.Info.BroadcastAddress) <= 0 {
            continue
        }
        addr := net.JoinHostPort(lp.Info.BroadcastAddress, strconv.Itoa(lp.Info.HTTPPort))
        lookupHTTPAddrs = append(lookupHTTPAddrs, addr)
    }
    return lookupHTTPAddrs
}

lookup.go的更多相关文章

  1. SQL Server-聚焦移除Bookmark Lookup、RID Lookup、Key Lookup提高SQL查询性能(六)

    前言 前面几节都是讲的基础内容,本节我们讲讲索引性能优化,当对大数据进行处理时首先想到的就是索引,一旦遇到这样的问题则手忙脚乱,各种查资料,为何平常不扎实基本功呢,我们由浅入深,简短的内容,深入的理解 ...

  2. Salesforce的sharing Rule 不支持Lookup型字段解决方案

    Salesforce 中 sharing rule 并不支持Look up 字段 和 formula 字段.但在实际项目中,有时会需要在sharing rule中直接取Look up型字段的值,解决方 ...

  3. eclipse调试(debug)的时候,出现Source not found,Edit Source Lookup Path,一闪而过

    问题描述 使用Eclipse调试代码的时候,打了断点,经常出现Source not found,网上找了半天,大部分提示点击Edit Source Lookup Path,添加被调试的工程,然而往往没 ...

  4. mongodb 3.x 之实用新功能窥看[2] ——使用$lookup做多表关联处理

    这篇我们来看mongodb另一个非常有意思的东西,那就是$lookup,我们知道mongodb是一个文档型的数据库,而且它也是最像关系型数据库的 一种nosql,但是呢,既然mongodb是无模式的, ...

  5. Lookup component 用法

    Lookup component 类似于Tsql的join子句, select a.* ,b.* from dbo.tis a left join dbo. tdes b on a.code=b.co ...

  6. [SharePoint]javascript client object model 获取lookup 类型的field的值,包括user类型(单人或者多人)的值。how to get the multiple user type/lookup type field value by Javascript client object model

    1. how to get value var context = new SP.ClientContext.get_current(); var web = context.get_web(); v ...

  7. [SharePoint 2010] Modify lookup mapping with PowerShell

    SharePoint支持将列表保存成列表模板,但当列表包含Lookup字段时,通过模板创建的列表会丢失Lookup字段的信息. 通过PowerShell,可以修改Lookup字段的xml内容. Fun ...

  8. Informatica Lookup Transformation组件的Connect 与Unconnected类型用法

    Informatica Lookup Transformation组件的Connect 与Unconnected类型用法及区别:下面是通一个Lookup在不同Mapping中的使用: 1. Conne ...

  9. AX 2012 两种lookup 的显示方式

    第一种:只能单选的lookup: 代码: public void BusinessUnitLookup(FormStringControl _formstrcontroll) { //OMOperat ...

  10. 创建一个List获取数据的lookup

    第一步,在类:syslookup中新建方法 public static client void lookupList(FormStringControl _formStringControl, Lis ...

随机推荐

  1. C语言有哪些鲜为人知的特性?

    译注:本文摘编自 Quora 的一个热门问答贴. 请在linux系统下测试本文中出现的代码 Andrew Weimholt 的回复: switch语句中的case 关键词可以放在if-else或者是循 ...

  2. Linux 命令——tee 重定向到文件并打印到屏幕

    需求: 源于我一个业务实现,需要通过shell脚本去调Java程序,并且能够拿到Java里面的返回值. 思路: 众所周知,通过shell调用Java,肯定是通过 Java -jar xxx.jar 命 ...

  3. Linux的pwd命令详解

    在Linux层次结构中,用户可以在被授权的任意目录下利用mkdir命令创建新目录,也可以利用cd命令从一个目录转换到另一个目录.然而,没有提示符来告知用户目前处于哪一个目录中.想要知道当前所处的目录, ...

  4. 全面解读Java NIO工作原理(3)

    全面解读Java NIO工作原理(3) 2011-12-14 10:31 Rollen Holt Rollen Holt的博客 我要评论(0) 字号:T | T JDK 1.4 中引入的新输入输出 ( ...

  5. Win7下 Python中文正则的奇异表现

    首先贴Win32下的直接Python shell下的测试结果: Python 2.7.6 (default, Nov 10 2013, 19:24:18) [MSC v.1500 32 bit (In ...

  6. 服务器禁止ping

    禁止ping后,不让别人通过域名ping到你的ip, 如果禁用后,你在ping自己的域名会给你返回服务商的IP并提示超时, 这样你就可以减少IP暴露,增加一点安全. 禁止方法: 编辑 /etc/sys ...

  7. Java经验杂谈(2.对Java多态的理解)

    多态是面向对象的重要特性之一,我试着用最简单的方式解释Java多态: 要正确理解多态,我们需要明确如下概念:・定义类型和实际类型・重载和重写・编译和运行 其中实际类型为new关键字后面的类型. 重载发 ...

  8. Angular路由——路由守卫

    一.路由守卫 当用户满足一定条件才被允许进入或者离开一个路由. 路由守卫场景: 只有当用户登录并拥有某些权限的时候才能进入某些路由. 一个由多个表单组成的向导,例如注册流程,用户只有在当前路由的组件中 ...

  9. C#的一些小知识

    一.Server.MapPath E:\MyProject\GisSystem\Json\jsonlist.aspx,GisSystem项目下有个Json文件夹,文件夹下有个jsonlist.aspx ...

  10. 运用jieba库分词

    代码: 统计出团队中文简介中词频 import jieba txt=open("C:\\Users\\Administrator\\Desktop\\介绍.txt","r ...