Skip to content

Commit f2efc68

Browse files
authored
Merge pull request #352 from micro/rwmutex
move to using rwmutex for selector
2 parents c2cc03a + 67d10e5 commit f2efc68

File tree

1 file changed

+38
-38
lines changed

1 file changed

+38
-38
lines changed

selector/cache/cache.go

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type cacheSelector struct {
1515
ttl time.Duration
1616

1717
// registry cache
18-
sync.Mutex
18+
sync.RWMutex
1919
cache map[string][]*registry.Service
2020
ttls map[string]time.Time
2121

@@ -81,17 +81,25 @@ func (c *cacheSelector) del(service string) {
8181
}
8282

8383
func (c *cacheSelector) get(service string) ([]*registry.Service, error) {
84-
c.Lock()
85-
defer c.Unlock()
84+
// read lock
85+
c.RLock()
8686

87-
// watch service if not watched
88-
if _, ok := c.watched[service]; !ok {
89-
go c.run(service)
90-
c.watched[service] = true
87+
// check the cache first
88+
services, ok := c.cache[service]
89+
// get cache ttl
90+
ttl, kk := c.ttls[service]
91+
92+
// got services && within ttl so return cache
93+
if ok && kk && time.Since(ttl) < c.ttl {
94+
// make a copy
95+
cp := c.cp(services)
96+
// unlock the read
97+
c.RUnlock()
98+
// return servics
99+
return cp, nil
91100
}
92101

93-
// get does the actual request for a service
94-
// it also caches it
102+
// get does the actual request for a service and cache it
95103
get := func(service string) ([]*registry.Service, error) {
96104
// ask the registry
97105
services, err := c.so.Registry.GetService(service)
@@ -100,43 +108,23 @@ func (c *cacheSelector) get(service string) ([]*registry.Service, error) {
100108
}
101109

102110
// cache results
111+
c.Lock()
103112
c.set(service, c.cp(services))
104-
return services, nil
105-
}
113+
c.Unlock()
106114

107-
// check the cache first
108-
services, ok := c.cache[service]
109-
110-
// cache miss or no services
111-
if !ok || len(services) == 0 {
112-
return get(service)
113-
}
114-
115-
// got cache but lets check ttl
116-
ttl, kk := c.ttls[service]
117-
118-
// within ttl so return cache
119-
if kk && time.Since(ttl) < c.ttl {
120-
return c.cp(services), nil
121-
}
122-
123-
// expired entry so get service
124-
services, err := get(service)
125-
126-
// no error then return error
127-
if err == nil {
128115
return services, nil
129116
}
130117

131-
// not found error then return
132-
if err == registry.ErrNotFound {
133-
return nil, selector.ErrNotFound
118+
// watch service if not watched
119+
if _, ok := c.watched[service]; !ok {
120+
go c.run(service)
134121
}
135122

136-
// other error
123+
// unlock the read lock
124+
c.RUnlock()
137125

138-
// return expired cache as last resort
139-
return c.cp(services), nil
126+
// get and return services
127+
return get(service)
140128
}
141129

142130
func (c *cacheSelector) set(service string, services []*registry.Service) {
@@ -257,6 +245,18 @@ func (c *cacheSelector) update(res *registry.Result) {
257245
// reloads the watcher if Init is called
258246
// and returns when Close is called
259247
func (c *cacheSelector) run(name string) {
248+
// set watcher
249+
c.Lock()
250+
c.watched[name] = true
251+
c.Unlock()
252+
253+
// delete watcher on exit
254+
defer func() {
255+
c.Lock()
256+
delete(c.watched, name)
257+
c.Unlock()
258+
}()
259+
260260
for {
261261
// exit early if already dead
262262
if c.quit() {

0 commit comments

Comments
 (0)