nats源码阅读记录--订阅主题扩算

router启动后,会找是否有别的router,然后相互构建一个集群。
过程是以下函数实现

//把本地的订阅 消息发送给远端的router
func (s *Server) sendSubsToRoute(route *client) {
   // Send over our account subscriptions.
   var _accs [4096]*Account
   accs := _accs[:0]
   // copy accounts into array first
   s.mu.Lock()
//并发需要,空间换时间
   for _, a := range s.accounts {
      accs = append(accs, a)
   }
   s.mu.Unlock()

   var raw [4096]*subscription
   var closed bool

   route.mu.Lock()
   for _, a := range accs {
      subs := raw[:0]
      a.mu.RLock()
     //从每个账户的每个远程实体(entry)中,随机的找出一个远端的链接,同步订阅信息过去
      for key, rme := range a.rm {
         // FIXME(dlc) - Just pass rme around.
         // Construct a sub on the fly. We need to place
         // a client (or im) to properly set the account.
         var qn []byte
         subEnd := len(key)
         if qi := rme.qi; qi > 0 {
            subEnd = int(qi) - 1
            qn = []byte(key[qi:])
         }
         c := a.randomClient()
         if c == nil {
            continue
         }
         sub := &subscription{client: c, subject: []byte(key[:subEnd]), queue: qn, qw: rme.n}
         subs = append(subs, sub)

      }
      a.mu.RUnlock()
      
      closed = route.sendRouteSubProtos(subs, false, func(sub *subscription) bool {
         //是否订阅的主题能够被对方接收
         //这涉及到账户 import export等概念
         //个人理解:账户是个权限控制问题。例如账户A 导出(export)服务和流给特定账户B/C,那么账户B/C可以有权限订阅对应的主题
        // 其他账号不能订阅。
         return route.canImport(string(sub.subject))
      })

      if closed {
         route.mu.Unlock()
         return
      }
   }
   route.mu.Unlock()
   if !closed {
      route.Debugf("Sent local subscriptions to route")
   }
}
func (c *client) processRemoteSub(argo []byte) (err error) {
   c.traceInOp("RS+", argo)

   // Indicate activity.
   c.in.subs++

   srv := c.srv
   if srv == nil {
      return nil
   }

   // Copy so we do not reference a potentially large buffer
   arg := make([]byte, len(argo))
   copy(arg, argo)

   args := splitArg(arg)
   sub := &subscription{client: c}

   switch len(args) {
   case 2:
      sub.queue = nil
   case 4:
      sub.queue = args[2]
      sub.qw = int32(parseSize(args[3]))
   default:
      return fmt.Errorf("processRemoteSub Parse Error: '%s'", arg)
   }
   sub.subject = args[1]

   //查询订阅者的账户,如果不存在就注册一个新的
   // Lookup the account
   // FIXME(dlc) - This may start having lots of contention?
   accountName := string(args[0])
   acc, _ := c.srv.LookupAccount(accountName)
   if acc == nil {
      if !srv.NewAccountsAllowed() {
         c.Debugf("Unknown account %q for subject %q", accountName, sub.subject)
         return nil
      }
      acc, _ = srv.LookupOrRegisterAccount(accountName)
   }

   c.mu.Lock()
   if c.nc == nil {
      c.mu.Unlock()
      return nil
   }

   //根据本地配置,本地是否接收此主题的订阅
   //对于本地来说,可以把被订阅的信息发布出去
   // Check permissions if applicable.
   if !c.canExport(string(sub.subject)) {
      c.mu.Unlock()
      c.Debugf("Can not export %q, ignoring remote subscription request", sub.subject)
      return nil
   }

   // Check if we have a maximum on the number of subscriptions.
   if c.subsExceeded() {
      c.mu.Unlock()
      c.maxSubsExceeded()
      return nil
   }

   // We store local subs by account and subject and optionally queue name.
   // If we have a queue it will have a trailing weight which we do not want.
   if sub.queue != nil {
      sub.sid = arg[:len(arg)-len(args[3])-1]
   } else {
      sub.sid = arg
   }
   key := string(sub.sid)
   osub := c.subs[key]
   updateGWs := false
   if osub == nil {
      //本地保存订阅信息
      c.subs[string(key)] = sub
      // Now place into the account sl.存入账户列表,用于权限控制
      if err = acc.sl.Insert(sub); err != nil {
         delete(c.subs, key)
         c.mu.Unlock()
         c.Errorf("Could not insert subscription: %v", err)
         c.sendErr("Invalid Subscription")
         return nil
      }
      updateGWs = srv.gateway.enabled
   } else if sub.queue != nil {
      // For a queue we need to update the weight.
      //如果订阅时,指定队列名称,那么按照权重选择订阅的客户端
      atomic.StoreInt32(&osub.qw, sub.qw)
      acc.sl.UpdateRemoteQSub(osub)
   }
   c.mu.Unlock()

   if c.opts.Verbose {
      c.sendOK()
   }
   if updateGWs {
      //扩散给其他集群
      srv.gatewayUpdateSubInterest(acc.Name, sub, 1)
   }
   return nil
}

 

你可能感兴趣的:(msg,queue)