connection_cache.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package hub
  2. import (
  3. "net"
  4. "sync"
  5. "time"
  6. )
  7. type AwaitingConnection struct {
  8. conn net.Conn
  9. expire time.Time
  10. }
  11. func (this *AwaitingConnection) Expired() bool {
  12. return this.expire.Before(time.Now())
  13. }
  14. type ConnectionCache struct {
  15. sync.Mutex
  16. cache map[string][]*AwaitingConnection
  17. }
  18. func NewConnectionCache() *ConnectionCache {
  19. c := &ConnectionCache{
  20. cache: make(map[string][]*AwaitingConnection),
  21. }
  22. go c.Cleanup()
  23. return c
  24. }
  25. func (this *ConnectionCache) Cleanup() {
  26. for {
  27. time.Sleep(time.Second * 4)
  28. this.Lock()
  29. for key, value := range this.cache {
  30. size := len(value)
  31. changed := false
  32. for i := 0; i < size; {
  33. if value[i].Expired() {
  34. value[i].conn.Close()
  35. value[i] = value[size-1]
  36. size--
  37. changed = true
  38. } else {
  39. i++
  40. }
  41. }
  42. if changed {
  43. for i := size; i < len(value); i++ {
  44. value[i] = nil
  45. }
  46. value = value[:size]
  47. this.cache[key] = value
  48. }
  49. }
  50. this.Unlock()
  51. }
  52. }
  53. func (this *ConnectionCache) Recycle(dest string, conn net.Conn) {
  54. this.Lock()
  55. defer this.Unlock()
  56. aconn := &AwaitingConnection{
  57. conn: conn,
  58. expire: time.Now().Add(time.Second * 4),
  59. }
  60. var list []*AwaitingConnection
  61. if v, found := this.cache[dest]; found {
  62. v = append(v, aconn)
  63. list = v
  64. } else {
  65. list = []*AwaitingConnection{aconn}
  66. }
  67. this.cache[dest] = list
  68. }
  69. func FindFirstValid(list []*AwaitingConnection) int {
  70. for idx, conn := range list {
  71. if !conn.Expired() {
  72. return idx
  73. }
  74. conn.conn.Close()
  75. }
  76. return -1
  77. }
  78. func (this *ConnectionCache) Get(dest string) net.Conn {
  79. this.Lock()
  80. defer this.Unlock()
  81. list, found := this.cache[dest]
  82. if !found {
  83. return nil
  84. }
  85. firstValid := FindFirstValid(list)
  86. if firstValid == -1 {
  87. delete(this.cache, dest)
  88. return nil
  89. }
  90. res := list[firstValid].conn
  91. list = list[firstValid+1:]
  92. this.cache[dest] = list
  93. return res
  94. }