()
| 1138 | } |
| 1139 | |
| 1140 | func (p *ConnPool) popIdle() (*Conn, error) { |
| 1141 | if p.closed() { |
| 1142 | return nil, ErrClosed |
| 1143 | } |
| 1144 | defer p.checkMinIdleConns() |
| 1145 | |
| 1146 | n := len(p.idleConns) |
| 1147 | if n == 0 { |
| 1148 | return nil, nil |
| 1149 | } |
| 1150 | |
| 1151 | var cn *Conn |
| 1152 | attempts := 0 |
| 1153 | |
| 1154 | maxAttempts := min(popAttempts, n) |
| 1155 | for attempts < maxAttempts { |
| 1156 | if len(p.idleConns) == 0 { |
| 1157 | return nil, nil |
| 1158 | } |
| 1159 | |
| 1160 | if p.cfg.PoolFIFO { |
| 1161 | cn = p.idleConns[0] |
| 1162 | copy(p.idleConns, p.idleConns[1:]) |
| 1163 | p.idleConns = p.idleConns[:len(p.idleConns)-1] |
| 1164 | } else { |
| 1165 | idx := len(p.idleConns) - 1 |
| 1166 | cn = p.idleConns[idx] |
| 1167 | p.idleConns = p.idleConns[:idx] |
| 1168 | } |
| 1169 | attempts++ |
| 1170 | |
| 1171 | // Hot path optimization: try IDLE → IN_USE or CREATED → IN_USE transition |
| 1172 | // Using inline TryAcquire() method for better performance (avoids pointer dereference) |
| 1173 | if cn.TryAcquire() { |
| 1174 | // Successfully acquired the connection |
| 1175 | p.idleConnsLen.Add(-1) |
| 1176 | break |
| 1177 | } |
| 1178 | |
| 1179 | // Connection is in UNUSABLE, INITIALIZING, or other state - skip it |
| 1180 | |
| 1181 | // Connection is not in a valid state (might be UNUSABLE for handoff/re-auth, INITIALIZING, etc.) |
| 1182 | // Put it back in the pool and try the next one |
| 1183 | if p.cfg.PoolFIFO { |
| 1184 | // FIFO: put at end (will be picked up last since we pop from front) |
| 1185 | p.idleConns = append(p.idleConns, cn) |
| 1186 | } else { |
| 1187 | // LIFO: put at beginning (will be picked up last since we pop from end) |
| 1188 | p.idleConns = append([]*Conn{cn}, p.idleConns...) |
| 1189 | } |
| 1190 | cn = nil |
| 1191 | } |
| 1192 | |
| 1193 | // If we exhausted all attempts without finding a usable connection, return nil |
| 1194 | if attempts > 1 && attempts >= maxAttempts && int32(attempts) >= p.poolSize.Load() { |
| 1195 | internal.Logger.Printf(context.Background(), "redis: connection pool: failed to get a usable connection after %d attempts", attempts) |
| 1196 | return nil, nil |
| 1197 | } |
no test coverage detected