github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/sublist.go (about)

     1  // Copyright 2016-2024 The NATS Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package server
    15  
    16  import (
    17  	"bytes"
    18  	"errors"
    19  	"strings"
    20  	"sync"
    21  	"sync/atomic"
    22  	"unicode/utf8"
    23  )
    24  
    25  // Sublist is a routing mechanism to handle subject distribution and
    26  // provides a facility to match subjects from published messages to
    27  // interested subscribers. Subscribers can have wildcard subjects to
    28  // match multiple published subjects.
    29  
    30  // Common byte variables for wildcards and token separator.
    31  const (
    32  	pwc   = '*'
    33  	pwcs  = "*"
    34  	fwc   = '>'
    35  	fwcs  = ">"
    36  	tsep  = "."
    37  	btsep = '.'
    38  )
    39  
    40  // Sublist related errors
    41  var (
    42  	ErrInvalidSubject    = errors.New("sublist: invalid subject")
    43  	ErrNotFound          = errors.New("sublist: no matches found")
    44  	ErrNilChan           = errors.New("sublist: nil channel")
    45  	ErrAlreadyRegistered = errors.New("sublist: notification already registered")
    46  )
    47  
    48  const (
    49  	// cacheMax is used to bound limit the frontend cache
    50  	slCacheMax = 1024
    51  	// If we run a sweeper we will drain to this count.
    52  	slCacheSweep = 256
    53  	// plistMin is our lower bounds to create a fast plist for Match.
    54  	plistMin = 256
    55  )
    56  
    57  // SublistResult is a result structure better optimized for queue subs.
    58  type SublistResult struct {
    59  	psubs []*subscription
    60  	qsubs [][]*subscription // don't make this a map, too expensive to iterate
    61  }
    62  
    63  // A Sublist stores and efficiently retrieves subscriptions.
    64  type Sublist struct {
    65  	sync.RWMutex
    66  	genid     uint64
    67  	matches   uint64
    68  	cacheHits uint64
    69  	inserts   uint64
    70  	removes   uint64
    71  	root      *level
    72  	cache     map[string]*SublistResult
    73  	ccSweep   int32
    74  	notify    *notifyMaps
    75  	count     uint32
    76  }
    77  
    78  // notifyMaps holds maps of arrays of channels for notifications
    79  // on a change of interest.
    80  type notifyMaps struct {
    81  	insert map[string][]chan<- bool
    82  	remove map[string][]chan<- bool
    83  }
    84  
    85  // A node contains subscriptions and a pointer to the next level.
    86  type node struct {
    87  	next  *level
    88  	psubs map[*subscription]struct{}
    89  	qsubs map[string]map[*subscription]struct{}
    90  	plist []*subscription
    91  }
    92  
    93  // A level represents a group of nodes and special pointers to
    94  // wildcard nodes.
    95  type level struct {
    96  	nodes    map[string]*node
    97  	pwc, fwc *node
    98  }
    99  
   100  // Create a new default node.
   101  func newNode() *node {
   102  	return &node{psubs: make(map[*subscription]struct{})}
   103  }
   104  
   105  // Create a new default level.
   106  func newLevel() *level {
   107  	return &level{nodes: make(map[string]*node)}
   108  }
   109  
   110  // In general caching is recommended however in some extreme cases where
   111  // interest changes are high, suppressing the cache can help.
   112  // https://github.com/nats-io/nats-server/issues/941
   113  // FIXME(dlc) - should be more dynamic at some point based on cache thrashing.
   114  
   115  // NewSublist will create a default sublist with caching enabled per the flag.
   116  func NewSublist(enableCache bool) *Sublist {
   117  	if enableCache {
   118  		return &Sublist{root: newLevel(), cache: make(map[string]*SublistResult)}
   119  	}
   120  	return &Sublist{root: newLevel()}
   121  }
   122  
   123  // NewSublistWithCache will create a default sublist with caching enabled.
   124  func NewSublistWithCache() *Sublist {
   125  	return NewSublist(true)
   126  }
   127  
   128  // NewSublistNoCache will create a default sublist with caching disabled.
   129  func NewSublistNoCache() *Sublist {
   130  	return NewSublist(false)
   131  }
   132  
   133  // CacheEnabled returns whether or not caching is enabled for this sublist.
   134  func (s *Sublist) CacheEnabled() bool {
   135  	s.RLock()
   136  	enabled := s.cache != nil
   137  	s.RUnlock()
   138  	return enabled
   139  }
   140  
   141  // RegisterNotification will register for notifications when interest for the given
   142  // subject changes. The subject must be a literal publish type subject.
   143  // The notification is true for when the first interest for a subject is inserted,
   144  // and false when all interest in the subject is removed. Note that this interest
   145  // needs to be exact and that wildcards will not trigger the notifications. The sublist
   146  // will not block when trying to send the notification. Its up to the caller to make
   147  // sure the channel send will not block.
   148  func (s *Sublist) RegisterNotification(subject string, notify chan<- bool) error {
   149  	return s.registerNotification(subject, _EMPTY_, notify)
   150  }
   151  
   152  func (s *Sublist) RegisterQueueNotification(subject, queue string, notify chan<- bool) error {
   153  	return s.registerNotification(subject, queue, notify)
   154  }
   155  
   156  func (s *Sublist) registerNotification(subject, queue string, notify chan<- bool) error {
   157  	if subjectHasWildcard(subject) {
   158  		return ErrInvalidSubject
   159  	}
   160  	if notify == nil {
   161  		return ErrNilChan
   162  	}
   163  
   164  	var hasInterest bool
   165  	r := s.Match(subject)
   166  
   167  	if len(r.psubs)+len(r.qsubs) > 0 {
   168  		if queue == _EMPTY_ {
   169  			for _, sub := range r.psubs {
   170  				if string(sub.subject) == subject {
   171  					hasInterest = true
   172  					break
   173  				}
   174  			}
   175  		} else {
   176  			for _, qsub := range r.qsubs {
   177  				qs := qsub[0]
   178  				if string(qs.subject) == subject && string(qs.queue) == queue {
   179  					hasInterest = true
   180  					break
   181  				}
   182  			}
   183  		}
   184  	}
   185  
   186  	key := keyFromSubjectAndQueue(subject, queue)
   187  	var err error
   188  
   189  	s.Lock()
   190  	if s.notify == nil {
   191  		s.notify = &notifyMaps{
   192  			insert: make(map[string][]chan<- bool),
   193  			remove: make(map[string][]chan<- bool),
   194  		}
   195  	}
   196  	// Check which list to add us to.
   197  	if hasInterest {
   198  		err = s.addRemoveNotify(key, notify)
   199  	} else {
   200  		err = s.addInsertNotify(key, notify)
   201  	}
   202  	s.Unlock()
   203  
   204  	if err == nil {
   205  		sendNotification(notify, hasInterest)
   206  	}
   207  	return err
   208  }
   209  
   210  // Lock should be held.
   211  func chkAndRemove(key string, notify chan<- bool, ms map[string][]chan<- bool) bool {
   212  	chs := ms[key]
   213  	for i, ch := range chs {
   214  		if ch == notify {
   215  			chs[i] = chs[len(chs)-1]
   216  			chs = chs[:len(chs)-1]
   217  			if len(chs) == 0 {
   218  				delete(ms, key)
   219  			}
   220  			return true
   221  		}
   222  	}
   223  	return false
   224  }
   225  
   226  func (s *Sublist) ClearNotification(subject string, notify chan<- bool) bool {
   227  	return s.clearNotification(subject, _EMPTY_, notify)
   228  }
   229  
   230  func (s *Sublist) ClearQueueNotification(subject, queue string, notify chan<- bool) bool {
   231  	return s.clearNotification(subject, queue, notify)
   232  }
   233  
   234  func (s *Sublist) clearNotification(subject, queue string, notify chan<- bool) bool {
   235  	s.Lock()
   236  	if s.notify == nil {
   237  		s.Unlock()
   238  		return false
   239  	}
   240  	key := keyFromSubjectAndQueue(subject, queue)
   241  	// Check both, start with remove.
   242  	didRemove := chkAndRemove(key, notify, s.notify.remove)
   243  	didRemove = didRemove || chkAndRemove(key, notify, s.notify.insert)
   244  	// Check if everything is gone
   245  	if len(s.notify.remove)+len(s.notify.insert) == 0 {
   246  		s.notify = nil
   247  	}
   248  	s.Unlock()
   249  	return didRemove
   250  }
   251  
   252  func sendNotification(ch chan<- bool, hasInterest bool) {
   253  	select {
   254  	case ch <- hasInterest:
   255  	default:
   256  	}
   257  }
   258  
   259  // Add a new channel for notification in insert map.
   260  // Write lock should be held.
   261  func (s *Sublist) addInsertNotify(subject string, notify chan<- bool) error {
   262  	return s.addNotify(s.notify.insert, subject, notify)
   263  }
   264  
   265  // Add a new channel for notification in removal map.
   266  // Write lock should be held.
   267  func (s *Sublist) addRemoveNotify(subject string, notify chan<- bool) error {
   268  	return s.addNotify(s.notify.remove, subject, notify)
   269  }
   270  
   271  // Add a new channel for notification.
   272  // Write lock should be held.
   273  func (s *Sublist) addNotify(m map[string][]chan<- bool, subject string, notify chan<- bool) error {
   274  	chs := m[subject]
   275  	if len(chs) > 0 {
   276  		// Check to see if this chan is already registered.
   277  		for _, ch := range chs {
   278  			if ch == notify {
   279  				return ErrAlreadyRegistered
   280  			}
   281  		}
   282  	}
   283  
   284  	m[subject] = append(chs, notify)
   285  	return nil
   286  }
   287  
   288  // To generate a key from subject and queue. We just add spc.
   289  func keyFromSubjectAndQueue(subject, queue string) string {
   290  	if len(queue) == 0 {
   291  		return subject
   292  	}
   293  	var sb strings.Builder
   294  	sb.WriteString(subject)
   295  	sb.WriteString(" ")
   296  	sb.WriteString(queue)
   297  	return sb.String()
   298  }
   299  
   300  // chkForInsertNotification will check to see if we need to notify on this subject.
   301  // Write lock should be held.
   302  func (s *Sublist) chkForInsertNotification(subject, queue string) {
   303  	key := keyFromSubjectAndQueue(subject, queue)
   304  
   305  	// All notify subjects are also literal so just do a hash lookup here.
   306  	if chs := s.notify.insert[key]; len(chs) > 0 {
   307  		for _, ch := range chs {
   308  			sendNotification(ch, true)
   309  		}
   310  		// Move from the insert map to the remove map.
   311  		s.notify.remove[key] = append(s.notify.remove[key], chs...)
   312  		delete(s.notify.insert, key)
   313  	}
   314  }
   315  
   316  // chkForRemoveNotification will check to see if we need to notify on this subject.
   317  // Write lock should be held.
   318  func (s *Sublist) chkForRemoveNotification(subject, queue string) {
   319  	key := keyFromSubjectAndQueue(subject, queue)
   320  	if chs := s.notify.remove[key]; len(chs) > 0 {
   321  		// We need to always check that we have no interest anymore.
   322  		var hasInterest bool
   323  		r := s.matchNoLock(subject)
   324  
   325  		if len(r.psubs)+len(r.qsubs) > 0 {
   326  			if queue == _EMPTY_ {
   327  				for _, sub := range r.psubs {
   328  					if string(sub.subject) == subject {
   329  						hasInterest = true
   330  						break
   331  					}
   332  				}
   333  			} else {
   334  				for _, qsub := range r.qsubs {
   335  					qs := qsub[0]
   336  					if string(qs.subject) == subject && string(qs.queue) == queue {
   337  						hasInterest = true
   338  						break
   339  					}
   340  				}
   341  			}
   342  		}
   343  		if !hasInterest {
   344  			for _, ch := range chs {
   345  				sendNotification(ch, false)
   346  			}
   347  			// Move from the remove map to the insert map.
   348  			s.notify.insert[key] = append(s.notify.insert[key], chs...)
   349  			delete(s.notify.remove, key)
   350  		}
   351  	}
   352  }
   353  
   354  // Insert adds a subscription into the sublist
   355  func (s *Sublist) Insert(sub *subscription) error {
   356  	// copy the subject since we hold this and this might be part of a large byte slice.
   357  	subject := string(sub.subject)
   358  	tsa := [32]string{}
   359  	tokens := tsa[:0]
   360  	start := 0
   361  	for i := 0; i < len(subject); i++ {
   362  		if subject[i] == btsep {
   363  			tokens = append(tokens, subject[start:i])
   364  			start = i + 1
   365  		}
   366  	}
   367  	tokens = append(tokens, subject[start:])
   368  
   369  	s.Lock()
   370  
   371  	var sfwc, haswc, isnew bool
   372  	var n *node
   373  	l := s.root
   374  
   375  	for _, t := range tokens {
   376  		lt := len(t)
   377  		if lt == 0 || sfwc {
   378  			s.Unlock()
   379  			return ErrInvalidSubject
   380  		}
   381  
   382  		if lt > 1 {
   383  			n = l.nodes[t]
   384  		} else {
   385  			switch t[0] {
   386  			case pwc:
   387  				n = l.pwc
   388  				haswc = true
   389  			case fwc:
   390  				n = l.fwc
   391  				haswc, sfwc = true, true
   392  			default:
   393  				n = l.nodes[t]
   394  			}
   395  		}
   396  		if n == nil {
   397  			n = newNode()
   398  			if lt > 1 {
   399  				l.nodes[t] = n
   400  			} else {
   401  				switch t[0] {
   402  				case pwc:
   403  					l.pwc = n
   404  				case fwc:
   405  					l.fwc = n
   406  				default:
   407  					l.nodes[t] = n
   408  				}
   409  			}
   410  		}
   411  		if n.next == nil {
   412  			n.next = newLevel()
   413  		}
   414  		l = n.next
   415  	}
   416  	if sub.queue == nil {
   417  		n.psubs[sub] = struct{}{}
   418  		isnew = len(n.psubs) == 1
   419  		if n.plist != nil {
   420  			n.plist = append(n.plist, sub)
   421  		} else if len(n.psubs) > plistMin {
   422  			n.plist = make([]*subscription, 0, len(n.psubs))
   423  			// Populate
   424  			for psub := range n.psubs {
   425  				n.plist = append(n.plist, psub)
   426  			}
   427  		}
   428  	} else {
   429  		if n.qsubs == nil {
   430  			n.qsubs = make(map[string]map[*subscription]struct{})
   431  		}
   432  		qname := string(sub.queue)
   433  		// This is a queue subscription
   434  		subs, ok := n.qsubs[qname]
   435  		if !ok {
   436  			subs = make(map[*subscription]struct{})
   437  			n.qsubs[qname] = subs
   438  			isnew = true
   439  		}
   440  		subs[sub] = struct{}{}
   441  	}
   442  
   443  	s.count++
   444  	s.inserts++
   445  
   446  	s.addToCache(subject, sub)
   447  	atomic.AddUint64(&s.genid, 1)
   448  
   449  	if s.notify != nil && isnew && !haswc && len(s.notify.insert) > 0 {
   450  		s.chkForInsertNotification(subject, string(sub.queue))
   451  	}
   452  	s.Unlock()
   453  
   454  	return nil
   455  }
   456  
   457  // Deep copy
   458  func copyResult(r *SublistResult) *SublistResult {
   459  	nr := &SublistResult{}
   460  	nr.psubs = append([]*subscription(nil), r.psubs...)
   461  	for _, qr := range r.qsubs {
   462  		nqr := append([]*subscription(nil), qr...)
   463  		nr.qsubs = append(nr.qsubs, nqr)
   464  	}
   465  	return nr
   466  }
   467  
   468  // Adds a new sub to an existing result.
   469  func (r *SublistResult) addSubToResult(sub *subscription) *SublistResult {
   470  	// Copy since others may have a reference.
   471  	nr := copyResult(r)
   472  	if sub.queue == nil {
   473  		nr.psubs = append(nr.psubs, sub)
   474  	} else {
   475  		if i := findQSlot(sub.queue, nr.qsubs); i >= 0 {
   476  			nr.qsubs[i] = append(nr.qsubs[i], sub)
   477  		} else {
   478  			nr.qsubs = append(nr.qsubs, []*subscription{sub})
   479  		}
   480  	}
   481  	return nr
   482  }
   483  
   484  // addToCache will add the new entry to the existing cache
   485  // entries if needed. Assumes write lock is held.
   486  // Assumes write lock is held.
   487  func (s *Sublist) addToCache(subject string, sub *subscription) {
   488  	if s.cache == nil {
   489  		return
   490  	}
   491  	// If literal we can direct match.
   492  	if subjectIsLiteral(subject) {
   493  		if r := s.cache[subject]; r != nil {
   494  			s.cache[subject] = r.addSubToResult(sub)
   495  		}
   496  		return
   497  	}
   498  	for key, r := range s.cache {
   499  		if matchLiteral(key, subject) {
   500  			s.cache[key] = r.addSubToResult(sub)
   501  		}
   502  	}
   503  }
   504  
   505  // removeFromCache will remove the sub from any active cache entries.
   506  // Assumes write lock is held.
   507  func (s *Sublist) removeFromCache(subject string) {
   508  	if s.cache == nil {
   509  		return
   510  	}
   511  	// If literal we can direct match.
   512  	if subjectIsLiteral(subject) {
   513  		delete(s.cache, subject)
   514  		return
   515  	}
   516  	// Wildcard here.
   517  	for key := range s.cache {
   518  		if matchLiteral(key, subject) {
   519  			delete(s.cache, key)
   520  		}
   521  	}
   522  }
   523  
   524  // a place holder for an empty result.
   525  var emptyResult = &SublistResult{}
   526  
   527  // Match will match all entries to the literal subject.
   528  // It will return a set of results for both normal and queue subscribers.
   529  func (s *Sublist) Match(subject string) *SublistResult {
   530  	return s.match(subject, true, nil)
   531  }
   532  
   533  // MatchWithResult will match all entries to the literal subject, reusing the
   534  // supplied SublistResult to reduce allocations on hot paths.
   535  // It will return a set of results for both normal and queue subscribers.
   536  func (s *Sublist) MatchWithResult(subject string, result *SublistResult) *SublistResult {
   537  	return s.match(subject, true, result)
   538  }
   539  
   540  func (s *Sublist) matchNoLock(subject string) *SublistResult {
   541  	return s.match(subject, false, nil)
   542  }
   543  
   544  func (s *Sublist) match(subject string, doLock bool, result *SublistResult) *SublistResult {
   545  	atomic.AddUint64(&s.matches, 1)
   546  
   547  	// Check cache first.
   548  	if doLock {
   549  		s.RLock()
   550  	}
   551  	// Writing to the cache is only allowed if not supplying our
   552  	// own SublistResult, i.e. via call to MatchWithResult.
   553  	cacheEnabled := result == nil && s.cache != nil
   554  	r, ok := s.cache[subject]
   555  	if doLock {
   556  		s.RUnlock()
   557  	}
   558  	if ok {
   559  		atomic.AddUint64(&s.cacheHits, 1)
   560  		return r
   561  	}
   562  
   563  	tsa := [32]string{}
   564  	tokens := tsa[:0]
   565  	start := 0
   566  	for i := 0; i < len(subject); i++ {
   567  		if subject[i] == btsep {
   568  			if i-start == 0 {
   569  				return emptyResult
   570  			}
   571  			tokens = append(tokens, subject[start:i])
   572  			start = i + 1
   573  		}
   574  	}
   575  	if start >= len(subject) {
   576  		return emptyResult
   577  	}
   578  	tokens = append(tokens, subject[start:])
   579  
   580  	// FIXME(dlc) - Make shared pool between sublist and client readLoop?
   581  	if result == nil {
   582  		result = &SublistResult{}
   583  	}
   584  	result.psubs = result.psubs[:0]
   585  	result.qsubs = result.qsubs[:0]
   586  
   587  	// Get result from the main structure and place into the shared cache.
   588  	// Hold the read lock to avoid race between match and store.
   589  	var n int
   590  
   591  	if doLock {
   592  		if cacheEnabled {
   593  			s.Lock()
   594  		} else {
   595  			s.RLock()
   596  		}
   597  	}
   598  
   599  	matchLevel(s.root, tokens, result)
   600  	// Check for empty result.
   601  	if len(result.psubs) == 0 && len(result.qsubs) == 0 {
   602  		result = emptyResult
   603  	}
   604  	if cacheEnabled {
   605  		s.cache[subject] = result
   606  		n = len(s.cache)
   607  	}
   608  	if doLock {
   609  		if cacheEnabled {
   610  			s.Unlock()
   611  		} else {
   612  			s.RUnlock()
   613  		}
   614  	}
   615  
   616  	// Reduce the cache count if we have exceeded our set maximum.
   617  	if cacheEnabled && n > slCacheMax && atomic.CompareAndSwapInt32(&s.ccSweep, 0, 1) {
   618  		go s.reduceCacheCount()
   619  	}
   620  
   621  	return result
   622  }
   623  
   624  // Remove entries in the cache until we are under the maximum.
   625  // TODO(dlc) this could be smarter now that its not inline.
   626  func (s *Sublist) reduceCacheCount() {
   627  	defer atomic.StoreInt32(&s.ccSweep, 0)
   628  	// If we are over the cache limit randomly drop until under the limit.
   629  	s.Lock()
   630  	for key := range s.cache {
   631  		delete(s.cache, key)
   632  		if len(s.cache) <= slCacheSweep {
   633  			break
   634  		}
   635  	}
   636  	s.Unlock()
   637  }
   638  
   639  // Helper function for auto-expanding remote qsubs.
   640  func isRemoteQSub(sub *subscription) bool {
   641  	return sub != nil && sub.queue != nil && sub.client != nil && (sub.client.kind == ROUTER || sub.client.kind == LEAF)
   642  }
   643  
   644  // UpdateRemoteQSub should be called when we update the weight of an existing
   645  // remote queue sub.
   646  func (s *Sublist) UpdateRemoteQSub(sub *subscription) {
   647  	// We could search to make sure we find it, but probably not worth
   648  	// it unless we are thrashing the cache. Just remove from our L2 and update
   649  	// the genid so L1 will be flushed.
   650  	s.Lock()
   651  	s.removeFromCache(string(sub.subject))
   652  	atomic.AddUint64(&s.genid, 1)
   653  	s.Unlock()
   654  }
   655  
   656  // This will add in a node's results to the total results.
   657  func addNodeToResults(n *node, results *SublistResult) {
   658  	// Normal subscriptions
   659  	if n.plist != nil {
   660  		results.psubs = append(results.psubs, n.plist...)
   661  	} else {
   662  		for psub := range n.psubs {
   663  			results.psubs = append(results.psubs, psub)
   664  		}
   665  	}
   666  	// Queue subscriptions
   667  	for qname, qr := range n.qsubs {
   668  		if len(qr) == 0 {
   669  			continue
   670  		}
   671  		// Need to find matching list in results
   672  		var i int
   673  		if i = findQSlot([]byte(qname), results.qsubs); i < 0 {
   674  			i = len(results.qsubs)
   675  			nqsub := make([]*subscription, 0, len(qr))
   676  			results.qsubs = append(results.qsubs, nqsub)
   677  		}
   678  		for sub := range qr {
   679  			if isRemoteQSub(sub) {
   680  				ns := atomic.LoadInt32(&sub.qw)
   681  				// Shadow these subscriptions
   682  				for n := 0; n < int(ns); n++ {
   683  					results.qsubs[i] = append(results.qsubs[i], sub)
   684  				}
   685  			} else {
   686  				results.qsubs[i] = append(results.qsubs[i], sub)
   687  			}
   688  		}
   689  	}
   690  }
   691  
   692  // We do not use a map here since we want iteration to be past when
   693  // processing publishes in L1 on client. So we need to walk sequentially
   694  // for now. Keep an eye on this in case we start getting large number of
   695  // different queue subscribers for the same subject.
   696  func findQSlot(queue []byte, qsl [][]*subscription) int {
   697  	if queue == nil {
   698  		return -1
   699  	}
   700  	for i, qr := range qsl {
   701  		if len(qr) > 0 && bytes.Equal(queue, qr[0].queue) {
   702  			return i
   703  		}
   704  	}
   705  	return -1
   706  }
   707  
   708  // matchLevel is used to recursively descend into the trie.
   709  func matchLevel(l *level, toks []string, results *SublistResult) {
   710  	var pwc, n *node
   711  	for i, t := range toks {
   712  		if l == nil {
   713  			return
   714  		}
   715  		if l.fwc != nil {
   716  			addNodeToResults(l.fwc, results)
   717  		}
   718  		if pwc = l.pwc; pwc != nil {
   719  			matchLevel(pwc.next, toks[i+1:], results)
   720  		}
   721  		n = l.nodes[t]
   722  		if n != nil {
   723  			l = n.next
   724  		} else {
   725  			l = nil
   726  		}
   727  	}
   728  	if n != nil {
   729  		addNodeToResults(n, results)
   730  	}
   731  	if pwc != nil {
   732  		addNodeToResults(pwc, results)
   733  	}
   734  }
   735  
   736  // lnt is used to track descent into levels for a removal for pruning.
   737  type lnt struct {
   738  	l *level
   739  	n *node
   740  	t string
   741  }
   742  
   743  // Raw low level remove, can do batches with lock held outside.
   744  func (s *Sublist) remove(sub *subscription, shouldLock bool, doCacheUpdates bool) error {
   745  	subject := string(sub.subject)
   746  	tsa := [32]string{}
   747  	tokens := tsa[:0]
   748  	start := 0
   749  	for i := 0; i < len(subject); i++ {
   750  		if subject[i] == btsep {
   751  			tokens = append(tokens, subject[start:i])
   752  			start = i + 1
   753  		}
   754  	}
   755  	tokens = append(tokens, subject[start:])
   756  
   757  	if shouldLock {
   758  		s.Lock()
   759  		defer s.Unlock()
   760  	}
   761  
   762  	var sfwc, haswc bool
   763  	var n *node
   764  	l := s.root
   765  
   766  	// Track levels for pruning
   767  	var lnts [32]lnt
   768  	levels := lnts[:0]
   769  
   770  	for _, t := range tokens {
   771  		lt := len(t)
   772  		if lt == 0 || sfwc {
   773  			return ErrInvalidSubject
   774  		}
   775  		if l == nil {
   776  			return ErrNotFound
   777  		}
   778  		if lt > 1 {
   779  			n = l.nodes[t]
   780  		} else {
   781  			switch t[0] {
   782  			case pwc:
   783  				n = l.pwc
   784  				haswc = true
   785  			case fwc:
   786  				n = l.fwc
   787  				haswc, sfwc = true, true
   788  			default:
   789  				n = l.nodes[t]
   790  			}
   791  		}
   792  		if n != nil {
   793  			levels = append(levels, lnt{l, n, t})
   794  			l = n.next
   795  		} else {
   796  			l = nil
   797  		}
   798  	}
   799  	removed, last := s.removeFromNode(n, sub)
   800  	if !removed {
   801  		return ErrNotFound
   802  	}
   803  
   804  	s.count--
   805  	s.removes++
   806  
   807  	for i := len(levels) - 1; i >= 0; i-- {
   808  		l, n, t := levels[i].l, levels[i].n, levels[i].t
   809  		if n.isEmpty() {
   810  			l.pruneNode(n, t)
   811  		}
   812  	}
   813  	if doCacheUpdates {
   814  		s.removeFromCache(subject)
   815  		atomic.AddUint64(&s.genid, 1)
   816  	}
   817  
   818  	if s.notify != nil && last && !haswc && len(s.notify.remove) > 0 {
   819  		s.chkForRemoveNotification(subject, string(sub.queue))
   820  	}
   821  
   822  	return nil
   823  }
   824  
   825  // Remove will remove a subscription.
   826  func (s *Sublist) Remove(sub *subscription) error {
   827  	return s.remove(sub, true, true)
   828  }
   829  
   830  // RemoveBatch will remove a list of subscriptions.
   831  func (s *Sublist) RemoveBatch(subs []*subscription) error {
   832  	if len(subs) == 0 {
   833  		return nil
   834  	}
   835  
   836  	s.Lock()
   837  	defer s.Unlock()
   838  
   839  	// TODO(dlc) - We could try to be smarter here for a client going away but the account
   840  	// has a large number of subscriptions compared to this client. Quick and dirty testing
   841  	// though said just disabling all the time best for now.
   842  
   843  	// Turn off our cache if enabled.
   844  	wasEnabled := s.cache != nil
   845  	s.cache = nil
   846  	// We will try to remove all subscriptions but will report the first that caused
   847  	// an error. In other words, we don't bail out at the first error which would
   848  	// possibly leave a bunch of subscriptions that could have been removed.
   849  	var err error
   850  	for _, sub := range subs {
   851  		if lerr := s.remove(sub, false, false); lerr != nil && err == nil {
   852  			err = lerr
   853  		}
   854  	}
   855  	// Turn caching back on here.
   856  	atomic.AddUint64(&s.genid, 1)
   857  	if wasEnabled {
   858  		s.cache = make(map[string]*SublistResult)
   859  	}
   860  	return err
   861  }
   862  
   863  // pruneNode is used to prune an empty node from the tree.
   864  func (l *level) pruneNode(n *node, t string) {
   865  	if n == nil {
   866  		return
   867  	}
   868  	if n == l.fwc {
   869  		l.fwc = nil
   870  	} else if n == l.pwc {
   871  		l.pwc = nil
   872  	} else {
   873  		delete(l.nodes, t)
   874  	}
   875  }
   876  
   877  // isEmpty will test if the node has any entries. Used
   878  // in pruning.
   879  func (n *node) isEmpty() bool {
   880  	if len(n.psubs) == 0 && len(n.qsubs) == 0 {
   881  		if n.next == nil || n.next.numNodes() == 0 {
   882  			return true
   883  		}
   884  	}
   885  	return false
   886  }
   887  
   888  // Return the number of nodes for the given level.
   889  func (l *level) numNodes() int {
   890  	num := len(l.nodes)
   891  	if l.pwc != nil {
   892  		num++
   893  	}
   894  	if l.fwc != nil {
   895  		num++
   896  	}
   897  	return num
   898  }
   899  
   900  // Remove the sub for the given node.
   901  func (s *Sublist) removeFromNode(n *node, sub *subscription) (found, last bool) {
   902  	if n == nil {
   903  		return false, true
   904  	}
   905  	if sub.queue == nil {
   906  		_, found = n.psubs[sub]
   907  		delete(n.psubs, sub)
   908  		if found && n.plist != nil {
   909  			// This will brute force remove the plist to perform
   910  			// correct behavior. Will get re-populated on a call
   911  			// to Match as needed.
   912  			n.plist = nil
   913  		}
   914  		return found, len(n.psubs) == 0
   915  	}
   916  
   917  	// We have a queue group subscription here
   918  	qsub := n.qsubs[string(sub.queue)]
   919  	_, found = qsub[sub]
   920  	delete(qsub, sub)
   921  	if len(qsub) == 0 {
   922  		// This is the last queue subscription interest when len(qsub) == 0, not
   923  		// when n.qsubs is empty.
   924  		last = true
   925  		delete(n.qsubs, string(sub.queue))
   926  	}
   927  	return found, last
   928  }
   929  
   930  // Count returns the number of subscriptions.
   931  func (s *Sublist) Count() uint32 {
   932  	s.RLock()
   933  	defer s.RUnlock()
   934  	return s.count
   935  }
   936  
   937  // CacheCount returns the number of result sets in the cache.
   938  func (s *Sublist) CacheCount() int {
   939  	s.RLock()
   940  	cc := len(s.cache)
   941  	s.RUnlock()
   942  	return cc
   943  }
   944  
   945  // SublistStats are public stats for the sublist
   946  type SublistStats struct {
   947  	NumSubs      uint32  `json:"num_subscriptions"`
   948  	NumCache     uint32  `json:"num_cache"`
   949  	NumInserts   uint64  `json:"num_inserts"`
   950  	NumRemoves   uint64  `json:"num_removes"`
   951  	NumMatches   uint64  `json:"num_matches"`
   952  	CacheHitRate float64 `json:"cache_hit_rate"`
   953  	MaxFanout    uint32  `json:"max_fanout"`
   954  	AvgFanout    float64 `json:"avg_fanout"`
   955  	totFanout    int
   956  	cacheCnt     int
   957  	cacheHits    uint64
   958  }
   959  
   960  func (s *SublistStats) add(stat *SublistStats) {
   961  	s.NumSubs += stat.NumSubs
   962  	s.NumCache += stat.NumCache
   963  	s.NumInserts += stat.NumInserts
   964  	s.NumRemoves += stat.NumRemoves
   965  	s.NumMatches += stat.NumMatches
   966  	s.cacheHits += stat.cacheHits
   967  	if s.MaxFanout < stat.MaxFanout {
   968  		s.MaxFanout = stat.MaxFanout
   969  	}
   970  
   971  	// ignore slStats.AvgFanout, collect the values
   972  	// it's based on instead
   973  	s.totFanout += stat.totFanout
   974  	s.cacheCnt += stat.cacheCnt
   975  	if s.totFanout > 0 {
   976  		s.AvgFanout = float64(s.totFanout) / float64(s.cacheCnt)
   977  	}
   978  	if s.NumMatches > 0 {
   979  		s.CacheHitRate = float64(s.cacheHits) / float64(s.NumMatches)
   980  	}
   981  }
   982  
   983  // Stats will return a stats structure for the current state.
   984  func (s *Sublist) Stats() *SublistStats {
   985  	st := &SublistStats{}
   986  
   987  	s.RLock()
   988  	cache := s.cache
   989  	cc := len(s.cache)
   990  	st.NumSubs = s.count
   991  	st.NumInserts = s.inserts
   992  	st.NumRemoves = s.removes
   993  	s.RUnlock()
   994  
   995  	st.NumCache = uint32(cc)
   996  	st.NumMatches = atomic.LoadUint64(&s.matches)
   997  	st.cacheHits = atomic.LoadUint64(&s.cacheHits)
   998  	if st.NumMatches > 0 {
   999  		st.CacheHitRate = float64(st.cacheHits) / float64(st.NumMatches)
  1000  	}
  1001  
  1002  	// whip through cache for fanout stats, this can be off if cache is full and doing evictions.
  1003  	// If this is called frequently, which it should not be, this could hurt performance.
  1004  	if cache != nil {
  1005  		tot, max, clen := 0, 0, 0
  1006  		s.RLock()
  1007  		for _, r := range s.cache {
  1008  			clen++
  1009  			l := len(r.psubs) + len(r.qsubs)
  1010  			tot += l
  1011  			if l > max {
  1012  				max = l
  1013  			}
  1014  		}
  1015  		s.RUnlock()
  1016  		st.totFanout = tot
  1017  		st.cacheCnt = clen
  1018  		st.MaxFanout = uint32(max)
  1019  		if tot > 0 {
  1020  			st.AvgFanout = float64(tot) / float64(clen)
  1021  		}
  1022  	}
  1023  	return st
  1024  }
  1025  
  1026  // numLevels will return the maximum number of levels
  1027  // contained in the Sublist tree.
  1028  func (s *Sublist) numLevels() int {
  1029  	return visitLevel(s.root, 0)
  1030  }
  1031  
  1032  // visitLevel is used to descend the Sublist tree structure
  1033  // recursively.
  1034  func visitLevel(l *level, depth int) int {
  1035  	if l == nil || l.numNodes() == 0 {
  1036  		return depth
  1037  	}
  1038  
  1039  	depth++
  1040  	maxDepth := depth
  1041  
  1042  	for _, n := range l.nodes {
  1043  		if n == nil {
  1044  			continue
  1045  		}
  1046  		newDepth := visitLevel(n.next, depth)
  1047  		if newDepth > maxDepth {
  1048  			maxDepth = newDepth
  1049  		}
  1050  	}
  1051  	if l.pwc != nil {
  1052  		pwcDepth := visitLevel(l.pwc.next, depth)
  1053  		if pwcDepth > maxDepth {
  1054  			maxDepth = pwcDepth
  1055  		}
  1056  	}
  1057  	if l.fwc != nil {
  1058  		fwcDepth := visitLevel(l.fwc.next, depth)
  1059  		if fwcDepth > maxDepth {
  1060  			maxDepth = fwcDepth
  1061  		}
  1062  	}
  1063  	return maxDepth
  1064  }
  1065  
  1066  // Determine if a subject has any wildcard tokens.
  1067  func subjectHasWildcard(subject string) bool {
  1068  	// This one exits earlier then !subjectIsLiteral(subject)
  1069  	for i, c := range subject {
  1070  		if c == pwc || c == fwc {
  1071  			if (i == 0 || subject[i-1] == btsep) &&
  1072  				(i+1 == len(subject) || subject[i+1] == btsep) {
  1073  				return true
  1074  			}
  1075  		}
  1076  	}
  1077  	return false
  1078  }
  1079  
  1080  // Determine if the subject has any wildcards. Fast version, does not check for
  1081  // valid subject. Used in caching layer.
  1082  func subjectIsLiteral(subject string) bool {
  1083  	for i, c := range subject {
  1084  		if c == pwc || c == fwc {
  1085  			if (i == 0 || subject[i-1] == btsep) &&
  1086  				(i+1 == len(subject) || subject[i+1] == btsep) {
  1087  				return false
  1088  			}
  1089  		}
  1090  	}
  1091  	return true
  1092  }
  1093  
  1094  // IsValidPublishSubject returns true if a subject is valid and a literal, false otherwise
  1095  func IsValidPublishSubject(subject string) bool {
  1096  	return IsValidSubject(subject) && subjectIsLiteral(subject)
  1097  }
  1098  
  1099  // IsValidSubject returns true if a subject is valid, false otherwise
  1100  func IsValidSubject(subject string) bool {
  1101  	return isValidSubject(subject, false)
  1102  }
  1103  
  1104  func isValidSubject(subject string, checkRunes bool) bool {
  1105  	if subject == _EMPTY_ {
  1106  		return false
  1107  	}
  1108  	if checkRunes {
  1109  		// Since casting to a string will always produce valid UTF-8, we need to look for replacement runes.
  1110  		// This signals something is off or corrupt.
  1111  		for _, r := range subject {
  1112  			if r == utf8.RuneError {
  1113  				return false
  1114  			}
  1115  		}
  1116  	}
  1117  	sfwc := false
  1118  	tokens := strings.Split(subject, tsep)
  1119  	for _, t := range tokens {
  1120  		length := len(t)
  1121  		if length == 0 || sfwc {
  1122  			return false
  1123  		}
  1124  		if length > 1 {
  1125  			if strings.ContainsAny(t, "\t\n\f\r ") {
  1126  				return false
  1127  			}
  1128  			continue
  1129  		}
  1130  		switch t[0] {
  1131  		case fwc:
  1132  			sfwc = true
  1133  		case ' ', '\t', '\n', '\r', '\f':
  1134  			return false
  1135  		}
  1136  	}
  1137  	return true
  1138  }
  1139  
  1140  // IsValidLiteralSubject returns true if a subject is valid and literal (no wildcards), false otherwise
  1141  func IsValidLiteralSubject(subject string) bool {
  1142  	return isValidLiteralSubject(strings.Split(subject, tsep))
  1143  }
  1144  
  1145  // isValidLiteralSubject returns true if the tokens are valid and literal (no wildcards), false otherwise
  1146  func isValidLiteralSubject(tokens []string) bool {
  1147  	for _, t := range tokens {
  1148  		if len(t) == 0 {
  1149  			return false
  1150  		}
  1151  		if len(t) > 1 {
  1152  			continue
  1153  		}
  1154  		switch t[0] {
  1155  		case pwc, fwc:
  1156  			return false
  1157  		}
  1158  	}
  1159  	return true
  1160  }
  1161  
  1162  // ValidateMappingDestination returns nil error if the subject is a valid subject mapping destination subject
  1163  func ValidateMappingDestination(subject string) error {
  1164  	if subject == _EMPTY_ {
  1165  		return nil
  1166  	}
  1167  	subjectTokens := strings.Split(subject, tsep)
  1168  	sfwc := false
  1169  	for _, t := range subjectTokens {
  1170  		length := len(t)
  1171  		if length == 0 || sfwc {
  1172  			return &mappingDestinationErr{t, ErrInvalidMappingDestinationSubject}
  1173  		}
  1174  
  1175  		if length > 4 && t[0] == '{' && t[1] == '{' && t[length-2] == '}' && t[length-1] == '}' {
  1176  			if !partitionMappingFunctionRegEx.MatchString(t) &&
  1177  				!wildcardMappingFunctionRegEx.MatchString(t) &&
  1178  				!splitFromLeftMappingFunctionRegEx.MatchString(t) &&
  1179  				!splitFromRightMappingFunctionRegEx.MatchString(t) &&
  1180  				!sliceFromLeftMappingFunctionRegEx.MatchString(t) &&
  1181  				!sliceFromRightMappingFunctionRegEx.MatchString(t) &&
  1182  				!splitMappingFunctionRegEx.MatchString(t) {
  1183  				return &mappingDestinationErr{t, ErrUnknownMappingDestinationFunction}
  1184  			} else {
  1185  				continue
  1186  			}
  1187  		}
  1188  
  1189  		if length == 1 && t[0] == fwc {
  1190  			sfwc = true
  1191  		} else if strings.ContainsAny(t, "\t\n\f\r ") {
  1192  			return ErrInvalidMappingDestinationSubject
  1193  		}
  1194  	}
  1195  	return nil
  1196  }
  1197  
  1198  // Will check tokens and report back if the have any partial or full wildcards.
  1199  func analyzeTokens(tokens []string) (hasPWC, hasFWC bool) {
  1200  	for _, t := range tokens {
  1201  		if lt := len(t); lt == 0 || lt > 1 {
  1202  			continue
  1203  		}
  1204  		switch t[0] {
  1205  		case pwc:
  1206  			hasPWC = true
  1207  		case fwc:
  1208  			hasFWC = true
  1209  		}
  1210  	}
  1211  	return
  1212  }
  1213  
  1214  // Check on a token basis if they could match.
  1215  func tokensCanMatch(t1, t2 string) bool {
  1216  	if len(t1) == 0 || len(t2) == 0 {
  1217  		return false
  1218  	}
  1219  	t1c, t2c := t1[0], t2[0]
  1220  	if t1c == pwc || t2c == pwc || t1c == fwc || t2c == fwc {
  1221  		return true
  1222  	}
  1223  	return t1 == t2
  1224  }
  1225  
  1226  // SubjectsCollide will determine if two subjects could both match a single literal subject.
  1227  func SubjectsCollide(subj1, subj2 string) bool {
  1228  	if subj1 == subj2 {
  1229  		return true
  1230  	}
  1231  	toks1 := strings.Split(subj1, tsep)
  1232  	toks2 := strings.Split(subj2, tsep)
  1233  	pwc1, fwc1 := analyzeTokens(toks1)
  1234  	pwc2, fwc2 := analyzeTokens(toks2)
  1235  	// if both literal just string compare.
  1236  	l1, l2 := !(pwc1 || fwc1), !(pwc2 || fwc2)
  1237  	if l1 && l2 {
  1238  		return subj1 == subj2
  1239  	}
  1240  	// So one or both have wildcards. If one is literal than we can do subset matching.
  1241  	if l1 && !l2 {
  1242  		return isSubsetMatch(toks1, subj2)
  1243  	} else if l2 && !l1 {
  1244  		return isSubsetMatch(toks2, subj1)
  1245  	}
  1246  	// Both have wildcards.
  1247  	// If they only have partials then the lengths must match.
  1248  	if !fwc1 && !fwc2 && len(toks1) != len(toks2) {
  1249  		return false
  1250  	}
  1251  	if lt1, lt2 := len(toks1), len(toks2); lt1 != lt2 {
  1252  		// If the shorter one only has partials then these will not collide.
  1253  		if lt1 < lt2 && !fwc1 || lt2 < lt1 && !fwc2 {
  1254  			return false
  1255  		}
  1256  	}
  1257  
  1258  	stop := len(toks1)
  1259  	if len(toks2) < stop {
  1260  		stop = len(toks2)
  1261  	}
  1262  
  1263  	// We look for reasons to say no.
  1264  	for i := 0; i < stop; i++ {
  1265  		t1, t2 := toks1[i], toks2[i]
  1266  		if !tokensCanMatch(t1, t2) {
  1267  			return false
  1268  		}
  1269  	}
  1270  
  1271  	return true
  1272  }
  1273  
  1274  // Returns number of tokens in the subject.
  1275  func numTokens(subject string) int {
  1276  	var numTokens int
  1277  	if len(subject) == 0 {
  1278  		return 0
  1279  	}
  1280  	for i := 0; i < len(subject); i++ {
  1281  		if subject[i] == btsep {
  1282  			numTokens++
  1283  		}
  1284  	}
  1285  	return numTokens + 1
  1286  }
  1287  
  1288  // Fast way to return an indexed token.
  1289  // This is one based, so first token is TokenAt(subject, 1)
  1290  func tokenAt(subject string, index uint8) string {
  1291  	ti, start := uint8(1), 0
  1292  	for i := 0; i < len(subject); i++ {
  1293  		if subject[i] == btsep {
  1294  			if ti == index {
  1295  				return subject[start:i]
  1296  			}
  1297  			start = i + 1
  1298  			ti++
  1299  		}
  1300  	}
  1301  	if ti == index {
  1302  		return subject[start:]
  1303  	}
  1304  	return _EMPTY_
  1305  }
  1306  
  1307  // use similar to append. meaning, the updated slice will be returned
  1308  func tokenizeSubjectIntoSlice(tts []string, subject string) []string {
  1309  	start := 0
  1310  	for i := 0; i < len(subject); i++ {
  1311  		if subject[i] == btsep {
  1312  			tts = append(tts, subject[start:i])
  1313  			start = i + 1
  1314  		}
  1315  	}
  1316  	tts = append(tts, subject[start:])
  1317  	return tts
  1318  }
  1319  
  1320  // Calls into the function isSubsetMatch()
  1321  func subjectIsSubsetMatch(subject, test string) bool {
  1322  	tsa := [32]string{}
  1323  	tts := tokenizeSubjectIntoSlice(tsa[:0], subject)
  1324  	return isSubsetMatch(tts, test)
  1325  }
  1326  
  1327  // This will test a subject as an array of tokens against a test subject
  1328  // Calls into the function isSubsetMatchTokenized
  1329  func isSubsetMatch(tokens []string, test string) bool {
  1330  	tsa := [32]string{}
  1331  	tts := tokenizeSubjectIntoSlice(tsa[:0], test)
  1332  	return isSubsetMatchTokenized(tokens, tts)
  1333  }
  1334  
  1335  // This will test a subject as an array of tokens against a test subject (also encoded as array of tokens)
  1336  // and determine if the tokens are matched. Both test subject and tokens
  1337  // may contain wildcards. So foo.* is a subset match of [">", "*.*", "foo.*"],
  1338  // but not of foo.bar, etc.
  1339  func isSubsetMatchTokenized(tokens, test []string) bool {
  1340  	// Walk the target tokens
  1341  	for i, t2 := range test {
  1342  		if i >= len(tokens) {
  1343  			return false
  1344  		}
  1345  		l := len(t2)
  1346  		if l == 0 {
  1347  			return false
  1348  		}
  1349  		if t2[0] == fwc && l == 1 {
  1350  			return true
  1351  		}
  1352  		t1 := tokens[i]
  1353  
  1354  		l = len(t1)
  1355  		if l == 0 || t1[0] == fwc && l == 1 {
  1356  			return false
  1357  		}
  1358  
  1359  		if t1[0] == pwc && len(t1) == 1 {
  1360  			m := t2[0] == pwc && len(t2) == 1
  1361  			if !m {
  1362  				return false
  1363  			}
  1364  			if i >= len(test) {
  1365  				return true
  1366  			}
  1367  			continue
  1368  		}
  1369  		if t2[0] != pwc && strings.Compare(t1, t2) != 0 {
  1370  			return false
  1371  		}
  1372  	}
  1373  	return len(tokens) == len(test)
  1374  }
  1375  
  1376  // matchLiteral is used to test literal subjects, those that do not have any
  1377  // wildcards, with a target subject. This is used in the cache layer.
  1378  func matchLiteral(literal, subject string) bool {
  1379  	li := 0
  1380  	ll := len(literal)
  1381  	ls := len(subject)
  1382  	for i := 0; i < ls; i++ {
  1383  		if li >= ll {
  1384  			return false
  1385  		}
  1386  		// This function has been optimized for speed.
  1387  		// For instance, do not set b:=subject[i] here since
  1388  		// we may bump `i` in this loop to avoid `continue` or
  1389  		// skipping common test in a particular test.
  1390  		// Run Benchmark_SublistMatchLiteral before making any change.
  1391  		switch subject[i] {
  1392  		case pwc:
  1393  			// NOTE: This is not testing validity of a subject, instead ensures
  1394  			// that wildcards are treated as such if they follow some basic rules,
  1395  			// namely that they are a token on their own.
  1396  			if i == 0 || subject[i-1] == btsep {
  1397  				if i == ls-1 {
  1398  					// There is no more token in the subject after this wildcard.
  1399  					// Skip token in literal and expect to not find a separator.
  1400  					for {
  1401  						// End of literal, this is a match.
  1402  						if li >= ll {
  1403  							return true
  1404  						}
  1405  						// Presence of separator, this can't be a match.
  1406  						if literal[li] == btsep {
  1407  							return false
  1408  						}
  1409  						li++
  1410  					}
  1411  				} else if subject[i+1] == btsep {
  1412  					// There is another token in the subject after this wildcard.
  1413  					// Skip token in literal and expect to get a separator.
  1414  					for {
  1415  						// We found the end of the literal before finding a separator,
  1416  						// this can't be a match.
  1417  						if li >= ll {
  1418  							return false
  1419  						}
  1420  						if literal[li] == btsep {
  1421  							break
  1422  						}
  1423  						li++
  1424  					}
  1425  					// Bump `i` since we know there is a `.` following, we are
  1426  					// safe. The common test below is going to check `.` with `.`
  1427  					// which is good. A `continue` here is too costly.
  1428  					i++
  1429  				}
  1430  			}
  1431  		case fwc:
  1432  			// For `>` to be a wildcard, it means being the only or last character
  1433  			// in the string preceded by a `.`
  1434  			if (i == 0 || subject[i-1] == btsep) && i == ls-1 {
  1435  				return true
  1436  			}
  1437  		}
  1438  		if subject[i] != literal[li] {
  1439  			return false
  1440  		}
  1441  		li++
  1442  	}
  1443  	// Make sure we have processed all of the literal's chars..
  1444  	return li >= ll
  1445  }
  1446  
  1447  func addLocalSub(sub *subscription, subs *[]*subscription, includeLeafHubs bool) {
  1448  	if sub != nil && sub.client != nil {
  1449  		kind := sub.client.kind
  1450  		if kind == CLIENT || kind == SYSTEM || kind == JETSTREAM || kind == ACCOUNT ||
  1451  			(includeLeafHubs && sub.client.isHubLeafNode() /* implied kind==LEAF */) {
  1452  			*subs = append(*subs, sub)
  1453  		}
  1454  	}
  1455  }
  1456  
  1457  func (s *Sublist) addNodeToSubs(n *node, subs *[]*subscription, includeLeafHubs bool) {
  1458  	// Normal subscriptions
  1459  	if n.plist != nil {
  1460  		for _, sub := range n.plist {
  1461  			addLocalSub(sub, subs, includeLeafHubs)
  1462  		}
  1463  	} else {
  1464  		for sub := range n.psubs {
  1465  			addLocalSub(sub, subs, includeLeafHubs)
  1466  		}
  1467  	}
  1468  	// Queue subscriptions
  1469  	for _, qr := range n.qsubs {
  1470  		for sub := range qr {
  1471  			addLocalSub(sub, subs, includeLeafHubs)
  1472  		}
  1473  	}
  1474  }
  1475  
  1476  func (s *Sublist) collectLocalSubs(l *level, subs *[]*subscription, includeLeafHubs bool) {
  1477  	for _, n := range l.nodes {
  1478  		s.addNodeToSubs(n, subs, includeLeafHubs)
  1479  		s.collectLocalSubs(n.next, subs, includeLeafHubs)
  1480  	}
  1481  	if l.pwc != nil {
  1482  		s.addNodeToSubs(l.pwc, subs, includeLeafHubs)
  1483  		s.collectLocalSubs(l.pwc.next, subs, includeLeafHubs)
  1484  	}
  1485  	if l.fwc != nil {
  1486  		s.addNodeToSubs(l.fwc, subs, includeLeafHubs)
  1487  		s.collectLocalSubs(l.fwc.next, subs, includeLeafHubs)
  1488  	}
  1489  }
  1490  
  1491  // Return all local client subscriptions. Use the supplied slice.
  1492  func (s *Sublist) localSubs(subs *[]*subscription, includeLeafHubs bool) {
  1493  	s.RLock()
  1494  	s.collectLocalSubs(s.root, subs, includeLeafHubs)
  1495  	s.RUnlock()
  1496  }
  1497  
  1498  // All is used to collect all subscriptions.
  1499  func (s *Sublist) All(subs *[]*subscription) {
  1500  	s.RLock()
  1501  	s.collectAllSubs(s.root, subs)
  1502  	s.RUnlock()
  1503  }
  1504  
  1505  func (s *Sublist) addAllNodeToSubs(n *node, subs *[]*subscription) {
  1506  	// Normal subscriptions
  1507  	if n.plist != nil {
  1508  		*subs = append(*subs, n.plist...)
  1509  	} else {
  1510  		for sub := range n.psubs {
  1511  			*subs = append(*subs, sub)
  1512  		}
  1513  	}
  1514  	// Queue subscriptions
  1515  	for _, qr := range n.qsubs {
  1516  		for sub := range qr {
  1517  			*subs = append(*subs, sub)
  1518  		}
  1519  	}
  1520  }
  1521  
  1522  func (s *Sublist) collectAllSubs(l *level, subs *[]*subscription) {
  1523  	for _, n := range l.nodes {
  1524  		s.addAllNodeToSubs(n, subs)
  1525  		s.collectAllSubs(n.next, subs)
  1526  	}
  1527  	if l.pwc != nil {
  1528  		s.addAllNodeToSubs(l.pwc, subs)
  1529  		s.collectAllSubs(l.pwc.next, subs)
  1530  	}
  1531  	if l.fwc != nil {
  1532  		s.addAllNodeToSubs(l.fwc, subs)
  1533  		s.collectAllSubs(l.fwc.next, subs)
  1534  	}
  1535  }
  1536  
  1537  // For a given subject (which may contain wildcards), this call returns all
  1538  // subscriptions that would match that subject. For instance, suppose that
  1539  // the sublist contains: foo.bar, foo.bar.baz and foo.baz, ReverseMatch("foo.*")
  1540  // would return foo.bar and foo.baz.
  1541  // This is used in situations where the sublist is likely to contain only
  1542  // literals and one wants to get all the subjects that would have been a match
  1543  // to a subscription on `subject`.
  1544  func (s *Sublist) ReverseMatch(subject string) *SublistResult {
  1545  	tsa := [32]string{}
  1546  	tokens := tsa[:0]
  1547  	start := 0
  1548  	for i := 0; i < len(subject); i++ {
  1549  		if subject[i] == btsep {
  1550  			tokens = append(tokens, subject[start:i])
  1551  			start = i + 1
  1552  		}
  1553  	}
  1554  	tokens = append(tokens, subject[start:])
  1555  
  1556  	result := &SublistResult{}
  1557  
  1558  	s.RLock()
  1559  	reverseMatchLevel(s.root, tokens, nil, result)
  1560  	// Check for empty result.
  1561  	if len(result.psubs) == 0 && len(result.qsubs) == 0 {
  1562  		result = emptyResult
  1563  	}
  1564  	s.RUnlock()
  1565  
  1566  	return result
  1567  }
  1568  
  1569  func reverseMatchLevel(l *level, toks []string, n *node, results *SublistResult) {
  1570  	if l == nil {
  1571  		return
  1572  	}
  1573  	for i, t := range toks {
  1574  		if len(t) == 1 {
  1575  			if t[0] == fwc {
  1576  				getAllNodes(l, results)
  1577  				return
  1578  			} else if t[0] == pwc {
  1579  				for _, n := range l.nodes {
  1580  					reverseMatchLevel(n.next, toks[i+1:], n, results)
  1581  				}
  1582  				if l.pwc != nil {
  1583  					reverseMatchLevel(l.pwc.next, toks[i+1:], n, results)
  1584  				}
  1585  				if l.fwc != nil {
  1586  					getAllNodes(l, results)
  1587  				}
  1588  				return
  1589  			}
  1590  		}
  1591  		// If the sub tree has a fwc at this position, match as well.
  1592  		if l.fwc != nil {
  1593  			getAllNodes(l, results)
  1594  			return
  1595  		} else if l.pwc != nil {
  1596  			reverseMatchLevel(l.pwc.next, toks[i+1:], n, results)
  1597  		}
  1598  		n = l.nodes[t]
  1599  		if n == nil {
  1600  			break
  1601  		}
  1602  		l = n.next
  1603  	}
  1604  	if n != nil {
  1605  		addNodeToResults(n, results)
  1606  	}
  1607  }
  1608  
  1609  func getAllNodes(l *level, results *SublistResult) {
  1610  	if l == nil {
  1611  		return
  1612  	}
  1613  	if l.pwc != nil {
  1614  		addNodeToResults(l.pwc, results)
  1615  	}
  1616  	if l.fwc != nil {
  1617  		addNodeToResults(l.fwc, results)
  1618  	}
  1619  	for _, n := range l.nodes {
  1620  		addNodeToResults(n, results)
  1621  		getAllNodes(n.next, results)
  1622  	}
  1623  }