private boolean topicRouteDataIsChange(TopicRouteData olddata, TopicRouteData nowdata) {
   if (olddata == null || nowdata == null) return true;
   TopicRouteData old = olddata.cloneTopicRouteData();
   TopicRouteData now = nowdata.cloneTopicRouteData();
   Collections.sort(old.getQueueDatas());
   Collections.sort(old.getBrokerDatas());
   Collections.sort(now.getQueueDatas());
   Collections.sort(now.getBrokerDatas());
   return !old.equals(now);
 }
  public String findBrokerAddrByTopic(final String topic) {
    TopicRouteData topicRouteData = this.topicRouteTable.get(topic);
    if (topicRouteData != null) {
      List<BrokerData> brokers = topicRouteData.getBrokerDatas();
      if (!brokers.isEmpty()) {
        BrokerData bd = brokers.get(0);
        return bd.selectBrokerAddr();
      }
    }

    return null;
  }
  private boolean isBrokerAddrExistInTopicRouteTable(final String addr) {
    Iterator<Entry<String, TopicRouteData>> it = this.topicRouteTable.entrySet().iterator();
    while (it.hasNext()) {
      Entry<String, TopicRouteData> entry = it.next();
      TopicRouteData topicRouteData = entry.getValue();
      List<BrokerData> bds = topicRouteData.getBrokerDatas();
      for (BrokerData bd : bds) {
        if (bd.getBrokerAddrs() != null) {
          boolean exist = bd.getBrokerAddrs().containsValue(addr);
          if (exist) return true;
        }
      }
    }

    return false;
  }
  /** 调用Name Server接口,根据Topic获取路由信息 */
  public boolean updateTopicRouteInfoFromNameServer(
      final String topic, boolean isDefault, DefaultMQProducer defaultMQProducer) {
    try {
      if (this.lockNamesrv.tryLock(LockTimeoutMillis, TimeUnit.MILLISECONDS)) {
        try {
          TopicRouteData topicRouteData;
          if (isDefault) {
            if (null == defaultMQProducer) return false;
            topicRouteData =
                this.mQClientAPIImpl.getTopicRouteInfoFromNameServer(
                    defaultMQProducer.getCreateTopicKey(), 1000 * 3);
            for (QueueData data : topicRouteData.getQueueDatas()) {
              // 读写分区个数是一致,故只做一次判断
              int queueNums =
                  Math.min(defaultMQProducer.getDefaultTopicQueueNums(), data.getReadQueueNums());
              data.setReadQueueNums(queueNums);
              data.setWriteQueueNums(queueNums);
            }
          } else {
            topicRouteData = this.mQClientAPIImpl.getTopicRouteInfoFromNameServer(topic, 1000 * 3);
          }
          if (topicRouteData != null) {
            TopicRouteData old = this.topicRouteTable.get(topic);
            boolean changed = topicRouteDataIsChange(old, topicRouteData);
            if (!changed) {
              changed = this.isNeedUpdateTopicRouteInfo(topic);
            } else {
              log.info(
                  "the topic[{}] route info changed, odl[{}] ,new[{}]", topic, old, topicRouteData);
            }

            if (changed) {
              // 后面排序会影响下次的equal逻辑判断,所以先clone一份
              TopicRouteData cloneTopicRouteData = topicRouteData.cloneTopicRouteData();

              // 更新Broker地址信息
              for (BrokerData bd : topicRouteData.getBrokerDatas()) {
                this.brokerAddrTable.put(bd.getBrokerName(), bd.getBrokerAddrs());
              }

              // 更新发布队列信息
              {
                TopicPublishInfo publishInfo =
                    topicRouteData2TopicPublishInfo(topic, topicRouteData);
                Iterator<Entry<String, MQProducerInner>> it =
                    this.producerTable.entrySet().iterator();
                while (it.hasNext()) {
                  Entry<String, MQProducerInner> entry = it.next();
                  MQProducerInner impl = entry.getValue();
                  if (impl != null) {
                    impl.updateTopicPublishInfo(topic, publishInfo);
                  }
                }
              }

              // 更新订阅队列信息
              {
                Set<MessageQueue> subscribeInfo =
                    topicRouteData2TopicSubscribeInfo(topic, topicRouteData);
                Iterator<Entry<String, MQConsumerInner>> it =
                    this.consumerTable.entrySet().iterator();
                while (it.hasNext()) {
                  Entry<String, MQConsumerInner> entry = it.next();
                  MQConsumerInner impl = entry.getValue();
                  if (impl != null) {
                    impl.updateTopicSubscribeInfo(topic, subscribeInfo);
                  }
                }
              }
              log.info("topicRouteTable.put TopicRouteData[{}]", cloneTopicRouteData);
              this.topicRouteTable.put(topic, cloneTopicRouteData);
              return true;
            }
          } else {
            log.warn(
                "updateTopicRouteInfoFromNameServer, getTopicRouteInfoFromNameServer return null, Topic: {}",
                topic);
          }
        } catch (Exception e) {
          if (!topic.startsWith(MixAll.RETRY_GROUP_TOPIC_PREFIX)) {
            log.warn("updateTopicRouteInfoFromNameServer Exception", e);
          }
        } finally {
          this.lockNamesrv.unlock();
        }
      } else {
        log.warn("updateTopicRouteInfoFromNameServer tryLock timeout {}ms", LockTimeoutMillis);
      }
    } catch (InterruptedException e) {
      log.warn("updateTopicRouteInfoFromNameServer Exception", e);
    }

    return false;
  }