gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/router/table.go (about)

     1  package router
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/google/uuid"
     9  	"gitee.com/liuxuezhan/go-micro-v1.18.0/util/log"
    10  )
    11  
    12  var (
    13  	// ErrRouteNotFound is returned when no route was found in the routing table
    14  	ErrRouteNotFound = errors.New("route not found")
    15  	// ErrDuplicateRoute is returned when the route already exists
    16  	ErrDuplicateRoute = errors.New("duplicate route")
    17  )
    18  
    19  // table is an in-memory routing table
    20  type table struct {
    21  	sync.RWMutex
    22  	// routes stores service routes
    23  	routes map[string]map[uint64]Route
    24  	// watchers stores table watchers
    25  	watchers map[string]*tableWatcher
    26  }
    27  
    28  // newtable creates a new routing table and returns it
    29  func newTable(opts ...Option) *table {
    30  	return &table{
    31  		routes:   make(map[string]map[uint64]Route),
    32  		watchers: make(map[string]*tableWatcher),
    33  	}
    34  }
    35  
    36  // sendEvent sends events to all subscribed watchers
    37  func (t *table) sendEvent(e *Event) {
    38  	t.RLock()
    39  	defer t.RUnlock()
    40  
    41  	for _, w := range t.watchers {
    42  		select {
    43  		case w.resChan <- e:
    44  		case <-w.done:
    45  		}
    46  	}
    47  }
    48  
    49  // Create creates new route in the routing table
    50  func (t *table) Create(r Route) error {
    51  	service := r.Service
    52  	sum := r.Hash()
    53  
    54  	t.Lock()
    55  	defer t.Unlock()
    56  
    57  	// check if there are any routes in the table for the route destination
    58  	if _, ok := t.routes[service]; !ok {
    59  		t.routes[service] = make(map[uint64]Route)
    60  	}
    61  
    62  	// add new route to the table for the route destination
    63  	if _, ok := t.routes[service][sum]; !ok {
    64  		t.routes[service][sum] = r
    65  		log.Debugf("Router emitting %s for route: %s", Create, r.Address)
    66  		go t.sendEvent(&Event{Type: Create, Timestamp: time.Now(), Route: r})
    67  		return nil
    68  	}
    69  
    70  	return ErrDuplicateRoute
    71  }
    72  
    73  // Delete deletes the route from the routing table
    74  func (t *table) Delete(r Route) error {
    75  	service := r.Service
    76  	sum := r.Hash()
    77  
    78  	t.Lock()
    79  	defer t.Unlock()
    80  
    81  	if _, ok := t.routes[service]; !ok {
    82  		return ErrRouteNotFound
    83  	}
    84  
    85  	if _, ok := t.routes[service][sum]; !ok {
    86  		return ErrRouteNotFound
    87  	}
    88  
    89  	delete(t.routes[service], sum)
    90  	log.Debugf("Router emitting %s for route: %s", Delete, r.Address)
    91  	go t.sendEvent(&Event{Type: Delete, Timestamp: time.Now(), Route: r})
    92  
    93  	return nil
    94  }
    95  
    96  // Update updates routing table with the new route
    97  func (t *table) Update(r Route) error {
    98  	service := r.Service
    99  	sum := r.Hash()
   100  
   101  	t.Lock()
   102  	defer t.Unlock()
   103  
   104  	// check if the route destination has any routes in the table
   105  	if _, ok := t.routes[service]; !ok {
   106  		t.routes[service] = make(map[uint64]Route)
   107  	}
   108  
   109  	if _, ok := t.routes[service][sum]; !ok {
   110  		t.routes[service][sum] = r
   111  		log.Debugf("Router emitting %s for route: %s", Update, r.Address)
   112  		go t.sendEvent(&Event{Type: Update, Timestamp: time.Now(), Route: r})
   113  		return nil
   114  	}
   115  
   116  	// just update the route, but dont emit Update event
   117  	t.routes[service][sum] = r
   118  
   119  	return nil
   120  }
   121  
   122  // List returns a list of all routes in the table
   123  func (t *table) List() ([]Route, error) {
   124  	t.RLock()
   125  	defer t.RUnlock()
   126  
   127  	var routes []Route
   128  	for _, rmap := range t.routes {
   129  		for _, route := range rmap {
   130  			routes = append(routes, route)
   131  		}
   132  	}
   133  
   134  	return routes, nil
   135  }
   136  
   137  // isMatch checks if the route matches given query options
   138  func isMatch(route Route, address, gateway, network, router string) bool {
   139  	// matches the values provided
   140  	match := func(a, b string) bool {
   141  		if a == "*" || a == b {
   142  			return true
   143  		}
   144  		return false
   145  	}
   146  
   147  	// a simple struct to hold our values
   148  	type compare struct {
   149  		a string
   150  		b string
   151  	}
   152  
   153  	// compare the following values
   154  	values := []compare{
   155  		{gateway, route.Gateway},
   156  		{network, route.Network},
   157  		{router, route.Router},
   158  		{address, route.Address},
   159  	}
   160  
   161  	for _, v := range values {
   162  		// attempt to match each value
   163  		if !match(v.a, v.b) {
   164  			return false
   165  		}
   166  	}
   167  
   168  	return true
   169  }
   170  
   171  // findRoutes finds all the routes for given network and router and returns them
   172  func findRoutes(routes map[uint64]Route, address, gateway, network, router string) []Route {
   173  	var results []Route
   174  	for _, route := range routes {
   175  		if isMatch(route, address, gateway, network, router) {
   176  			results = append(results, route)
   177  		}
   178  	}
   179  	return results
   180  }
   181  
   182  // Lookup queries routing table and returns all routes that match the lookup query
   183  func (t *table) Query(q ...QueryOption) ([]Route, error) {
   184  	t.RLock()
   185  	defer t.RUnlock()
   186  
   187  	// create new query options
   188  	opts := NewQuery(q...)
   189  
   190  	if opts.Service != "*" {
   191  		if _, ok := t.routes[opts.Service]; !ok {
   192  			return nil, ErrRouteNotFound
   193  		}
   194  		return findRoutes(t.routes[opts.Service], opts.Address, opts.Gateway, opts.Network, opts.Router), nil
   195  	}
   196  
   197  	results := make([]Route, 0, len(t.routes))
   198  	// search through all destinations
   199  	for _, routes := range t.routes {
   200  		results = append(results, findRoutes(routes, opts.Address, opts.Gateway, opts.Network, opts.Router)...)
   201  	}
   202  
   203  	return results, nil
   204  }
   205  
   206  // Watch returns routing table entry watcher
   207  func (t *table) Watch(opts ...WatchOption) (Watcher, error) {
   208  	// by default watch everything
   209  	wopts := WatchOptions{
   210  		Service: "*",
   211  	}
   212  
   213  	for _, o := range opts {
   214  		o(&wopts)
   215  	}
   216  
   217  	w := &tableWatcher{
   218  		id:      uuid.New().String(),
   219  		opts:    wopts,
   220  		resChan: make(chan *Event, 10),
   221  		done:    make(chan struct{}),
   222  	}
   223  
   224  	// when the watcher is stopped delete it
   225  	go func() {
   226  		<-w.done
   227  		t.Lock()
   228  		delete(t.watchers, w.id)
   229  		t.Unlock()
   230  	}()
   231  
   232  	// save the watcher
   233  	t.Lock()
   234  	t.watchers[w.id] = w
   235  	t.Unlock()
   236  
   237  	return w, nil
   238  }