本站源代码
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

227 lines
5.7KB

  1. package redis
  2. import (
  3. "crypto/tls"
  4. "errors"
  5. "fmt"
  6. "net"
  7. "net/url"
  8. "runtime"
  9. "strconv"
  10. "strings"
  11. "time"
  12. "github.com/go-redis/redis/internal/pool"
  13. )
  14. // Limiter is the interface of a rate limiter or a circuit breaker.
  15. type Limiter interface {
  16. // Allow returns a nil if operation is allowed or an error otherwise.
  17. // If operation is allowed client must report the result of operation
  18. // whether is a success or a failure.
  19. Allow() error
  20. // ReportResult reports the result of previously allowed operation.
  21. // nil indicates a success, non-nil error indicates a failure.
  22. ReportResult(result error)
  23. }
  24. type Options struct {
  25. // The network type, either tcp or unix.
  26. // Default is tcp.
  27. Network string
  28. // host:port address.
  29. Addr string
  30. // Dialer creates new network connection and has priority over
  31. // Network and Addr options.
  32. Dialer func() (net.Conn, error)
  33. // Hook that is called when new connection is established.
  34. OnConnect func(*Conn) error
  35. // Optional password. Must match the password specified in the
  36. // requirepass server configuration option.
  37. Password string
  38. // Database to be selected after connecting to the server.
  39. DB int
  40. // Maximum number of retries before giving up.
  41. // Default is to not retry failed commands.
  42. MaxRetries int
  43. // Minimum backoff between each retry.
  44. // Default is 8 milliseconds; -1 disables backoff.
  45. MinRetryBackoff time.Duration
  46. // Maximum backoff between each retry.
  47. // Default is 512 milliseconds; -1 disables backoff.
  48. MaxRetryBackoff time.Duration
  49. // Dial timeout for establishing new connections.
  50. // Default is 5 seconds.
  51. DialTimeout time.Duration
  52. // Timeout for socket reads. If reached, commands will fail
  53. // with a timeout instead of blocking. Use value -1 for no timeout and 0 for default.
  54. // Default is 3 seconds.
  55. ReadTimeout time.Duration
  56. // Timeout for socket writes. If reached, commands will fail
  57. // with a timeout instead of blocking.
  58. // Default is ReadTimeout.
  59. WriteTimeout time.Duration
  60. // Maximum number of socket connections.
  61. // Default is 10 connections per every CPU as reported by runtime.NumCPU.
  62. PoolSize int
  63. // Minimum number of idle connections which is useful when establishing
  64. // new connection is slow.
  65. MinIdleConns int
  66. // Connection age at which client retires (closes) the connection.
  67. // Default is to not close aged connections.
  68. MaxConnAge time.Duration
  69. // Amount of time client waits for connection if all connections
  70. // are busy before returning an error.
  71. // Default is ReadTimeout + 1 second.
  72. PoolTimeout time.Duration
  73. // Amount of time after which client closes idle connections.
  74. // Should be less than server's timeout.
  75. // Default is 5 minutes. -1 disables idle timeout check.
  76. IdleTimeout time.Duration
  77. // Frequency of idle checks made by idle connections reaper.
  78. // Default is 1 minute. -1 disables idle connections reaper,
  79. // but idle connections are still discarded by the client
  80. // if IdleTimeout is set.
  81. IdleCheckFrequency time.Duration
  82. // Enables read only queries on slave nodes.
  83. readOnly bool
  84. // TLS Config to use. When set TLS will be negotiated.
  85. TLSConfig *tls.Config
  86. }
  87. func (opt *Options) init() {
  88. if opt.Network == "" {
  89. opt.Network = "tcp"
  90. }
  91. if opt.Addr == "" {
  92. opt.Addr = "localhost:6379"
  93. }
  94. if opt.Dialer == nil {
  95. opt.Dialer = func() (net.Conn, error) {
  96. netDialer := &net.Dialer{
  97. Timeout: opt.DialTimeout,
  98. KeepAlive: 5 * time.Minute,
  99. }
  100. if opt.TLSConfig == nil {
  101. return netDialer.Dial(opt.Network, opt.Addr)
  102. } else {
  103. return tls.DialWithDialer(netDialer, opt.Network, opt.Addr, opt.TLSConfig)
  104. }
  105. }
  106. }
  107. if opt.PoolSize == 0 {
  108. opt.PoolSize = 10 * runtime.NumCPU()
  109. }
  110. if opt.DialTimeout == 0 {
  111. opt.DialTimeout = 5 * time.Second
  112. }
  113. switch opt.ReadTimeout {
  114. case -1:
  115. opt.ReadTimeout = 0
  116. case 0:
  117. opt.ReadTimeout = 3 * time.Second
  118. }
  119. switch opt.WriteTimeout {
  120. case -1:
  121. opt.WriteTimeout = 0
  122. case 0:
  123. opt.WriteTimeout = opt.ReadTimeout
  124. }
  125. if opt.PoolTimeout == 0 {
  126. opt.PoolTimeout = opt.ReadTimeout + time.Second
  127. }
  128. if opt.IdleTimeout == 0 {
  129. opt.IdleTimeout = 5 * time.Minute
  130. }
  131. if opt.IdleCheckFrequency == 0 {
  132. opt.IdleCheckFrequency = time.Minute
  133. }
  134. switch opt.MinRetryBackoff {
  135. case -1:
  136. opt.MinRetryBackoff = 0
  137. case 0:
  138. opt.MinRetryBackoff = 8 * time.Millisecond
  139. }
  140. switch opt.MaxRetryBackoff {
  141. case -1:
  142. opt.MaxRetryBackoff = 0
  143. case 0:
  144. opt.MaxRetryBackoff = 512 * time.Millisecond
  145. }
  146. }
  147. // ParseURL parses an URL into Options that can be used to connect to Redis.
  148. func ParseURL(redisURL string) (*Options, error) {
  149. o := &Options{Network: "tcp"}
  150. u, err := url.Parse(redisURL)
  151. if err != nil {
  152. return nil, err
  153. }
  154. if u.Scheme != "redis" && u.Scheme != "rediss" {
  155. return nil, errors.New("invalid redis URL scheme: " + u.Scheme)
  156. }
  157. if u.User != nil {
  158. if p, ok := u.User.Password(); ok {
  159. o.Password = p
  160. }
  161. }
  162. if len(u.Query()) > 0 {
  163. return nil, errors.New("no options supported")
  164. }
  165. h, p, err := net.SplitHostPort(u.Host)
  166. if err != nil {
  167. h = u.Host
  168. }
  169. if h == "" {
  170. h = "localhost"
  171. }
  172. if p == "" {
  173. p = "6379"
  174. }
  175. o.Addr = net.JoinHostPort(h, p)
  176. f := strings.FieldsFunc(u.Path, func(r rune) bool {
  177. return r == '/'
  178. })
  179. switch len(f) {
  180. case 0:
  181. o.DB = 0
  182. case 1:
  183. if o.DB, err = strconv.Atoi(f[0]); err != nil {
  184. return nil, fmt.Errorf("invalid redis database number: %q", f[0])
  185. }
  186. default:
  187. return nil, errors.New("invalid redis URL path: " + u.Path)
  188. }
  189. if u.Scheme == "rediss" {
  190. o.TLSConfig = &tls.Config{ServerName: h}
  191. }
  192. return o, nil
  193. }
  194. func newConnPool(opt *Options) *pool.ConnPool {
  195. return pool.NewConnPool(&pool.Options{
  196. Dialer: opt.Dialer,
  197. PoolSize: opt.PoolSize,
  198. MinIdleConns: opt.MinIdleConns,
  199. MaxConnAge: opt.MaxConnAge,
  200. PoolTimeout: opt.PoolTimeout,
  201. IdleTimeout: opt.IdleTimeout,
  202. IdleCheckFrequency: opt.IdleCheckFrequency,
  203. })
  204. }
上海开阖软件有限公司 沪ICP备12045867号-1