summaryrefslogtreecommitdiff
path: root/vendor/github.com/jackc/pgx/v5/pgxpool
diff options
context:
space:
mode:
authorLibravatar kim <grufwub@gmail.com>2025-09-08 20:53:25 +0200
committerLibravatar kim <gruf@noreply.codeberg.org>2025-09-08 20:53:25 +0200
commita6429b5410062cb8067e6dbbc9999d7d579a751d (patch)
treec10458d8a5e41ec561b0d139d83547353fdb69bc /vendor/github.com/jackc/pgx/v5/pgxpool
parent[bugfix] check for nil notification (#4417) (diff)
downloadgotosocial-a6429b5410062cb8067e6dbbc9999d7d579a751d.tar.xz
[chore] update dependencies (#4422)
- github.com/jackc/pgx/v5 v5.7.5 -> v5.7.6 - github.com/ncruces/go-sqlite3 v0.28.0 -> v0.29.0 - github.com/tdewolff/minify/v2 v2.24.2 -> v2.24.3 - golang.org/x/oauth2 v0.30.0 -> v0.31.0 - golang.org/x/sys v0.35.0 -> v0.36.0 - golang.org/x/text v0.28.0 -> v0.29.0 Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4422 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
Diffstat (limited to 'vendor/github.com/jackc/pgx/v5/pgxpool')
-rw-r--r--vendor/github.com/jackc/pgx/v5/pgxpool/pool.go115
1 files changed, 89 insertions, 26 deletions
diff --git a/vendor/github.com/jackc/pgx/v5/pgxpool/pool.go b/vendor/github.com/jackc/pgx/v5/pgxpool/pool.go
index e22ed289a..addfb412f 100644
--- a/vendor/github.com/jackc/pgx/v5/pgxpool/pool.go
+++ b/vendor/github.com/jackc/pgx/v5/pgxpool/pool.go
@@ -2,7 +2,7 @@ package pgxpool
import (
"context"
- "fmt"
+ "errors"
"math/rand"
"runtime"
"strconv"
@@ -15,12 +15,14 @@ import (
"github.com/jackc/puddle/v2"
)
-var defaultMaxConns = int32(4)
-var defaultMinConns = int32(0)
-var defaultMinIdleConns = int32(0)
-var defaultMaxConnLifetime = time.Hour
-var defaultMaxConnIdleTime = time.Minute * 30
-var defaultHealthCheckPeriod = time.Minute
+var (
+ defaultMaxConns = int32(4)
+ defaultMinConns = int32(0)
+ defaultMinIdleConns = int32(0)
+ defaultMaxConnLifetime = time.Hour
+ defaultMaxConnIdleTime = time.Minute * 30
+ defaultHealthCheckPeriod = time.Minute
+)
type connResource struct {
conn *pgx.Conn
@@ -84,9 +86,10 @@ type Pool struct {
config *Config
beforeConnect func(context.Context, *pgx.ConnConfig) error
afterConnect func(context.Context, *pgx.Conn) error
- beforeAcquire func(context.Context, *pgx.Conn) bool
+ prepareConn func(context.Context, *pgx.Conn) (bool, error)
afterRelease func(*pgx.Conn) bool
beforeClose func(*pgx.Conn)
+ shouldPing func(context.Context, ShouldPingParams) bool
minConns int32
minIdleConns int32
maxConns int32
@@ -104,6 +107,12 @@ type Pool struct {
closeChan chan struct{}
}
+// ShouldPingParams are the parameters passed to ShouldPing.
+type ShouldPingParams struct {
+ Conn *pgx.Conn
+ IdleDuration time.Duration
+}
+
// Config is the configuration struct for creating a pool. It must be created by [ParseConfig] and then it can be
// modified.
type Config struct {
@@ -119,8 +128,23 @@ type Config struct {
// BeforeAcquire is called before a connection is acquired from the pool. It must return true to allow the
// acquisition or false to indicate that the connection should be destroyed and a different connection should be
// acquired.
+ //
+ // Deprecated: Use PrepareConn instead. If both PrepareConn and BeforeAcquire are set, PrepareConn will take
+ // precedence, ignoring BeforeAcquire.
BeforeAcquire func(context.Context, *pgx.Conn) bool
+ // PrepareConn is called before a connection is acquired from the pool. If this function returns true, the connection
+ // is considered valid, otherwise the connection is destroyed. If the function returns a non-nil error, the instigating
+ // query will fail with the returned error.
+ //
+ // Specifically, this means that:
+ //
+ // - If it returns true and a nil error, the query proceeds as normal.
+ // - If it returns true and an error, the connection will be returned to the pool, and the instigating query will fail with the returned error.
+ // - If it returns false, and an error, the connection will be destroyed, and the query will fail with the returned error.
+ // - If it returns false and a nil error, the connection will be destroyed, and the instigating query will be retried on a new connection.
+ PrepareConn func(context.Context, *pgx.Conn) (bool, error)
+
// AfterRelease is called after a connection is released, but before it is returned to the pool. It must return true to
// return the connection to the pool or false to destroy the connection.
AfterRelease func(*pgx.Conn) bool
@@ -128,6 +152,10 @@ type Config struct {
// BeforeClose is called right before a connection is closed and removed from the pool.
BeforeClose func(*pgx.Conn)
+ // ShouldPing is called after a connection is acquired from the pool. If it returns true, the connection is pinged to check for liveness.
+ // If this func is not set, the default behavior is to ping connections that have been idle for at least 1 second.
+ ShouldPing func(context.Context, ShouldPingParams) bool
+
// MaxConnLifetime is the duration since creation after which a connection will be automatically closed.
MaxConnLifetime time.Duration
@@ -190,11 +218,18 @@ func NewWithConfig(ctx context.Context, config *Config) (*Pool, error) {
panic("config must be created by ParseConfig")
}
+ prepareConn := config.PrepareConn
+ if prepareConn == nil && config.BeforeAcquire != nil {
+ prepareConn = func(ctx context.Context, conn *pgx.Conn) (bool, error) {
+ return config.BeforeAcquire(ctx, conn), nil
+ }
+ }
+
p := &Pool{
config: config,
beforeConnect: config.BeforeConnect,
afterConnect: config.AfterConnect,
- beforeAcquire: config.BeforeAcquire,
+ prepareConn: prepareConn,
afterRelease: config.AfterRelease,
beforeClose: config.BeforeClose,
minConns: config.MinConns,
@@ -216,6 +251,14 @@ func NewWithConfig(ctx context.Context, config *Config) (*Pool, error) {
p.releaseTracer = t
}
+ if config.ShouldPing != nil {
+ p.shouldPing = config.ShouldPing
+ } else {
+ p.shouldPing = func(ctx context.Context, params ShouldPingParams) bool {
+ return params.IdleDuration > time.Second
+ }
+ }
+
var err error
p.p, err = puddle.NewPool(
&puddle.Config[*connResource]{
@@ -321,10 +364,10 @@ func ParseConfig(connString string) (*Config, error) {
delete(connConfig.Config.RuntimeParams, "pool_max_conns")
n, err := strconv.ParseInt(s, 10, 32)
if err != nil {
- return nil, fmt.Errorf("cannot parse pool_max_conns: %w", err)
+ return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_max_conns", err)
}
if n < 1 {
- return nil, fmt.Errorf("pool_max_conns too small: %d", n)
+ return nil, pgconn.NewParseConfigError(connString, "pool_max_conns too small", err)
}
config.MaxConns = int32(n)
} else {
@@ -338,7 +381,7 @@ func ParseConfig(connString string) (*Config, error) {
delete(connConfig.Config.RuntimeParams, "pool_min_conns")
n, err := strconv.ParseInt(s, 10, 32)
if err != nil {
- return nil, fmt.Errorf("cannot parse pool_min_conns: %w", err)
+ return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_min_conns", err)
}
config.MinConns = int32(n)
} else {
@@ -349,7 +392,7 @@ func ParseConfig(connString string) (*Config, error) {
delete(connConfig.Config.RuntimeParams, "pool_min_idle_conns")
n, err := strconv.ParseInt(s, 10, 32)
if err != nil {
- return nil, fmt.Errorf("cannot parse pool_min_idle_conns: %w", err)
+ return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_min_idle_conns", err)
}
config.MinIdleConns = int32(n)
} else {
@@ -360,7 +403,7 @@ func ParseConfig(connString string) (*Config, error) {
delete(connConfig.Config.RuntimeParams, "pool_max_conn_lifetime")
d, err := time.ParseDuration(s)
if err != nil {
- return nil, fmt.Errorf("invalid pool_max_conn_lifetime: %w", err)
+ return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_max_conn_lifetime", err)
}
config.MaxConnLifetime = d
} else {
@@ -371,7 +414,7 @@ func ParseConfig(connString string) (*Config, error) {
delete(connConfig.Config.RuntimeParams, "pool_max_conn_idle_time")
d, err := time.ParseDuration(s)
if err != nil {
- return nil, fmt.Errorf("invalid pool_max_conn_idle_time: %w", err)
+ return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_max_conn_idle_time", err)
}
config.MaxConnIdleTime = d
} else {
@@ -382,7 +425,7 @@ func ParseConfig(connString string) (*Config, error) {
delete(connConfig.Config.RuntimeParams, "pool_health_check_period")
d, err := time.ParseDuration(s)
if err != nil {
- return nil, fmt.Errorf("invalid pool_health_check_period: %w", err)
+ return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_health_check_period", err)
}
config.HealthCheckPeriod = d
} else {
@@ -393,7 +436,7 @@ func ParseConfig(connString string) (*Config, error) {
delete(connConfig.Config.RuntimeParams, "pool_max_conn_lifetime_jitter")
d, err := time.ParseDuration(s)
if err != nil {
- return nil, fmt.Errorf("invalid pool_max_conn_lifetime_jitter: %w", err)
+ return nil, pgconn.NewParseConfigError(connString, "cannot parse pool_max_conn_lifetime_jitter", err)
}
config.MaxConnLifetimeJitter = d
}
@@ -545,7 +588,10 @@ func (p *Pool) Acquire(ctx context.Context) (c *Conn, err error) {
}()
}
- for {
+ // Try to acquire from the connection pool up to maxConns + 1 times, so that
+ // any that fatal errors would empty the pool and still at least try 1 fresh
+ // connection.
+ for range p.maxConns + 1 {
res, err := p.p.Acquire(ctx)
if err != nil {
return nil, err
@@ -553,7 +599,8 @@ func (p *Pool) Acquire(ctx context.Context) (c *Conn, err error) {
cr := res.Value()
- if res.IdleDuration() > time.Second {
+ shouldPingParams := ShouldPingParams{Conn: cr.conn, IdleDuration: res.IdleDuration()}
+ if p.shouldPing(ctx, shouldPingParams) {
err := cr.conn.Ping(ctx)
if err != nil {
res.Destroy()
@@ -561,12 +608,25 @@ func (p *Pool) Acquire(ctx context.Context) (c *Conn, err error) {
}
}
- if p.beforeAcquire == nil || p.beforeAcquire(ctx, cr.conn) {
- return cr.getConn(p, res), nil
+ if p.prepareConn != nil {
+ ok, err := p.prepareConn(ctx, cr.conn)
+ if !ok {
+ res.Destroy()
+ }
+ if err != nil {
+ if ok {
+ res.Release()
+ }
+ return nil, err
+ }
+ if !ok {
+ continue
+ }
}
- res.Destroy()
+ return cr.getConn(p, res), nil
}
+ return nil, errors.New("pgxpool: detected infinite loop acquiring connection; likely bug in PrepareConn or BeforeAcquire hook")
}
// AcquireFunc acquires a *Conn and calls f with that *Conn. ctx will only affect the Acquire. It has no effect on the
@@ -589,11 +649,14 @@ func (p *Pool) AcquireAllIdle(ctx context.Context) []*Conn {
conns := make([]*Conn, 0, len(resources))
for _, res := range resources {
cr := res.Value()
- if p.beforeAcquire == nil || p.beforeAcquire(ctx, cr.conn) {
- conns = append(conns, cr.getConn(p, res))
- } else {
- res.Destroy()
+ if p.prepareConn != nil {
+ ok, err := p.prepareConn(ctx, cr.conn)
+ if !ok || err != nil {
+ res.Destroy()
+ continue
+ }
}
+ conns = append(conns, cr.getConn(p, res))
}
return conns