You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
2.1 KiB

  1. package pool
  2. import (
  3. "bufio"
  4. "context"
  5. "net"
  6. "sync/atomic"
  7. "time"
  8. "github.com/go-redis/redis/v8/internal/proto"
  9. )
  10. var noDeadline = time.Time{}
  11. type Conn struct {
  12. usedAt int64 // atomic
  13. netConn net.Conn
  14. rd *proto.Reader
  15. bw *bufio.Writer
  16. wr *proto.Writer
  17. Inited bool
  18. pooled bool
  19. createdAt time.Time
  20. }
  21. func NewConn(netConn net.Conn) *Conn {
  22. cn := &Conn{
  23. netConn: netConn,
  24. createdAt: time.Now(),
  25. }
  26. cn.rd = proto.NewReader(netConn)
  27. cn.bw = bufio.NewWriter(netConn)
  28. cn.wr = proto.NewWriter(cn.bw)
  29. cn.SetUsedAt(time.Now())
  30. return cn
  31. }
  32. func (cn *Conn) UsedAt() time.Time {
  33. unix := atomic.LoadInt64(&cn.usedAt)
  34. return time.Unix(unix, 0)
  35. }
  36. func (cn *Conn) SetUsedAt(tm time.Time) {
  37. atomic.StoreInt64(&cn.usedAt, tm.Unix())
  38. }
  39. func (cn *Conn) SetNetConn(netConn net.Conn) {
  40. cn.netConn = netConn
  41. cn.rd.Reset(netConn)
  42. cn.bw.Reset(netConn)
  43. }
  44. func (cn *Conn) Write(b []byte) (int, error) {
  45. return cn.netConn.Write(b)
  46. }
  47. func (cn *Conn) RemoteAddr() net.Addr {
  48. if cn.netConn != nil {
  49. return cn.netConn.RemoteAddr()
  50. }
  51. return nil
  52. }
  53. func (cn *Conn) WithReader(ctx context.Context, timeout time.Duration, fn func(rd *proto.Reader) error) error {
  54. if err := cn.netConn.SetReadDeadline(cn.deadline(ctx, timeout)); err != nil {
  55. return err
  56. }
  57. return fn(cn.rd)
  58. }
  59. func (cn *Conn) WithWriter(
  60. ctx context.Context, timeout time.Duration, fn func(wr *proto.Writer) error,
  61. ) error {
  62. if err := cn.netConn.SetWriteDeadline(cn.deadline(ctx, timeout)); err != nil {
  63. return err
  64. }
  65. if cn.bw.Buffered() > 0 {
  66. cn.bw.Reset(cn.netConn)
  67. }
  68. if err := fn(cn.wr); err != nil {
  69. return err
  70. }
  71. return cn.bw.Flush()
  72. }
  73. func (cn *Conn) Close() error {
  74. return cn.netConn.Close()
  75. }
  76. func (cn *Conn) deadline(ctx context.Context, timeout time.Duration) time.Time {
  77. tm := time.Now()
  78. cn.SetUsedAt(tm)
  79. if timeout > 0 {
  80. tm = tm.Add(timeout)
  81. }
  82. if ctx != nil {
  83. deadline, ok := ctx.Deadline()
  84. if ok {
  85. if timeout == 0 {
  86. return deadline
  87. }
  88. if deadline.Before(tm) {
  89. return deadline
  90. }
  91. return tm
  92. }
  93. }
  94. if timeout > 0 {
  95. return tm
  96. }
  97. return noDeadline
  98. }