get.pme.sh/pnats@v0.0.0-20240304004023-26bb5a137ed0/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, sub *subscription) {
   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)
   531  }
   532  
   533  func (s *Sublist) matchNoLock(subject string) *SublistResult {
   534  	return s.match(subject, false)
   535  }
   536  
   537  func (s *Sublist) match(subject string, doLock bool) *SublistResult {
   538  	atomic.AddUint64(&s.matches, 1)
   539  
   540  	// Check cache first.
   541  	if doLock {
   542  		s.RLock()
   543  	}
   544  	cacheEnabled := s.cache != nil
   545  	r, ok := s.cache[subject]
   546  	if doLock {
   547  		s.RUnlock()
   548  	}
   549  	if ok {
   550  		atomic.AddUint64(&s.cacheHits, 1)
   551  		return r
   552  	}
   553  
   554  	tsa := [32]string{}
   555  	tokens := tsa[:0]
   556  	start := 0
   557  	for i := 0; i < len(subject); i++ {
   558  		if subject[i] == btsep {
   559  			if i-start == 0 {
   560  				return emptyResult
   561  			}
   562  			tokens = append(tokens, subject[start:i])
   563  			start = i + 1
   564  		}
   565  	}
   566  	if start >= len(subject) {
   567  		return emptyResult
   568  	}
   569  	tokens = append(tokens, subject[start:])
   570  
   571  	// FIXME(dlc) - Make shared pool between sublist and client readLoop?
   572  	result := &SublistResult{}
   573  
   574  	// Get result from the main structure and place into the shared cache.
   575  	// Hold the read lock to avoid race between match and store.
   576  	var n int
   577  
   578  	if doLock {
   579  		if cacheEnabled {
   580  			s.Lock()
   581  		} else {
   582  			s.RLock()
   583  		}
   584  	}
   585  
   586  	matchLevel(s.root, tokens, result)
   587  	// Check for empty result.
   588  	if len(result.psubs) == 0 && len(result.qsubs) == 0 {
   589  		result = emptyResult
   590  	}
   591  	if cacheEnabled {
   592  		s.cache[subject] = result
   593  		n = len(s.cache)
   594  	}
   595  	if doLock {
   596  		if cacheEnabled {
   597  			s.Unlock()
   598  		} else {
   599  			s.RUnlock()
   600  		}
   601  	}
   602  
   603  	// Reduce the cache count if we have exceeded our set maximum.
   604  	if cacheEnabled && n > slCacheMax && atomic.CompareAndSwapInt32(&s.ccSweep, 0, 1) {
   605  		go s.reduceCacheCount()
   606  	}
   607  
   608  	return result
   609  }
   610  
   611  // Remove entries in the cache until we are under the maximum.
   612  // TODO(dlc) this could be smarter now that its not inline.
   613  func (s *Sublist) reduceCacheCount() {
   614  	defer atomic.StoreInt32(&s.ccSweep, 0)
   615  	// If we are over the cache limit randomly drop until under the limit.
   616  	s.Lock()
   617  	for key := range s.cache {
   618  		delete(s.cache, key)
   619  		if len(s.cache) <= slCacheSweep {
   620  			break
   621  		}
   622  	}
   623  	s.Unlock()
   624  }
   625  
   626  // Helper function for auto-expanding remote qsubs.
   627  func isRemoteQSub(sub *subscription) bool {
   628  	return sub != nil && sub.queue != nil && sub.client != nil && (sub.client.kind == ROUTER || sub.client.kind == LEAF)
   629  }
   630  
   631  // UpdateRemoteQSub should be called when we update the weight of an existing
   632  // remote queue sub.
   633  func (s *Sublist) UpdateRemoteQSub(sub *subscription) {
   634  	// We could search to make sure we find it, but probably not worth
   635  	// it unless we are thrashing the cache. Just remove from our L2 and update
   636  	// the genid so L1 will be flushed.
   637  	s.Lock()
   638  	s.removeFromCache(string(sub.subject), sub)
   639  	atomic.AddUint64(&s.genid, 1)
   640  	s.Unlock()
   641  }
   642  
   643  // This will add in a node's results to the total results.
   644  func addNodeToResults(n *node, results *SublistResult) {
   645  	// Normal subscriptions
   646  	if n.plist != nil {
   647  		results.psubs = append(results.psubs, n.plist...)
   648  	} else {
   649  		for psub := range n.psubs {
   650  			results.psubs = append(results.psubs, psub)
   651  		}
   652  	}
   653  	// Queue subscriptions
   654  	for qname, qr := range n.qsubs {
   655  		if len(qr) == 0 {
   656  			continue
   657  		}
   658  		// Need to find matching list in results
   659  		var i int
   660  		if i = findQSlot([]byte(qname), results.qsubs); i < 0 {
   661  			i = len(results.qsubs)
   662  			nqsub := make([]*subscription, 0, len(qr))
   663  			results.qsubs = append(results.qsubs, nqsub)
   664  		}
   665  		for sub := range qr {
   666  			if isRemoteQSub(sub) {
   667  				ns := atomic.LoadInt32(&sub.qw)
   668  				// Shadow these subscriptions
   669  				for n := 0; n < int(ns); n++ {
   670  					results.qsubs[i] = append(results.qsubs[i], sub)
   671  				}
   672  			} else {
   673  				results.qsubs[i] = append(results.qsubs[i], sub)
   674  			}
   675  		}
   676  	}
   677  }
   678  
   679  // We do not use a map here since we want iteration to be past when
   680  // processing publishes in L1 on client. So we need to walk sequentially
   681  // for now. Keep an eye on this in case we start getting large number of
   682  // different queue subscribers for the same subject.
   683  func findQSlot(queue []byte, qsl [][]*subscription) int {
   684  	if queue == nil {
   685  		return -1
   686  	}
   687  	for i, qr := range qsl {
   688  		if len(qr) > 0 && bytes.Equal(queue, qr[0].queue) {
   689  			return i
   690  		}
   691  	}
   692  	return -1
   693  }
   694  
   695  // matchLevel is used to recursively descend into the trie.
   696  func matchLevel(l *level, toks []string, results *SublistResult) {
   697  	var pwc, n *node
   698  	for i, t := range toks {
   699  		if l == nil {
   700  			return
   701  		}
   702  		if l.fwc != nil {
   703  			addNodeToResults(l.fwc, results)
   704  		}
   705  		if pwc = l.pwc; pwc != nil {
   706  			matchLevel(pwc.next, toks[i+1:], results)
   707  		}
   708  		n = l.nodes[t]
   709  		if n != nil {
   710  			l = n.next
   711  		} else {
   712  			l = nil
   713  		}
   714  	}
   715  	if n != nil {
   716  		addNodeToResults(n, results)
   717  	}
   718  	if pwc != nil {
   719  		addNodeToResults(pwc, results)
   720  	}
   721  }
   722  
   723  // lnt is used to track descent into levels for a removal for pruning.
   724  type lnt struct {
   725  	l *level
   726  	n *node
   727  	t string
   728  }
   729  
   730  // Raw low level remove, can do batches with lock held outside.
   731  func (s *Sublist) remove(sub *subscription, shouldLock bool, doCacheUpdates bool) error {
   732  	subject := string(sub.subject)
   733  	tsa := [32]string{}
   734  	tokens := tsa[:0]
   735  	start := 0
   736  	for i := 0; i < len(subject); i++ {
   737  		if subject[i] == btsep {
   738  			tokens = append(tokens, subject[start:i])
   739  			start = i + 1
   740  		}
   741  	}
   742  	tokens = append(tokens, subject[start:])
   743  
   744  	if shouldLock {
   745  		s.Lock()
   746  		defer s.Unlock()
   747  	}
   748  
   749  	var sfwc, haswc bool
   750  	var n *node
   751  	l := s.root
   752  
   753  	// Track levels for pruning
   754  	var lnts [32]lnt
   755  	levels := lnts[:0]
   756  
   757  	for _, t := range tokens {
   758  		lt := len(t)
   759  		if lt == 0 || sfwc {
   760  			return ErrInvalidSubject
   761  		}
   762  		if l == nil {
   763  			return ErrNotFound
   764  		}
   765  		if lt > 1 {
   766  			n = l.nodes[t]
   767  		} else {
   768  			switch t[0] {
   769  			case pwc:
   770  				n = l.pwc
   771  				haswc = true
   772  			case fwc:
   773  				n = l.fwc
   774  				haswc, sfwc = true, true
   775  			default:
   776  				n = l.nodes[t]
   777  			}
   778  		}
   779  		if n != nil {
   780  			levels = append(levels, lnt{l, n, t})
   781  			l = n.next
   782  		} else {
   783  			l = nil
   784  		}
   785  	}
   786  	removed, last := s.removeFromNode(n, sub)
   787  	if !removed {
   788  		return ErrNotFound
   789  	}
   790  
   791  	s.count--
   792  	s.removes++
   793  
   794  	for i := len(levels) - 1; i >= 0; i-- {
   795  		l, n, t := levels[i].l, levels[i].n, levels[i].t
   796  		if n.isEmpty() {
   797  			l.pruneNode(n, t)
   798  		}
   799  	}
   800  	if doCacheUpdates {
   801  		s.removeFromCache(subject, sub)
   802  		atomic.AddUint64(&s.genid, 1)
   803  	}
   804  
   805  	if s.notify != nil && last && !haswc && len(s.notify.remove) > 0 {
   806  		s.chkForRemoveNotification(subject, string(sub.queue))
   807  	}
   808  
   809  	return nil
   810  }
   811  
   812  // Remove will remove a subscription.
   813  func (s *Sublist) Remove(sub *subscription) error {
   814  	return s.remove(sub, true, true)
   815  }
   816  
   817  // RemoveBatch will remove a list of subscriptions.
   818  func (s *Sublist) RemoveBatch(subs []*subscription) error {
   819  	if len(subs) == 0 {
   820  		return nil
   821  	}
   822  
   823  	s.Lock()
   824  	defer s.Unlock()
   825  
   826  	// TODO(dlc) - We could try to be smarter here for a client going away but the account
   827  	// has a large number of subscriptions compared to this client. Quick and dirty testing
   828  	// though said just disabling all the time best for now.
   829  
   830  	// Turn off our cache if enabled.
   831  	wasEnabled := s.cache != nil
   832  	s.cache = nil
   833  	// We will try to remove all subscriptions but will report the first that caused
   834  	// an error. In other words, we don't bail out at the first error which would
   835  	// possibly leave a bunch of subscriptions that could have been removed.
   836  	var err error
   837  	for _, sub := range subs {
   838  		if lerr := s.remove(sub, false, false); lerr != nil && err == nil {
   839  			err = lerr
   840  		}
   841  	}
   842  	// Turn caching back on here.
   843  	atomic.AddUint64(&s.genid, 1)
   844  	if wasEnabled {
   845  		s.cache = make(map[string]*SublistResult)
   846  	}
   847  	return err
   848  }
   849  
   850  // pruneNode is used to prune an empty node from the tree.
   851  func (l *level) pruneNode(n *node, t string) {
   852  	if n == nil {
   853  		return
   854  	}
   855  	if n == l.fwc {
   856  		l.fwc = nil
   857  	} else if n == l.pwc {
   858  		l.pwc = nil
   859  	} else {
   860  		delete(l.nodes, t)
   861  	}
   862  }
   863  
   864  // isEmpty will test if the node has any entries. Used
   865  // in pruning.
   866  func (n *node) isEmpty() bool {
   867  	if len(n.psubs) == 0 && len(n.qsubs) == 0 {
   868  		if n.next == nil || n.next.numNodes() == 0 {
   869  			return true
   870  		}
   871  	}
   872  	return false
   873  }
   874  
   875  // Return the number of nodes for the given level.
   876  func (l *level) numNodes() int {
   877  	num := len(l.nodes)
   878  	if l.pwc != nil {
   879  		num++
   880  	}
   881  	if l.fwc != nil {
   882  		num++
   883  	}
   884  	return num
   885  }
   886  
   887  // Remove the sub for the given node.
   888  func (s *Sublist) removeFromNode(n *node, sub *subscription) (found, last bool) {
   889  	if n == nil {
   890  		return false, true
   891  	}
   892  	if sub.queue == nil {
   893  		_, found = n.psubs[sub]
   894  		delete(n.psubs, sub)
   895  		if found && n.plist != nil {
   896  			// This will brute force remove the plist to perform
   897  			// correct behavior. Will get re-populated on a call
   898  			// to Match as needed.
   899  			n.plist = nil
   900  		}
   901  		return found, len(n.psubs) == 0
   902  	}
   903  
   904  	// We have a queue group subscription here
   905  	qsub := n.qsubs[string(sub.queue)]
   906  	_, found = qsub[sub]
   907  	delete(qsub, sub)
   908  	if len(qsub) == 0 {
   909  		// This is the last queue subscription interest when len(qsub) == 0, not
   910  		// when n.qsubs is empty.
   911  		last = true
   912  		delete(n.qsubs, string(sub.queue))
   913  	}
   914  	return found, last
   915  }
   916  
   917  // Count returns the number of subscriptions.
   918  func (s *Sublist) Count() uint32 {
   919  	s.RLock()
   920  	defer s.RUnlock()
   921  	return s.count
   922  }
   923  
   924  // CacheCount returns the number of result sets in the cache.
   925  func (s *Sublist) CacheCount() int {
   926  	s.RLock()
   927  	cc := len(s.cache)
   928  	s.RUnlock()
   929  	return cc
   930  }
   931  
   932  // SublistStats are public stats for the sublist
   933  type SublistStats struct {
   934  	NumSubs      uint32  `json:"num_subscriptions"`
   935  	NumCache     uint32  `json:"num_cache"`
   936  	NumInserts   uint64  `json:"num_inserts"`
   937  	NumRemoves   uint64  `json:"num_removes"`
   938  	NumMatches   uint64  `json:"num_matches"`
   939  	CacheHitRate float64 `json:"cache_hit_rate"`
   940  	MaxFanout    uint32  `json:"max_fanout"`
   941  	AvgFanout    float64 `json:"avg_fanout"`
   942  	totFanout    int
   943  	cacheCnt     int
   944  	cacheHits    uint64
   945  }
   946  
   947  func (s *SublistStats) add(stat *SublistStats) {
   948  	s.NumSubs += stat.NumSubs
   949  	s.NumCache += stat.NumCache
   950  	s.NumInserts += stat.NumInserts
   951  	s.NumRemoves += stat.NumRemoves
   952  	s.NumMatches += stat.NumMatches
   953  	s.cacheHits += stat.cacheHits
   954  	if s.MaxFanout < stat.MaxFanout {
   955  		s.MaxFanout = stat.MaxFanout
   956  	}
   957  
   958  	// ignore slStats.AvgFanout, collect the values
   959  	// it's based on instead
   960  	s.totFanout += stat.totFanout
   961  	s.cacheCnt += stat.cacheCnt
   962  	if s.totFanout > 0 {
   963  		s.AvgFanout = float64(s.totFanout) / float64(s.cacheCnt)
   964  	}
   965  	if s.NumMatches > 0 {
   966  		s.CacheHitRate = float64(s.cacheHits) / float64(s.NumMatches)
   967  	}
   968  }
   969  
   970  // Stats will return a stats structure for the current state.
   971  func (s *Sublist) Stats() *SublistStats {
   972  	st := &SublistStats{}
   973  
   974  	s.RLock()
   975  	cache := s.cache
   976  	cc := len(s.cache)
   977  	st.NumSubs = s.count
   978  	st.NumInserts = s.inserts
   979  	st.NumRemoves = s.removes
   980  	s.RUnlock()
   981  
   982  	st.NumCache = uint32(cc)
   983  	st.NumMatches = atomic.LoadUint64(&s.matches)
   984  	st.cacheHits = atomic.LoadUint64(&s.cacheHits)
   985  	if st.NumMatches > 0 {
   986  		st.CacheHitRate = float64(st.cacheHits) / float64(st.NumMatches)
   987  	}
   988  
   989  	// whip through cache for fanout stats, this can be off if cache is full and doing evictions.
   990  	// If this is called frequently, which it should not be, this could hurt performance.
   991  	if cache != nil {
   992  		tot, max, clen := 0, 0, 0
   993  		s.RLock()
   994  		for _, r := range s.cache {
   995  			clen++
   996  			l := len(r.psubs) + len(r.qsubs)
   997  			tot += l
   998  			if l > max {
   999  				max = l
  1000  			}
  1001  		}
  1002  		s.RUnlock()
  1003  		st.totFanout = tot
  1004  		st.cacheCnt = clen
  1005  		st.MaxFanout = uint32(max)
  1006  		if tot > 0 {
  1007  			st.AvgFanout = float64(tot) / float64(clen)
  1008  		}
  1009  	}
  1010  	return st
  1011  }
  1012  
  1013  // numLevels will return the maximum number of levels
  1014  // contained in the Sublist tree.
  1015  func (s *Sublist) numLevels() int {
  1016  	return visitLevel(s.root, 0)
  1017  }
  1018  
  1019  // visitLevel is used to descend the Sublist tree structure
  1020  // recursively.
  1021  func visitLevel(l *level, depth int) int {
  1022  	if l == nil || l.numNodes() == 0 {
  1023  		return depth
  1024  	}
  1025  
  1026  	depth++
  1027  	maxDepth := depth
  1028  
  1029  	for _, n := range l.nodes {
  1030  		if n == nil {
  1031  			continue
  1032  		}
  1033  		newDepth := visitLevel(n.next, depth)
  1034  		if newDepth > maxDepth {
  1035  			maxDepth = newDepth
  1036  		}
  1037  	}
  1038  	if l.pwc != nil {
  1039  		pwcDepth := visitLevel(l.pwc.next, depth)
  1040  		if pwcDepth > maxDepth {
  1041  			maxDepth = pwcDepth
  1042  		}
  1043  	}
  1044  	if l.fwc != nil {
  1045  		fwcDepth := visitLevel(l.fwc.next, depth)
  1046  		if fwcDepth > maxDepth {
  1047  			maxDepth = fwcDepth
  1048  		}
  1049  	}
  1050  	return maxDepth
  1051  }
  1052  
  1053  // Determine if a subject has any wildcard tokens.
  1054  func subjectHasWildcard(subject string) bool {
  1055  	// This one exits earlier then !subjectIsLiteral(subject)
  1056  	for i, c := range subject {
  1057  		if c == pwc || c == fwc {
  1058  			if (i == 0 || subject[i-1] == btsep) &&
  1059  				(i+1 == len(subject) || subject[i+1] == btsep) {
  1060  				return true
  1061  			}
  1062  		}
  1063  	}
  1064  	return false
  1065  }
  1066  
  1067  // Determine if the subject has any wildcards. Fast version, does not check for
  1068  // valid subject. Used in caching layer.
  1069  func subjectIsLiteral(subject string) bool {
  1070  	for i, c := range subject {
  1071  		if c == pwc || c == fwc {
  1072  			if (i == 0 || subject[i-1] == btsep) &&
  1073  				(i+1 == len(subject) || subject[i+1] == btsep) {
  1074  				return false
  1075  			}
  1076  		}
  1077  	}
  1078  	return true
  1079  }
  1080  
  1081  // IsValidPublishSubject returns true if a subject is valid and a literal, false otherwise
  1082  func IsValidPublishSubject(subject string) bool {
  1083  	return IsValidSubject(subject) && subjectIsLiteral(subject)
  1084  }
  1085  
  1086  // IsValidSubject returns true if a subject is valid, false otherwise
  1087  func IsValidSubject(subject string) bool {
  1088  	return isValidSubject(subject, false)
  1089  }
  1090  
  1091  func isValidSubject(subject string, checkRunes bool) bool {
  1092  	if subject == _EMPTY_ {
  1093  		return false
  1094  	}
  1095  	if checkRunes {
  1096  		// Since casting to a string will always produce valid UTF-8, we need to look for replacement runes.
  1097  		// This signals something is off or corrupt.
  1098  		for _, r := range subject {
  1099  			if r == utf8.RuneError {
  1100  				return false
  1101  			}
  1102  		}
  1103  	}
  1104  	sfwc := false
  1105  	tokens := strings.Split(subject, tsep)
  1106  	for _, t := range tokens {
  1107  		length := len(t)
  1108  		if length == 0 || sfwc {
  1109  			return false
  1110  		}
  1111  		if length > 1 {
  1112  			if strings.ContainsAny(t, "\t\n\f\r ") {
  1113  				return false
  1114  			}
  1115  			continue
  1116  		}
  1117  		switch t[0] {
  1118  		case fwc:
  1119  			sfwc = true
  1120  		case ' ', '\t', '\n', '\r', '\f':
  1121  			return false
  1122  		}
  1123  	}
  1124  	return true
  1125  }
  1126  
  1127  // IsValidLiteralSubject returns true if a subject is valid and literal (no wildcards), false otherwise
  1128  func IsValidLiteralSubject(subject string) bool {
  1129  	return isValidLiteralSubject(strings.Split(subject, tsep))
  1130  }
  1131  
  1132  // isValidLiteralSubject returns true if the tokens are valid and literal (no wildcards), false otherwise
  1133  func isValidLiteralSubject(tokens []string) bool {
  1134  	for _, t := range tokens {
  1135  		if len(t) == 0 {
  1136  			return false
  1137  		}
  1138  		if len(t) > 1 {
  1139  			continue
  1140  		}
  1141  		switch t[0] {
  1142  		case pwc, fwc:
  1143  			return false
  1144  		}
  1145  	}
  1146  	return true
  1147  }
  1148  
  1149  // ValidateMappingDestination returns nil error if the subject is a valid subject mapping destination subject
  1150  func ValidateMappingDestination(subject string) error {
  1151  	if subject == _EMPTY_ {
  1152  		return nil
  1153  	}
  1154  	subjectTokens := strings.Split(subject, tsep)
  1155  	sfwc := false
  1156  	for _, t := range subjectTokens {
  1157  		length := len(t)
  1158  		if length == 0 || sfwc {
  1159  			return &mappingDestinationErr{t, ErrInvalidMappingDestinationSubject}
  1160  		}
  1161  
  1162  		if length > 4 && t[0] == '{' && t[1] == '{' && t[length-2] == '}' && t[length-1] == '}' {
  1163  			if !partitionMappingFunctionRegEx.MatchString(t) &&
  1164  				!wildcardMappingFunctionRegEx.MatchString(t) &&
  1165  				!splitFromLeftMappingFunctionRegEx.MatchString(t) &&
  1166  				!splitFromRightMappingFunctionRegEx.MatchString(t) &&
  1167  				!sliceFromLeftMappingFunctionRegEx.MatchString(t) &&
  1168  				!sliceFromRightMappingFunctionRegEx.MatchString(t) &&
  1169  				!splitMappingFunctionRegEx.MatchString(t) {
  1170  				return &mappingDestinationErr{t, ErrUnknownMappingDestinationFunction}
  1171  			} else {
  1172  				continue
  1173  			}
  1174  		}
  1175  
  1176  		if length == 1 && t[0] == fwc {
  1177  			sfwc = true
  1178  		} else if strings.ContainsAny(t, "\t\n\f\r ") {
  1179  			return ErrInvalidMappingDestinationSubject
  1180  		}
  1181  	}
  1182  	return nil
  1183  }
  1184  
  1185  // Will check tokens and report back if the have any partial or full wildcards.
  1186  func analyzeTokens(tokens []string) (hasPWC, hasFWC bool) {
  1187  	for _, t := range tokens {
  1188  		if lt := len(t); lt == 0 || lt > 1 {
  1189  			continue
  1190  		}
  1191  		switch t[0] {
  1192  		case pwc:
  1193  			hasPWC = true
  1194  		case fwc:
  1195  			hasFWC = true
  1196  		}
  1197  	}
  1198  	return
  1199  }
  1200  
  1201  // Check on a token basis if they could match.
  1202  func tokensCanMatch(t1, t2 string) bool {
  1203  	if len(t1) == 0 || len(t2) == 0 {
  1204  		return false
  1205  	}
  1206  	t1c, t2c := t1[0], t2[0]
  1207  	if t1c == pwc || t2c == pwc || t1c == fwc || t2c == fwc {
  1208  		return true
  1209  	}
  1210  	return t1 == t2
  1211  }
  1212  
  1213  // SubjectsCollide will determine if two subjects could both match a single literal subject.
  1214  func SubjectsCollide(subj1, subj2 string) bool {
  1215  	if subj1 == subj2 {
  1216  		return true
  1217  	}
  1218  	toks1 := strings.Split(subj1, tsep)
  1219  	toks2 := strings.Split(subj2, tsep)
  1220  	pwc1, fwc1 := analyzeTokens(toks1)
  1221  	pwc2, fwc2 := analyzeTokens(toks2)
  1222  	// if both literal just string compare.
  1223  	l1, l2 := !(pwc1 || fwc1), !(pwc2 || fwc2)
  1224  	if l1 && l2 {
  1225  		return subj1 == subj2
  1226  	}
  1227  	// So one or both have wildcards. If one is literal than we can do subset matching.
  1228  	if l1 && !l2 {
  1229  		return isSubsetMatch(toks1, subj2)
  1230  	} else if l2 && !l1 {
  1231  		return isSubsetMatch(toks2, subj1)
  1232  	}
  1233  	// Both have wildcards.
  1234  	// If they only have partials then the lengths must match.
  1235  	if !fwc1 && !fwc2 && len(toks1) != len(toks2) {
  1236  		return false
  1237  	}
  1238  	if lt1, lt2 := len(toks1), len(toks2); lt1 != lt2 {
  1239  		// If the shorter one only has partials then these will not collide.
  1240  		if lt1 < lt2 && !fwc1 || lt2 < lt1 && !fwc2 {
  1241  			return false
  1242  		}
  1243  	}
  1244  
  1245  	stop := len(toks1)
  1246  	if len(toks2) < stop {
  1247  		stop = len(toks2)
  1248  	}
  1249  
  1250  	// We look for reasons to say no.
  1251  	for i := 0; i < stop; i++ {
  1252  		t1, t2 := toks1[i], toks2[i]
  1253  		if !tokensCanMatch(t1, t2) {
  1254  			return false
  1255  		}
  1256  	}
  1257  
  1258  	return true
  1259  }
  1260  
  1261  // Returns number of tokens in the subject.
  1262  func numTokens(subject string) int {
  1263  	var numTokens int
  1264  	if len(subject) == 0 {
  1265  		return 0
  1266  	}
  1267  	for i := 0; i < len(subject); i++ {
  1268  		if subject[i] == btsep {
  1269  			numTokens++
  1270  		}
  1271  	}
  1272  	return numTokens + 1
  1273  }
  1274  
  1275  // Fast way to return an indexed token.
  1276  // This is one based, so first token is TokenAt(subject, 1)
  1277  func tokenAt(subject string, index uint8) string {
  1278  	ti, start := uint8(1), 0
  1279  	for i := 0; i < len(subject); i++ {
  1280  		if subject[i] == btsep {
  1281  			if ti == index {
  1282  				return subject[start:i]
  1283  			}
  1284  			start = i + 1
  1285  			ti++
  1286  		}
  1287  	}
  1288  	if ti == index {
  1289  		return subject[start:]
  1290  	}
  1291  	return _EMPTY_
  1292  }
  1293  
  1294  // use similar to append. meaning, the updated slice will be returned
  1295  func tokenizeSubjectIntoSlice(tts []string, subject string) []string {
  1296  	start := 0
  1297  	for i := 0; i < len(subject); i++ {
  1298  		if subject[i] == btsep {
  1299  			tts = append(tts, subject[start:i])
  1300  			start = i + 1
  1301  		}
  1302  	}
  1303  	tts = append(tts, subject[start:])
  1304  	return tts
  1305  }
  1306  
  1307  // Calls into the function isSubsetMatch()
  1308  func subjectIsSubsetMatch(subject, test string) bool {
  1309  	tsa := [32]string{}
  1310  	tts := tokenizeSubjectIntoSlice(tsa[:0], subject)
  1311  	return isSubsetMatch(tts, test)
  1312  }
  1313  
  1314  // This will test a subject as an array of tokens against a test subject
  1315  // Calls into the function isSubsetMatchTokenized
  1316  func isSubsetMatch(tokens []string, test string) bool {
  1317  	tsa := [32]string{}
  1318  	tts := tokenizeSubjectIntoSlice(tsa[:0], test)
  1319  	return isSubsetMatchTokenized(tokens, tts)
  1320  }
  1321  
  1322  // This will test a subject as an array of tokens against a test subject (also encoded as array of tokens)
  1323  // and determine if the tokens are matched. Both test subject and tokens
  1324  // may contain wildcards. So foo.* is a subset match of [">", "*.*", "foo.*"],
  1325  // but not of foo.bar, etc.
  1326  func isSubsetMatchTokenized(tokens, test []string) bool {
  1327  	// Walk the target tokens
  1328  	for i, t2 := range test {
  1329  		if i >= len(tokens) {
  1330  			return false
  1331  		}
  1332  		l := len(t2)
  1333  		if l == 0 {
  1334  			return false
  1335  		}
  1336  		if t2[0] == fwc && l == 1 {
  1337  			return true
  1338  		}
  1339  		t1 := tokens[i]
  1340  
  1341  		l = len(t1)
  1342  		if l == 0 || t1[0] == fwc && l == 1 {
  1343  			return false
  1344  		}
  1345  
  1346  		if t1[0] == pwc && len(t1) == 1 {
  1347  			m := t2[0] == pwc && len(t2) == 1
  1348  			if !m {
  1349  				return false
  1350  			}
  1351  			if i >= len(test) {
  1352  				return true
  1353  			}
  1354  			continue
  1355  		}
  1356  		if t2[0] != pwc && strings.Compare(t1, t2) != 0 {
  1357  			return false
  1358  		}
  1359  	}
  1360  	return len(tokens) == len(test)
  1361  }
  1362  
  1363  // matchLiteral is used to test literal subjects, those that do not have any
  1364  // wildcards, with a target subject. This is used in the cache layer.
  1365  func matchLiteral(literal, subject string) bool {
  1366  	li := 0
  1367  	ll := len(literal)
  1368  	ls := len(subject)
  1369  	for i := 0; i < ls; i++ {
  1370  		if li >= ll {
  1371  			return false
  1372  		}
  1373  		// This function has been optimized for speed.
  1374  		// For instance, do not set b:=subject[i] here since
  1375  		// we may bump `i` in this loop to avoid `continue` or
  1376  		// skipping common test in a particular test.
  1377  		// Run Benchmark_SublistMatchLiteral before making any change.
  1378  		switch subject[i] {
  1379  		case pwc:
  1380  			// NOTE: This is not testing validity of a subject, instead ensures
  1381  			// that wildcards are treated as such if they follow some basic rules,
  1382  			// namely that they are a token on their own.
  1383  			if i == 0 || subject[i-1] == btsep {
  1384  				if i == ls-1 {
  1385  					// There is no more token in the subject after this wildcard.
  1386  					// Skip token in literal and expect to not find a separator.
  1387  					for {
  1388  						// End of literal, this is a match.
  1389  						if li >= ll {
  1390  							return true
  1391  						}
  1392  						// Presence of separator, this can't be a match.
  1393  						if literal[li] == btsep {
  1394  							return false
  1395  						}
  1396  						li++
  1397  					}
  1398  				} else if subject[i+1] == btsep {
  1399  					// There is another token in the subject after this wildcard.
  1400  					// Skip token in literal and expect to get a separator.
  1401  					for {
  1402  						// We found the end of the literal before finding a separator,
  1403  						// this can't be a match.
  1404  						if li >= ll {
  1405  							return false
  1406  						}
  1407  						if literal[li] == btsep {
  1408  							break
  1409  						}
  1410  						li++
  1411  					}
  1412  					// Bump `i` since we know there is a `.` following, we are
  1413  					// safe. The common test below is going to check `.` with `.`
  1414  					// which is good. A `continue` here is too costly.
  1415  					i++
  1416  				}
  1417  			}
  1418  		case fwc:
  1419  			// For `>` to be a wildcard, it means being the only or last character
  1420  			// in the string preceded by a `.`
  1421  			if (i == 0 || subject[i-1] == btsep) && i == ls-1 {
  1422  				return true
  1423  			}
  1424  		}
  1425  		if subject[i] != literal[li] {
  1426  			return false
  1427  		}
  1428  		li++
  1429  	}
  1430  	// Make sure we have processed all of the literal's chars..
  1431  	return li >= ll
  1432  }
  1433  
  1434  func addLocalSub(sub *subscription, subs *[]*subscription, includeLeafHubs bool) {
  1435  	if sub != nil && sub.client != nil {
  1436  		kind := sub.client.kind
  1437  		if kind == CLIENT || kind == SYSTEM || kind == JETSTREAM || kind == ACCOUNT ||
  1438  			(includeLeafHubs && sub.client.isHubLeafNode() /* implied kind==LEAF */) {
  1439  			*subs = append(*subs, sub)
  1440  		}
  1441  	}
  1442  }
  1443  
  1444  func (s *Sublist) addNodeToSubs(n *node, subs *[]*subscription, includeLeafHubs bool) {
  1445  	// Normal subscriptions
  1446  	if n.plist != nil {
  1447  		for _, sub := range n.plist {
  1448  			addLocalSub(sub, subs, includeLeafHubs)
  1449  		}
  1450  	} else {
  1451  		for sub := range n.psubs {
  1452  			addLocalSub(sub, subs, includeLeafHubs)
  1453  		}
  1454  	}
  1455  	// Queue subscriptions
  1456  	for _, qr := range n.qsubs {
  1457  		for sub := range qr {
  1458  			addLocalSub(sub, subs, includeLeafHubs)
  1459  		}
  1460  	}
  1461  }
  1462  
  1463  func (s *Sublist) collectLocalSubs(l *level, subs *[]*subscription, includeLeafHubs bool) {
  1464  	for _, n := range l.nodes {
  1465  		s.addNodeToSubs(n, subs, includeLeafHubs)
  1466  		s.collectLocalSubs(n.next, subs, includeLeafHubs)
  1467  	}
  1468  	if l.pwc != nil {
  1469  		s.addNodeToSubs(l.pwc, subs, includeLeafHubs)
  1470  		s.collectLocalSubs(l.pwc.next, subs, includeLeafHubs)
  1471  	}
  1472  	if l.fwc != nil {
  1473  		s.addNodeToSubs(l.fwc, subs, includeLeafHubs)
  1474  		s.collectLocalSubs(l.fwc.next, subs, includeLeafHubs)
  1475  	}
  1476  }
  1477  
  1478  // Return all local client subscriptions. Use the supplied slice.
  1479  func (s *Sublist) localSubs(subs *[]*subscription, includeLeafHubs bool) {
  1480  	s.RLock()
  1481  	s.collectLocalSubs(s.root, subs, includeLeafHubs)
  1482  	s.RUnlock()
  1483  }
  1484  
  1485  // All is used to collect all subscriptions.
  1486  func (s *Sublist) All(subs *[]*subscription) {
  1487  	s.RLock()
  1488  	s.collectAllSubs(s.root, subs)
  1489  	s.RUnlock()
  1490  }
  1491  
  1492  func (s *Sublist) addAllNodeToSubs(n *node, subs *[]*subscription) {
  1493  	// Normal subscriptions
  1494  	if n.plist != nil {
  1495  		*subs = append(*subs, n.plist...)
  1496  	} else {
  1497  		for sub := range n.psubs {
  1498  			*subs = append(*subs, sub)
  1499  		}
  1500  	}
  1501  	// Queue subscriptions
  1502  	for _, qr := range n.qsubs {
  1503  		for sub := range qr {
  1504  			*subs = append(*subs, sub)
  1505  		}
  1506  	}
  1507  }
  1508  
  1509  func (s *Sublist) collectAllSubs(l *level, subs *[]*subscription) {
  1510  	for _, n := range l.nodes {
  1511  		s.addAllNodeToSubs(n, subs)
  1512  		s.collectAllSubs(n.next, subs)
  1513  	}
  1514  	if l.pwc != nil {
  1515  		s.addAllNodeToSubs(l.pwc, subs)
  1516  		s.collectAllSubs(l.pwc.next, subs)
  1517  	}
  1518  	if l.fwc != nil {
  1519  		s.addAllNodeToSubs(l.fwc, subs)
  1520  		s.collectAllSubs(l.fwc.next, subs)
  1521  	}
  1522  }
  1523  
  1524  // For a given subject (which may contain wildcards), this call returns all
  1525  // subscriptions that would match that subject. For instance, suppose that
  1526  // the sublist contains: foo.bar, foo.bar.baz and foo.baz, ReverseMatch("foo.*")
  1527  // would return foo.bar and foo.baz.
  1528  // This is used in situations where the sublist is likely to contain only
  1529  // literals and one wants to get all the subjects that would have been a match
  1530  // to a subscription on `subject`.
  1531  func (s *Sublist) ReverseMatch(subject string) *SublistResult {
  1532  	tsa := [32]string{}
  1533  	tokens := tsa[:0]
  1534  	start := 0
  1535  	for i := 0; i < len(subject); i++ {
  1536  		if subject[i] == btsep {
  1537  			tokens = append(tokens, subject[start:i])
  1538  			start = i + 1
  1539  		}
  1540  	}
  1541  	tokens = append(tokens, subject[start:])
  1542  
  1543  	result := &SublistResult{}
  1544  
  1545  	s.RLock()
  1546  	reverseMatchLevel(s.root, tokens, nil, result)
  1547  	// Check for empty result.
  1548  	if len(result.psubs) == 0 && len(result.qsubs) == 0 {
  1549  		result = emptyResult
  1550  	}
  1551  	s.RUnlock()
  1552  
  1553  	return result
  1554  }
  1555  
  1556  func reverseMatchLevel(l *level, toks []string, n *node, results *SublistResult) {
  1557  	if l == nil {
  1558  		return
  1559  	}
  1560  	for i, t := range toks {
  1561  		if len(t) == 1 {
  1562  			if t[0] == fwc {
  1563  				getAllNodes(l, results)
  1564  				return
  1565  			} else if t[0] == pwc {
  1566  				for _, n := range l.nodes {
  1567  					reverseMatchLevel(n.next, toks[i+1:], n, results)
  1568  				}
  1569  				if l.pwc != nil {
  1570  					reverseMatchLevel(l.pwc.next, toks[i+1:], n, results)
  1571  				}
  1572  				if l.fwc != nil {
  1573  					getAllNodes(l, results)
  1574  				}
  1575  				return
  1576  			}
  1577  		}
  1578  		// If the sub tree has a fwc at this position, match as well.
  1579  		if l.fwc != nil {
  1580  			getAllNodes(l, results)
  1581  			return
  1582  		} else if l.pwc != nil {
  1583  			reverseMatchLevel(l.pwc.next, toks[i+1:], n, results)
  1584  		}
  1585  		n = l.nodes[t]
  1586  		if n == nil {
  1587  			break
  1588  		}
  1589  		l = n.next
  1590  	}
  1591  	if n != nil {
  1592  		addNodeToResults(n, results)
  1593  	}
  1594  }
  1595  
  1596  func getAllNodes(l *level, results *SublistResult) {
  1597  	if l == nil {
  1598  		return
  1599  	}
  1600  	if l.pwc != nil {
  1601  		addNodeToResults(l.pwc, results)
  1602  	}
  1603  	if l.fwc != nil {
  1604  		addNodeToResults(l.fwc, results)
  1605  	}
  1606  	for _, n := range l.nodes {
  1607  		addNodeToResults(n, results)
  1608  		getAllNodes(n.next, results)
  1609  	}
  1610  }