// GetTopic performs a thread safe operation // to return a pointer to a Topic object (potentially new) func (n *NSQd) GetTopic(topicName string) *Topic { n.Lock() t, ok := n.topicMap[topicName] if ok { n.Unlock() return t } else { t = NewTopic(topicName, &Context{n}) n.topicMap[topicName] = t log.Printf("TOPIC(%s): created", t.name) // release our global nsqd lock, and switch to a more granular topic lock while we init our // channels from lookupd. This blocks concurrent PutMessages to this topic. t.Lock() n.Unlock() // if using lookupd, make a blocking call to get the topics, and immediately create them. // this makes sure that any message received is buffered to the right channels if len(n.lookupPeers) > 0 { channelNames, _ := lookupd.GetLookupdTopicChannels(t.name, n.lookupHttpAddrs()) for _, channelName := range channelNames { t.getOrCreateChannel(channelName) } } t.Unlock() // NOTE: I would prefer for this to only happen in topic.GetChannel() but we're special // casing the code above so that we can control the locks such that it is impossible // for a message to be written to a (new) topic while we're looking up channels // from lookupd... // // update messagePump state select { case t.channelUpdateChan <- 1: case <-t.exitChan: } } return t }
func lookupHandler(w http.ResponseWriter, req *http.Request) { reqParams, err := util.NewReqParams(req) if err != nil { log.Printf("ERROR: failed to parse request params - %s", err.Error()) http.Error(w, "INVALID_REQUEST", 500) return } channels := make(map[string][]string) allTopics, _ := lookupd.GetLookupdTopics(lookupdHTTPAddrs) for _, topicName := range allTopics { var producers []string producers, _ = lookupd.GetLookupdTopicProducers(topicName, lookupdHTTPAddrs) if len(producers) == 0 { topicChannels, _ := lookupd.GetLookupdTopicChannels(topicName, lookupdHTTPAddrs) channels[topicName] = topicChannels } } p := struct { Title string GraphOptions *GraphOptions TopicMap map[string][]string Lookupd []string Version string }{ Title: "NSQ Lookup", GraphOptions: NewGraphOptions(w, req, reqParams), TopicMap: channels, Lookupd: lookupdHTTPAddrs, Version: util.BINARY_VERSION, } err = templates.ExecuteTemplate(w, "lookup.html", p) if err != nil { log.Printf("Template Error %s", err.Error()) http.Error(w, "Template Error", 500) } }