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 }