This repository has been archived by the owner on Feb 7, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cache.go
106 lines (82 loc) · 2.28 KB
/
cache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package srvcache
import (
"net"
"sync"
"time"
"github.com/sirupsen/logrus"
)
// Resolver performs dns lookup like net.LookupSRV
type Resolver func(service string, proto string, name string) (cname string, addrs []*net.SRV, err error)
// Cache provides a fixed term DNS cache for SRV lookups
type Cache struct {
identity string
cache map[query]*entry
maxAge time.Duration
resolver Resolver
log *logrus.Entry
sync.Mutex
}
type query struct {
service string
proto string
name string
}
type entry struct {
cname string
addrs []*net.SRV
expTime time.Time
}
// LookupSRV has the same signature as net.LookupSRV but performs caching
func (c *Cache) LookupSRV(service string, proto string, name string) (cname string, addrs []*net.SRV, err error) {
q := query{service, proto, name}
cname, addrs = c.retrieve(q)
if addrs == nil {
cname, addrs, err = c.resolver("", "", name)
if err != nil {
return "", nil, err
}
}
c.store(q, cname, addrs)
srvctr.WithLabelValues(c.identity).Inc()
return cname, addrs, err
}
// LookupSrvServers performs a cached SRV lookup and returns a Servers collection
func (c *Cache) LookupSrvServers(service string, proto string, name string, scheme string) (s Servers, err error) {
_, addrs, err := c.LookupSRV(service, proto, name)
if err != nil {
return NewServers(), err
}
servers := make([]Server, len(addrs))
for i, addr := range addrs {
servers[i] = &BasicServer{host: addr.Target, port: addr.Port, scheme: scheme}
}
return NewServers(servers...), nil
}
func (c *Cache) store(q query, cname string, addrs []*net.SRV) {
c.Lock()
defer c.Unlock()
c.cache[q] = &entry{
cname: cname,
addrs: addrs,
expTime: time.Now().Add(c.maxAge),
}
}
func (c *Cache) retrieve(q query) (string, []*net.SRV) {
c.Lock()
defer c.Unlock()
entry, found := c.cache[q]
if !found {
c.log.Debugf("SRV cache miss on SRV record %#v in cache", q)
srvmiss.WithLabelValues(c.identity).Inc()
return "", nil
}
if time.Now().Before(entry.expTime) {
c.log.Debugf("SRV cache hit on SRV record %#v", q)
srvhit.WithLabelValues(c.identity).Inc()
return entry.cname, entry.addrs
}
c.log.Debugf("SRV cache miss on SRV record %#v due to age of the record", q)
delete(c.cache, q)
srvmiss.WithLabelValues(c.identity).Inc()
return "", nil
}