// 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, n.options, 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() defer t.Unlock() 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) } } } return t }
// 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 { deleteCallback := func(t *Topic) { n.DeleteExistingTopic(t.name) } t = NewTopic(topicName, &context{n}, deleteCallback) n.topicMap[topicName] = t n.logf("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 (s *httpServer) 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(s.context.nsqadmin.options.NSQLookupdHTTPAddresses) for _, topicName := range allTopics { var producers []string producers, _ = lookupd.GetLookupdTopicProducers(topicName, s.context.nsqadmin.options.NSQLookupdHTTPAddresses) if len(producers) == 0 { topicChannels, _ := lookupd.GetLookupdTopicChannels(topicName, s.context.nsqadmin.options.NSQLookupdHTTPAddresses) 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, s.context), TopicMap: channels, Lookupd: s.context.nsqadmin.options.NSQLookupdHTTPAddresses, Version: util.BINARY_VERSION, } err = templates.T.ExecuteTemplate(w, "lookup.html", p) if err != nil { log.Printf("Template Error %s", err.Error()) http.Error(w, "Template Error", 500) } }