Merge pull request #352 from micro/rwmutex
move to using rwmutex for selector
This commit is contained in:
		
							
								
								
									
										78
									
								
								selector/cache/cache.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										78
									
								
								selector/cache/cache.go
									
									
									
									
										vendored
									
									
								
							| @@ -15,7 +15,7 @@ type cacheSelector struct { | |||||||
| 	ttl time.Duration | 	ttl time.Duration | ||||||
|  |  | ||||||
| 	// registry cache | 	// registry cache | ||||||
| 	sync.Mutex | 	sync.RWMutex | ||||||
| 	cache map[string][]*registry.Service | 	cache map[string][]*registry.Service | ||||||
| 	ttls  map[string]time.Time | 	ttls  map[string]time.Time | ||||||
|  |  | ||||||
| @@ -81,17 +81,25 @@ func (c *cacheSelector) del(service string) { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (c *cacheSelector) get(service string) ([]*registry.Service, error) { | func (c *cacheSelector) get(service string) ([]*registry.Service, error) { | ||||||
| 	c.Lock() | 	// read lock | ||||||
| 	defer c.Unlock() | 	c.RLock() | ||||||
|  |  | ||||||
| 	// watch service if not watched | 	// check the cache first | ||||||
| 	if _, ok := c.watched[service]; !ok { | 	services, ok := c.cache[service] | ||||||
| 		go c.run(service) | 	// get cache ttl | ||||||
| 		c.watched[service] = true | 	ttl, kk := c.ttls[service] | ||||||
|  |  | ||||||
|  | 	// got services && within ttl so return cache | ||||||
|  | 	if ok && kk && time.Since(ttl) < c.ttl { | ||||||
|  | 		// make a copy | ||||||
|  | 		cp := c.cp(services) | ||||||
|  | 		// unlock the read | ||||||
|  | 		c.RUnlock() | ||||||
|  | 		// return servics | ||||||
|  | 		return cp, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// get does the actual request for a service | 	// get does the actual request for a service and cache it | ||||||
| 	// it also caches it |  | ||||||
| 	get := func(service string) ([]*registry.Service, error) { | 	get := func(service string) ([]*registry.Service, error) { | ||||||
| 		// ask the registry | 		// ask the registry | ||||||
| 		services, err := c.so.Registry.GetService(service) | 		services, err := c.so.Registry.GetService(service) | ||||||
| @@ -100,43 +108,23 @@ func (c *cacheSelector) get(service string) ([]*registry.Service, error) { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// cache results | 		// cache results | ||||||
|  | 		c.Lock() | ||||||
| 		c.set(service, c.cp(services)) | 		c.set(service, c.cp(services)) | ||||||
|  | 		c.Unlock() | ||||||
|  |  | ||||||
| 		return services, nil | 		return services, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// check the cache first | 	// watch service if not watched | ||||||
| 	services, ok := c.cache[service] | 	if _, ok := c.watched[service]; !ok { | ||||||
|  | 		go c.run(service) | ||||||
| 	// cache miss or no services |  | ||||||
| 	if !ok || len(services) == 0 { |  | ||||||
| 		return get(service) |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// got cache but lets check ttl | 	// unlock the read lock | ||||||
| 	ttl, kk := c.ttls[service] | 	c.RUnlock() | ||||||
|  |  | ||||||
| 	// within ttl so return cache | 	// get and return services | ||||||
| 	if kk && time.Since(ttl) < c.ttl { | 	return get(service) | ||||||
| 		return c.cp(services), nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// expired entry so get service |  | ||||||
| 	services, err := get(service) |  | ||||||
|  |  | ||||||
| 	// no error then return error |  | ||||||
| 	if err == nil { |  | ||||||
| 		return services, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// not found error then return |  | ||||||
| 	if err == registry.ErrNotFound { |  | ||||||
| 		return nil, selector.ErrNotFound |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// other error |  | ||||||
|  |  | ||||||
| 	// return expired cache as last resort |  | ||||||
| 	return c.cp(services), nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| func (c *cacheSelector) set(service string, services []*registry.Service) { | func (c *cacheSelector) set(service string, services []*registry.Service) { | ||||||
| @@ -257,6 +245,18 @@ func (c *cacheSelector) update(res *registry.Result) { | |||||||
| // reloads the watcher if Init is called | // reloads the watcher if Init is called | ||||||
| // and returns when Close is called | // and returns when Close is called | ||||||
| func (c *cacheSelector) run(name string) { | func (c *cacheSelector) run(name string) { | ||||||
|  | 	// set watcher | ||||||
|  | 	c.Lock() | ||||||
|  | 	c.watched[name] = true | ||||||
|  | 	c.Unlock() | ||||||
|  |  | ||||||
|  | 	// delete watcher on exit | ||||||
|  | 	defer func() { | ||||||
|  | 		c.Lock() | ||||||
|  | 		delete(c.watched, name) | ||||||
|  | 		c.Unlock() | ||||||
|  | 	}() | ||||||
|  |  | ||||||
| 	for { | 	for { | ||||||
| 		// exit early if already dead | 		// exit early if already dead | ||||||
| 		if c.quit() { | 		if c.quit() { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user