gopkg.in/rethinkdb/rethinkdb-go.v6@v6.2.2/pool.go (about) 1 package rethinkdb 2 3 import ( 4 "errors" 5 "sync" 6 "sync/atomic" 7 8 "golang.org/x/net/context" 9 ) 10 11 var ( 12 errPoolClosed = errors.New("rethinkdb: pool is closed") 13 ) 14 15 const ( 16 poolIsNotClosed int32 = 0 17 poolIsClosed int32 = 1 18 ) 19 20 type connFactory func(host string, opts *ConnectOpts) (*Connection, error) 21 22 // A Pool is used to store a pool of connections to a single RethinkDB server 23 type Pool struct { 24 host Host 25 opts *ConnectOpts 26 27 conns []*Connection 28 pointer int32 29 closed int32 30 31 connFactory connFactory 32 33 mu sync.Mutex // protects lazy creating connections 34 } 35 36 // NewPool creates a new connection pool for the given host 37 func NewPool(host Host, opts *ConnectOpts) (*Pool, error) { 38 return newPool(host, opts, NewConnection) 39 } 40 41 func newPool(host Host, opts *ConnectOpts, connFactory connFactory) (*Pool, error) { 42 initialCap := opts.InitialCap 43 if initialCap <= 0 { 44 // Fallback to MaxIdle if InitialCap is zero, this should be removed 45 // when MaxIdle is removed 46 initialCap = opts.MaxIdle 47 } 48 49 maxOpen := opts.MaxOpen 50 if maxOpen <= 0 { 51 maxOpen = 1 52 } 53 54 conns := make([]*Connection, maxOpen) 55 var err error 56 for i := 0; i < opts.InitialCap; i++ { 57 conns[i], err = connFactory(host.String(), opts) 58 if err != nil { 59 return nil, err 60 } 61 } 62 63 return &Pool{ 64 conns: conns, 65 pointer: -1, 66 host: host, 67 opts: opts, 68 connFactory: connFactory, 69 closed: poolIsNotClosed, 70 }, nil 71 } 72 73 // Ping verifies a connection to the database is still alive, 74 // establishing a connection if necessary. 75 func (p *Pool) Ping() error { 76 _, err := p.conn() 77 return err 78 } 79 80 // Close closes the database, releasing any open resources. 81 // 82 // It is rare to Close a Pool, as the Pool handle is meant to be 83 // long-lived and shared between many goroutines. 84 func (p *Pool) Close() error { 85 if atomic.LoadInt32(&p.closed) == poolIsClosed { 86 return nil 87 } 88 89 p.mu.Lock() 90 defer p.mu.Unlock() 91 92 if p.closed == poolIsClosed { 93 return nil 94 } 95 p.closed = poolIsClosed 96 97 for _, c := range p.conns { 98 if c != nil { 99 err := c.Close() 100 if err != nil { 101 return err 102 } 103 } 104 } 105 106 return nil 107 } 108 109 func (p *Pool) conn() (*Connection, error) { 110 if atomic.LoadInt32(&p.closed) == poolIsClosed { 111 return nil, errPoolClosed 112 } 113 114 pos := atomic.AddInt32(&p.pointer, 1) 115 if pos == int32(len(p.conns)) { 116 atomic.StoreInt32(&p.pointer, 0) 117 } 118 pos = pos % int32(len(p.conns)) 119 120 var err error 121 122 if p.conns[pos] == nil { 123 p.mu.Lock() 124 defer p.mu.Unlock() 125 126 if p.conns[pos] == nil { 127 p.conns[pos], err = p.connFactory(p.host.String(), p.opts) 128 if err != nil { 129 return nil, err 130 } 131 } 132 } else if p.conns[pos].isBad() { 133 // connBad connection needs to be reconnected 134 p.mu.Lock() 135 defer p.mu.Unlock() 136 137 p.conns[pos], err = p.connFactory(p.host.String(), p.opts) 138 if err != nil { 139 return nil, err 140 } 141 } 142 143 return p.conns[pos], nil 144 } 145 146 // SetInitialPoolCap sets the initial capacity of the connection pool. 147 // 148 // Deprecated: This value should only be set when connecting 149 func (p *Pool) SetInitialPoolCap(n int) { 150 return 151 } 152 153 // SetMaxIdleConns sets the maximum number of connections in the idle 154 // connection pool. 155 // 156 // Deprecated: This value should only be set when connecting 157 func (p *Pool) SetMaxIdleConns(n int) { 158 return 159 } 160 161 // SetMaxOpenConns sets the maximum number of open connections to the database. 162 // 163 // Deprecated: This value should only be set when connecting 164 func (p *Pool) SetMaxOpenConns(n int) { 165 return 166 } 167 168 // Query execution functions 169 170 // Exec executes a query without waiting for any response. 171 func (p *Pool) Exec(ctx context.Context, q Query) error { 172 c, err := p.conn() 173 if err != nil { 174 return err 175 } 176 177 _, _, err = c.Query(ctx, q) 178 return err 179 } 180 181 // Query executes a query and waits for the response 182 func (p *Pool) Query(ctx context.Context, q Query) (*Cursor, error) { 183 c, err := p.conn() 184 if err != nil { 185 return nil, err 186 } 187 188 _, cursor, err := c.Query(ctx, q) 189 return cursor, err 190 } 191 192 // Server returns the server name and server UUID being used by a connection. 193 func (p *Pool) Server() (ServerResponse, error) { 194 var response ServerResponse 195 196 c, err := p.conn() 197 if err != nil { 198 return response, err 199 } 200 201 response, err = c.Server() 202 return response, err 203 }