github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/router/registry/table.go (about)

     1  // Licensed under the Apache License, Version 2.0 (the "License");
     2  // you may not use this file except in compliance with the License.
     3  // You may obtain a copy of the License at
     4  //
     5  //     https://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS,
     9  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    10  // See the License for the specific language governing permissions and
    11  // limitations under the License.
    12  //
    13  // Original source: github.com/tickoalcantara12/micro/v3/router/registry/table.go
    14  
    15  package registry
    16  
    17  import (
    18  	"sync"
    19  	"time"
    20  
    21  	"github.com/google/uuid"
    22  	"github.com/tickoalcantara12/micro/v3/service/logger"
    23  	"github.com/tickoalcantara12/micro/v3/service/router"
    24  )
    25  
    26  // table is an in-memory routing table
    27  type table struct {
    28  	sync.RWMutex
    29  	// routes stores service routes
    30  	routes map[string]map[uint64]*route
    31  	// watchers stores table watchers
    32  	watchers map[string]*tableWatcher
    33  }
    34  
    35  type route struct {
    36  	route   router.Route
    37  	updated time.Time
    38  }
    39  
    40  // newtable creates a new routing table and returns it
    41  func newTable() *table {
    42  	return &table{
    43  		routes:   make(map[string]map[uint64]*route),
    44  		watchers: make(map[string]*tableWatcher),
    45  	}
    46  }
    47  
    48  // pruneRoutes will prune routes older than the time specified
    49  func (t *table) pruneRoutes(olderThan time.Duration) {
    50  	var routes []router.Route
    51  
    52  	t.Lock()
    53  
    54  	// search for all the routes
    55  	for _, routeList := range t.routes {
    56  		for _, r := range routeList {
    57  			// if any route is older than
    58  			if time.Since(r.updated).Seconds() > olderThan.Seconds() {
    59  				routes = append(routes, r.route)
    60  			}
    61  		}
    62  	}
    63  
    64  	t.Unlock()
    65  
    66  	// delete the routes we've found
    67  	for _, route := range routes {
    68  		t.Delete(route)
    69  	}
    70  }
    71  
    72  // deleteService removes the entire service
    73  func (t *table) deleteService(service, network string) {
    74  	t.Lock()
    75  	defer t.Unlock()
    76  
    77  	routes, ok := t.routes[service]
    78  	if !ok {
    79  		return
    80  	}
    81  
    82  	// delete the routes for the service
    83  	for hash, rt := range routes {
    84  		// TODO: check if this causes a problem
    85  		// with * in the network if that is a thing
    86  		// or blank strings
    87  		if rt.route.Network != network {
    88  			continue
    89  		}
    90  		delete(routes, hash)
    91  	}
    92  
    93  	// delete the map for the service if its empty
    94  	if len(routes) == 0 {
    95  		delete(t.routes, service)
    96  		return
    97  	}
    98  
    99  	// save the routes
   100  	t.routes[service] = routes
   101  }
   102  
   103  // sendEvent sends events to all subscribed watchers
   104  func (t *table) sendEvent(e *router.Event) {
   105  	t.RLock()
   106  	defer t.RUnlock()
   107  
   108  	if len(e.Id) == 0 {
   109  		e.Id = uuid.New().String()
   110  	}
   111  
   112  	for _, w := range t.watchers {
   113  		select {
   114  		case w.resChan <- e:
   115  		case <-w.done:
   116  		// don't block forever
   117  		case <-time.After(time.Second):
   118  		}
   119  	}
   120  }
   121  
   122  // Create creates new route in the routing table
   123  func (t *table) Create(r router.Route) error {
   124  	service := r.Service
   125  	sum := r.Hash()
   126  
   127  	t.Lock()
   128  	defer t.Unlock()
   129  
   130  	// check if there are any routes in the table for the route destination
   131  	if _, ok := t.routes[service]; !ok {
   132  		t.routes[service] = make(map[uint64]*route)
   133  	}
   134  
   135  	// add new route to the table for the route destination
   136  	if _, ok := t.routes[service][sum]; ok {
   137  		return router.ErrDuplicateRoute
   138  	}
   139  
   140  	// create the route
   141  	t.routes[service][sum] = &route{r, time.Now()}
   142  
   143  	if logger.V(logger.DebugLevel, logger.DefaultLogger) {
   144  		logger.Debugf("Router emitting %s for route: %s", router.Create, r.Address)
   145  	}
   146  
   147  	// send a route created event
   148  	go t.sendEvent(&router.Event{Type: router.Create, Timestamp: time.Now(), Route: r})
   149  
   150  	return nil
   151  }
   152  
   153  // Delete deletes the route from the routing table
   154  func (t *table) Delete(r router.Route) error {
   155  	service := r.Service
   156  	sum := r.Hash()
   157  
   158  	t.Lock()
   159  	defer t.Unlock()
   160  
   161  	if _, ok := t.routes[service]; !ok {
   162  		return router.ErrRouteNotFound
   163  	}
   164  
   165  	if _, ok := t.routes[service][sum]; !ok {
   166  		return router.ErrRouteNotFound
   167  	}
   168  
   169  	// delete the route from the service
   170  	delete(t.routes[service], sum)
   171  
   172  	// delete the whole map if there are no routes left
   173  	if len(t.routes[service]) == 0 {
   174  		delete(t.routes, service)
   175  	}
   176  
   177  	if logger.V(logger.DebugLevel, logger.DefaultLogger) {
   178  		logger.Debugf("Router emitting %s for route: %s", router.Delete, r.Address)
   179  	}
   180  	go t.sendEvent(&router.Event{Type: router.Delete, Timestamp: time.Now(), Route: r})
   181  
   182  	return nil
   183  }
   184  
   185  // Update updates routing table with the new route
   186  func (t *table) Update(r router.Route) error {
   187  	service := r.Service
   188  	sum := r.Hash()
   189  
   190  	t.Lock()
   191  	defer t.Unlock()
   192  
   193  	// check if the route destination has any routes in the table
   194  	if _, ok := t.routes[service]; !ok {
   195  		t.routes[service] = make(map[uint64]*route)
   196  	}
   197  
   198  	if _, ok := t.routes[service][sum]; !ok {
   199  		// update the route
   200  		t.routes[service][sum] = &route{r, time.Now()}
   201  
   202  		if logger.V(logger.DebugLevel, logger.DefaultLogger) {
   203  			logger.Debugf("Router emitting %s for route: %s", router.Update, r.Address)
   204  		}
   205  		go t.sendEvent(&router.Event{Type: router.Update, Timestamp: time.Now(), Route: r})
   206  		return nil
   207  	}
   208  
   209  	// just update the route, but dont emit Update event
   210  	t.routes[service][sum] = &route{r, time.Now()}
   211  
   212  	return nil
   213  }
   214  
   215  // Read entries from the table
   216  func (t *table) Read(opts ...router.ReadOption) ([]router.Route, error) {
   217  	var options router.ReadOptions
   218  	for _, o := range opts {
   219  		o(&options)
   220  	}
   221  
   222  	t.RLock()
   223  	defer t.RUnlock()
   224  
   225  	var routes []router.Route
   226  
   227  	// get the routes based on options passed
   228  	if len(options.Service) > 0 {
   229  		routeMap, ok := t.routes[options.Service]
   230  		if !ok {
   231  			return nil, router.ErrRouteNotFound
   232  		}
   233  		for _, rt := range routeMap {
   234  			routes = append(routes, rt.route)
   235  		}
   236  		return routes, nil
   237  	}
   238  
   239  	// otherwise get all routes
   240  	for _, serviceRoutes := range t.routes {
   241  		for _, rt := range serviceRoutes {
   242  			routes = append(routes, rt.route)
   243  		}
   244  	}
   245  
   246  	return routes, nil
   247  }
   248  
   249  // Watch returns routing table entry watcher
   250  func (t *table) Watch(opts ...router.WatchOption) (router.Watcher, error) {
   251  	// by default watch everything
   252  	wopts := router.WatchOptions{
   253  		Service: "*",
   254  	}
   255  
   256  	for _, o := range opts {
   257  		o(&wopts)
   258  	}
   259  
   260  	w := &tableWatcher{
   261  		id:      uuid.New().String(),
   262  		opts:    wopts,
   263  		resChan: make(chan *router.Event, 10),
   264  		done:    make(chan struct{}),
   265  	}
   266  
   267  	// when the watcher is stopped delete it
   268  	go func() {
   269  		<-w.done
   270  		t.Lock()
   271  		delete(t.watchers, w.id)
   272  		t.Unlock()
   273  	}()
   274  
   275  	// save the watcher
   276  	t.Lock()
   277  	t.watchers[w.id] = w
   278  	t.Unlock()
   279  
   280  	return w, nil
   281  }