dns_cache.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. package tos
  2. import (
  3. "container/heap"
  4. "context"
  5. "net"
  6. "strings"
  7. "sync"
  8. "time"
  9. )
  10. const (
  11. DefaultCacheCap = 100
  12. VolceHostSuffix = "volces.com"
  13. HostSplitSep = "."
  14. HostSplitLength = 4
  15. )
  16. type cacheItem struct {
  17. host string
  18. ipList []string
  19. expireAt time.Time
  20. heapIndex int
  21. }
  22. type priorityQueue []*cacheItem
  23. func (p priorityQueue) Len() int {
  24. return len(p)
  25. }
  26. func (p priorityQueue) Peek() *cacheItem {
  27. if p.Len() > 0 {
  28. return p[0]
  29. }
  30. return nil
  31. }
  32. func (p priorityQueue) Less(i, j int) bool {
  33. return p[i].expireAt.Before(p[j].expireAt)
  34. }
  35. func (p priorityQueue) Swap(i, j int) {
  36. p[i], p[j] = p[j], p[i]
  37. p[i].heapIndex = i
  38. p[j].heapIndex = j
  39. }
  40. func (p *priorityQueue) Push(x interface{}) {
  41. n := len(*p)
  42. item := x.(*cacheItem)
  43. item.heapIndex = n
  44. *p = append(*p, item)
  45. }
  46. func (p *priorityQueue) Pop() interface{} {
  47. old := *p
  48. n := len(old)
  49. item := old[n-1]
  50. old[n-1] = nil
  51. item.heapIndex = -1
  52. *p = old[0 : n-1]
  53. return item
  54. }
  55. type cache struct {
  56. lock sync.RWMutex
  57. heap *priorityQueue
  58. cleanTime time.Time
  59. data map[string]cacheItem
  60. expiration time.Duration
  61. }
  62. func (c *cache) Remove(key string, removeIp string) {
  63. c.lock.Lock()
  64. defer c.lock.Unlock()
  65. data, ok := c.data[key]
  66. if !ok {
  67. return
  68. }
  69. value := make([]string, 0, len(data.ipList))
  70. for _, ip := range data.ipList {
  71. if ip == removeIp {
  72. continue
  73. }
  74. value = append(value, ip)
  75. }
  76. // 没有有效的 IP 将缓存删除
  77. if len(value) == 0 {
  78. delete(c.data, key)
  79. return
  80. }
  81. data.ipList = value
  82. c.data[key] = data
  83. }
  84. func (c *cache) Get(key string) ([]string, bool) {
  85. c.lock.RLock()
  86. data, ok := c.data[key]
  87. c.lock.RUnlock()
  88. if !ok {
  89. return nil, false
  90. }
  91. if data.expireAt.Before(time.Now()) {
  92. return nil, false
  93. }
  94. return data.ipList, true
  95. }
  96. func (c *cache) cleanCache() {
  97. c.cleanTime = time.Now().Add(c.expiration)
  98. maxCleanCount := 5
  99. for i := 0; i < maxCleanCount; i++ {
  100. item := c.heap.Peek()
  101. if item == nil {
  102. return
  103. }
  104. if item.expireAt.Before(time.Now()) {
  105. heap.Pop(c.heap)
  106. data, ok := c.data[item.host]
  107. if ok && data.expireAt == item.expireAt {
  108. delete(c.data, item.host)
  109. }
  110. } else {
  111. return
  112. }
  113. }
  114. }
  115. func (c *cache) Put(key string, ipList []string) {
  116. c.lock.Lock()
  117. defer c.lock.Unlock()
  118. item := cacheItem{
  119. ipList: ipList,
  120. expireAt: time.Now().Add(c.expiration),
  121. host: key,
  122. }
  123. c.data[key] = item
  124. heap.Push(c.heap, &item)
  125. // 大于 Cap
  126. if c.heap.Len() > DefaultCacheCap {
  127. item := heap.Pop(c.heap).(*cacheItem)
  128. if item == nil {
  129. return
  130. }
  131. data, ok := c.data[item.host]
  132. if ok && data.expireAt == item.expireAt {
  133. delete(c.data, item.host)
  134. }
  135. }
  136. if time.Now().After(c.cleanTime) {
  137. c.cleanCache()
  138. }
  139. }
  140. type resolver struct {
  141. cache *cache
  142. }
  143. func newResolver(expiration time.Duration) *resolver {
  144. pq := make(priorityQueue, 0)
  145. return &resolver{cache: &cache{
  146. heap: &pq,
  147. cleanTime: time.Now().Add(expiration),
  148. data: make(map[string]cacheItem),
  149. expiration: expiration,
  150. }}
  151. }
  152. func ipToStringList(ips []net.IP) []string {
  153. res := make([]string, len(ips))
  154. for i, ip := range ips {
  155. res[i] = ip.String()
  156. }
  157. return res
  158. }
  159. func wrappedHost(host string) string {
  160. if !strings.HasSuffix(host, VolceHostSuffix) {
  161. return host
  162. }
  163. hostSplit := strings.Split(host, HostSplitSep)
  164. if len(hostSplit) != HostSplitLength {
  165. return host
  166. }
  167. return strings.Join(hostSplit[1:], HostSplitSep)
  168. }
  169. func (r *resolver) GetIpList(ctx context.Context, host string) ([]string, error) {
  170. ipList, ok := r.cache.Get(wrappedHost(host))
  171. if ok {
  172. return ipList, nil
  173. }
  174. ips, err := net.LookupIP(host)
  175. if err != nil {
  176. return nil, err
  177. }
  178. ipsStr := ipToStringList(ips)
  179. r.cache.Put(wrappedHost(host), ipsStr)
  180. return ipsStr, nil
  181. }
  182. func (r *resolver) Remove(host string, ip string) {
  183. r.cache.Remove(wrappedHost(host), ip)
  184. }