pool.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright 2012 Gary Burd
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. package redis
  15. import (
  16. "errors"
  17. )
  18. // Pool maintains a pool of connections.
  19. //
  20. // Pooled connections do not support concurrent access or pub/sub.
  21. //
  22. // The following example shows how to use a pool in a web application. The
  23. // application creates a pool at application startup and makes it available to
  24. // request handlers, possibly using a global variable:
  25. //
  26. // var server string // host:port of server
  27. // var password string
  28. // ...
  29. //
  30. // pool = redis.NewPool(func () (c redis.Conn, err error) {
  31. // c, err = redis.Dial(server)
  32. // if err != nil {
  33. // err = c.Do("AUTH", password)
  34. // }
  35. // return
  36. // }, 3)
  37. //
  38. // This pool has a maximum of three connections to the server specified by the
  39. // variable "server". Each connection is authenticated using a password.
  40. //
  41. // A request handler gets a connection from the pool and closes the connection
  42. // when the handler is done:
  43. //
  44. // conn, err := pool.Get()
  45. // if err != nil {
  46. // // handle the error
  47. // }
  48. // defer conn.Close()
  49. // // do something with the connection
  50. //
  51. // Close() returns the connection to the pool if there's room in the pool and
  52. // the connection does not have a permanent error. Otherwise, Close() releases
  53. // the resources used by the connection.
  54. type Pool struct {
  55. newFn func() (Conn, error)
  56. conns chan Conn
  57. }
  58. type pooledConnection struct {
  59. c Conn
  60. err error
  61. pool *Pool
  62. }
  63. // NewPool returns a new connection pool. The pool uses newFn to create
  64. // connections as needed and maintains a maximum of maxIdle idle connections.
  65. func NewPool(newFn func() (Conn, error), maxIdle int) *Pool {
  66. return &Pool{newFn: newFn, conns: make(chan Conn, maxIdle)}
  67. }
  68. // Get returns an idle connection from the pool if available or creates a new
  69. // connection. The caller should Close() the connection to return the
  70. // connection to the pool.
  71. func (p *Pool) Get() (Conn, error) {
  72. var c Conn
  73. select {
  74. case c = <-p.conns:
  75. default:
  76. var err error
  77. c, err = p.newFn()
  78. if err != nil {
  79. return nil, err
  80. }
  81. }
  82. return &pooledConnection{c: c, pool: p}, nil
  83. }
  84. func (c *pooledConnection) Err() error {
  85. if c.err != nil {
  86. return c.err
  87. }
  88. return c.c.Err()
  89. }
  90. func (c *pooledConnection) Do(commandName string, args ...interface{}) (reply interface{}, err error) {
  91. if c.err != nil {
  92. return nil, c.err
  93. }
  94. return c.c.Do(commandName, args...)
  95. }
  96. func (c *pooledConnection) Send(commandName string, args ...interface{}) error {
  97. if c.err != nil {
  98. return c.err
  99. }
  100. return c.c.Send(commandName, args...)
  101. }
  102. func (c *pooledConnection) Flush() error {
  103. if c.err != nil {
  104. return c.err
  105. }
  106. return c.c.Flush()
  107. }
  108. func (c *pooledConnection) Receive() (reply interface{}, err error) {
  109. if c.err != nil {
  110. return nil, c.err
  111. }
  112. return c.c.Receive()
  113. }
  114. var errPoolClosed = errors.New("redigo: pooled connection closed")
  115. func (c *pooledConnection) Close() (err error) {
  116. if c.err != nil {
  117. return c.err
  118. }
  119. c.err = errPoolClosed
  120. if c.c.Err() != nil {
  121. return c.c.Close()
  122. }
  123. select {
  124. case c.pool.conns <- c.c:
  125. default:
  126. return c.c.Close()
  127. }
  128. return nil
  129. }