github.com/nsqio/nsq@v1.3.0/nsqlookupd/registration_db.go (about)

     1  package nsqlookupd
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"sync/atomic"
     7  	"time"
     8  )
     9  
    10  type RegistrationDB struct {
    11  	sync.RWMutex
    12  	registrationMap map[Registration]ProducerMap
    13  }
    14  
    15  type Registration struct {
    16  	Category string
    17  	Key      string
    18  	SubKey   string
    19  }
    20  type Registrations []Registration
    21  
    22  type PeerInfo struct {
    23  	lastUpdate       int64
    24  	id               string
    25  	RemoteAddress    string `json:"remote_address"`
    26  	Hostname         string `json:"hostname"`
    27  	BroadcastAddress string `json:"broadcast_address"`
    28  	TCPPort          int    `json:"tcp_port"`
    29  	HTTPPort         int    `json:"http_port"`
    30  	Version          string `json:"version"`
    31  }
    32  
    33  type Producer struct {
    34  	peerInfo     *PeerInfo
    35  	tombstoned   bool
    36  	tombstonedAt time.Time
    37  }
    38  
    39  type Producers []*Producer
    40  type ProducerMap map[string]*Producer
    41  
    42  func (p *Producer) String() string {
    43  	return fmt.Sprintf("%s [%d, %d]", p.peerInfo.BroadcastAddress, p.peerInfo.TCPPort, p.peerInfo.HTTPPort)
    44  }
    45  
    46  func (p *Producer) Tombstone() {
    47  	p.tombstoned = true
    48  	p.tombstonedAt = time.Now()
    49  }
    50  
    51  func (p *Producer) IsTombstoned(lifetime time.Duration) bool {
    52  	return p.tombstoned && time.Since(p.tombstonedAt) < lifetime
    53  }
    54  
    55  func NewRegistrationDB() *RegistrationDB {
    56  	return &RegistrationDB{
    57  		registrationMap: make(map[Registration]ProducerMap),
    58  	}
    59  }
    60  
    61  // add a registration key
    62  func (r *RegistrationDB) AddRegistration(k Registration) {
    63  	r.Lock()
    64  	defer r.Unlock()
    65  	_, ok := r.registrationMap[k]
    66  	if !ok {
    67  		r.registrationMap[k] = make(map[string]*Producer)
    68  	}
    69  }
    70  
    71  // add a producer to a registration
    72  func (r *RegistrationDB) AddProducer(k Registration, p *Producer) bool {
    73  	r.Lock()
    74  	defer r.Unlock()
    75  	_, ok := r.registrationMap[k]
    76  	if !ok {
    77  		r.registrationMap[k] = make(map[string]*Producer)
    78  	}
    79  	producers := r.registrationMap[k]
    80  	_, found := producers[p.peerInfo.id]
    81  	if !found {
    82  		producers[p.peerInfo.id] = p
    83  	}
    84  	return !found
    85  }
    86  
    87  // remove a producer from a registration
    88  func (r *RegistrationDB) RemoveProducer(k Registration, id string) (bool, int) {
    89  	r.Lock()
    90  	defer r.Unlock()
    91  	producers, ok := r.registrationMap[k]
    92  	if !ok {
    93  		return false, 0
    94  	}
    95  	removed := false
    96  	if _, exists := producers[id]; exists {
    97  		removed = true
    98  	}
    99  
   100  	// Note: this leaves keys in the DB even if they have empty lists
   101  	delete(producers, id)
   102  	return removed, len(producers)
   103  }
   104  
   105  // remove a Registration and all it's producers
   106  func (r *RegistrationDB) RemoveRegistration(k Registration) {
   107  	r.Lock()
   108  	defer r.Unlock()
   109  	delete(r.registrationMap, k)
   110  }
   111  
   112  func (r *RegistrationDB) needFilter(key string, subkey string) bool {
   113  	return key == "*" || subkey == "*"
   114  }
   115  
   116  func (r *RegistrationDB) FindRegistrations(category string, key string, subkey string) Registrations {
   117  	r.RLock()
   118  	defer r.RUnlock()
   119  	if !r.needFilter(key, subkey) {
   120  		k := Registration{category, key, subkey}
   121  		if _, ok := r.registrationMap[k]; ok {
   122  			return Registrations{k}
   123  		}
   124  		return Registrations{}
   125  	}
   126  	results := Registrations{}
   127  	for k := range r.registrationMap {
   128  		if !k.IsMatch(category, key, subkey) {
   129  			continue
   130  		}
   131  		results = append(results, k)
   132  	}
   133  	return results
   134  }
   135  
   136  func (r *RegistrationDB) FindProducers(category string, key string, subkey string) Producers {
   137  	r.RLock()
   138  	defer r.RUnlock()
   139  	if !r.needFilter(key, subkey) {
   140  		k := Registration{category, key, subkey}
   141  		return ProducerMap2Slice(r.registrationMap[k])
   142  	}
   143  
   144  	results := make(map[string]struct{})
   145  	var retProducers Producers
   146  	for k, producers := range r.registrationMap {
   147  		if !k.IsMatch(category, key, subkey) {
   148  			continue
   149  		}
   150  		for _, producer := range producers {
   151  			_, found := results[producer.peerInfo.id]
   152  			if !found {
   153  				results[producer.peerInfo.id] = struct{}{}
   154  				retProducers = append(retProducers, producer)
   155  			}
   156  		}
   157  	}
   158  	return retProducers
   159  }
   160  
   161  func (r *RegistrationDB) LookupRegistrations(id string) Registrations {
   162  	r.RLock()
   163  	defer r.RUnlock()
   164  	results := Registrations{}
   165  	for k, producers := range r.registrationMap {
   166  		if _, exists := producers[id]; exists {
   167  			results = append(results, k)
   168  		}
   169  	}
   170  	return results
   171  }
   172  
   173  func (k Registration) IsMatch(category string, key string, subkey string) bool {
   174  	if category != k.Category {
   175  		return false
   176  	}
   177  	if key != "*" && k.Key != key {
   178  		return false
   179  	}
   180  	if subkey != "*" && k.SubKey != subkey {
   181  		return false
   182  	}
   183  	return true
   184  }
   185  
   186  func (rr Registrations) Filter(category string, key string, subkey string) Registrations {
   187  	output := Registrations{}
   188  	for _, k := range rr {
   189  		if k.IsMatch(category, key, subkey) {
   190  			output = append(output, k)
   191  		}
   192  	}
   193  	return output
   194  }
   195  
   196  func (rr Registrations) Keys() []string {
   197  	keys := make([]string, len(rr))
   198  	for i, k := range rr {
   199  		keys[i] = k.Key
   200  	}
   201  	return keys
   202  }
   203  
   204  func (rr Registrations) SubKeys() []string {
   205  	subkeys := make([]string, len(rr))
   206  	for i, k := range rr {
   207  		subkeys[i] = k.SubKey
   208  	}
   209  	return subkeys
   210  }
   211  
   212  func (pp Producers) FilterByActive(inactivityTimeout time.Duration, tombstoneLifetime time.Duration) Producers {
   213  	now := time.Now()
   214  	results := Producers{}
   215  	for _, p := range pp {
   216  		cur := time.Unix(0, atomic.LoadInt64(&p.peerInfo.lastUpdate))
   217  		if now.Sub(cur) > inactivityTimeout || p.IsTombstoned(tombstoneLifetime) {
   218  			continue
   219  		}
   220  		results = append(results, p)
   221  	}
   222  	return results
   223  }
   224  
   225  func (pp Producers) PeerInfo() []*PeerInfo {
   226  	results := []*PeerInfo{}
   227  	for _, p := range pp {
   228  		results = append(results, p.peerInfo)
   229  	}
   230  	return results
   231  }
   232  
   233  func ProducerMap2Slice(pm ProducerMap) Producers {
   234  	var producers Producers
   235  	for _, producer := range pm {
   236  		producers = append(producers, producer)
   237  	}
   238  
   239  	return producers
   240  }