From 2c2668f4933129bbedf20bc68fb8b727799a447c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 7 Apr 2022 18:09:49 +0000 Subject: [PATCH] build(deps): bump github.com/jackc/pgx/v4 from 4.13.0 to 4.15.0 Bumps [github.com/jackc/pgx/v4](https://github.com/jackc/pgx) from 4.13.0 to 4.15.0. - [Release notes](https://github.com/jackc/pgx/releases) - [Changelog](https://github.com/jackc/pgx/blob/master/CHANGELOG.md) - [Commits](https://github.com/jackc/pgx/compare/v4.13.0...v4.15.0) --- updated-dependencies: - dependency-name: github.com/jackc/pgx/v4 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 15 +-- vendor/github.com/jackc/pgconn/CHANGELOG.md | 14 +++ vendor/github.com/jackc/pgconn/config.go | 90 ++++++++++++--- .../internal/ctxwatch/context_watcher.go | 13 ++- vendor/github.com/jackc/pgconn/pgconn.go | 107 +++++++++--------- .../github.com/jackc/pgconn/stmtcache/lru.go | 8 ++ .../github.com/jackc/pgproto3/v2/backend.go | 12 +- .../jackc/pgproto3/v2/function_call.go | 94 +++++++++++++++ .../pgproto3/v2/sasl_initial_response.go | 2 +- .../jackc/pgproto3/v2/sasl_response.go | 2 +- vendor/github.com/jackc/pgx/v4/CHANGELOG.md | 24 ++++ vendor/github.com/jackc/pgx/v4/README.md | 4 +- vendor/github.com/jackc/pgx/v4/batch.go | 63 +++++++++-- vendor/github.com/jackc/pgx/v4/conn.go | 22 +++- vendor/github.com/jackc/pgx/v4/doc.go | 2 +- .../jackc/pgx/v4/extended_query_builder.go | 33 +++--- vendor/github.com/jackc/pgx/v4/go.mod | 8 +- vendor/github.com/jackc/pgx/v4/go.sum | 18 +++ .../jackc/pgx/v4/pgxpool/batch_results.go | 8 ++ .../github.com/jackc/pgx/v4/pgxpool/conn.go | 2 + .../github.com/jackc/pgx/v4/pgxpool/pool.go | 78 ++++++++++++- .../github.com/jackc/pgx/v4/pgxpool/stat.go | 3 +- vendor/github.com/jackc/pgx/v4/pgxpool/tx.go | 15 +++ vendor/github.com/jackc/pgx/v4/rows.go | 7 +- vendor/github.com/jackc/pgx/v4/tx.go | 24 ++-- vendor/github.com/jackc/puddle/CHANGELOG.md | 14 +++ vendor/github.com/jackc/puddle/pool.go | 63 ++++++++++- vendor/modules.txt | 8 +- 29 files changed, 605 insertions(+), 150 deletions(-) create mode 100644 vendor/github.com/jackc/pgproto3/v2/function_call.go diff --git a/go.mod b/go.mod index a5a87376c..91178a3fb 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/gophercloud/gophercloud v0.22.0 github.com/hashicorp/go-retryablehttp v0.7.0 github.com/jackc/pgtype v1.10.0 - github.com/jackc/pgx/v4 v4.13.0 + github.com/jackc/pgx/v4 v4.15.0 github.com/julienschmidt/httprouter v1.3.0 github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b github.com/labstack/echo/v4 v4.6.1 diff --git a/go.sum b/go.sum index 422d3d8b9..fddb7a343 100644 --- a/go.sum +++ b/go.sum @@ -381,8 +381,8 @@ github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfG github.com/jackc/pgconn v1.8.1/go.mod h1:JV6m6b6jhjdmzchES0drzCcYcAHS1OPD5xu3OZ/lE2g= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.10.0 h1:4EYhlDVEMsJ30nNj0mmgwIUXoq7e9sMJrVC2ED6QlCU= -github.com/jackc/pgconn v1.10.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.11.0 h1:HiHArx4yFbwl91X3qqIHtUFoiIfLNJXCQRsnzkiwwaQ= +github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -399,8 +399,9 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1 h1:7PQ/4gLoqnl87ZxL7xjO0DR5gYuviDCZxQJsUlFW1eI= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns= +github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= @@ -413,7 +414,6 @@ github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/V github.com/jackc/pgtype v1.7.0/go.mod h1:ZnHF+rMePVqDKaOfJVI4Q8IVvAQMryDlDkZnKOI75BE= github.com/jackc/pgtype v1.8.0/go.mod h1:PqDKcEBtllAtk/2p6z6SHdXW5UB+MhE75tUol2OKexE= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.8.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgtype v1.10.0 h1:ILnBWrRMSXGczYvmkYD6PsYyVFUNLTnIUJHHDLmqk38= github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= @@ -425,14 +425,15 @@ github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9s github.com/jackc/pgx/v4 v4.11.0/go.mod h1:i62xJgdrtVDsnL3U8ekyrQXEwGNTRoG7/8r+CIdYfcc= github.com/jackc/pgx/v4 v4.12.0/go.mod h1:fE547h6VulLPA3kySjfnSG/e2D861g/50JlVUa/ub60= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.13.0 h1:JCjhT5vmhMAf/YwBHLvrBn4OGdIQBiFG6ym8Zmdx570= -github.com/jackc/pgx/v4 v4.13.0/go.mod h1:9P4X524sErlaxj0XSGZk7s+LD0eOyu1ZDUrrpznYDF0= +github.com/jackc/pgx/v4 v4.15.0 h1:B7dTkXsdILD3MF987WGGCcg+tvLW6bZJdEcqVFeU//w= +github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3 h1:JnPg/5Q9xVJGfjsO5CPUOjnJps1JaRUm8I9FXVCFK94= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.2.1 h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw= +github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= diff --git a/vendor/github.com/jackc/pgconn/CHANGELOG.md b/vendor/github.com/jackc/pgconn/CHANGELOG.md index 45c02f1e9..a37eecfe1 100644 --- a/vendor/github.com/jackc/pgconn/CHANGELOG.md +++ b/vendor/github.com/jackc/pgconn/CHANGELOG.md @@ -1,3 +1,17 @@ +# 1.11.0 (February 7, 2022) + +* Support port in ip from LookupFunc to override config (James Hartig) +* Fix TLS connection timeout (Blake Embrey) +* Add support for read-only, primary, standby, prefer-standby target_session_attributes (Oscar) +* Fix connect when receiving NoticeResponse + +# 1.10.1 (November 20, 2021) + +* Close without waiting for response (Kei Kamikawa) +* Save waiting for network round-trip in CopyFrom (Rueian) +* Fix concurrency issue with ContextWatcher +* LRU.Get always checks context for cancellation / expiration (Georges Varouchas) + # 1.10.0 (July 24, 2021) * net.Timeout errors are no longer returned when a query is canceled via context. A wrapped context error is returned. diff --git a/vendor/github.com/jackc/pgconn/config.go b/vendor/github.com/jackc/pgconn/config.go index 172e7478b..0eab23af9 100644 --- a/vendor/github.com/jackc/pgconn/config.go +++ b/vendor/github.com/jackc/pgconn/config.go @@ -248,21 +248,21 @@ func ParseConfig(connString string) (*Config, error) { config.LookupFunc = makeDefaultResolver().LookupHost notRuntimeParams := map[string]struct{}{ - "host": struct{}{}, - "port": struct{}{}, - "database": struct{}{}, - "user": struct{}{}, - "password": struct{}{}, - "passfile": struct{}{}, - "connect_timeout": struct{}{}, - "sslmode": struct{}{}, - "sslkey": struct{}{}, - "sslcert": struct{}{}, - "sslrootcert": struct{}{}, - "target_session_attrs": struct{}{}, - "min_read_buffer_size": struct{}{}, - "service": struct{}{}, - "servicefile": struct{}{}, + "host": {}, + "port": {}, + "database": {}, + "user": {}, + "password": {}, + "passfile": {}, + "connect_timeout": {}, + "sslmode": {}, + "sslkey": {}, + "sslcert": {}, + "sslrootcert": {}, + "target_session_attrs": {}, + "min_read_buffer_size": {}, + "service": {}, + "servicefile": {}, } for k, v := range settings { @@ -329,10 +329,19 @@ func ParseConfig(connString string) (*Config, error) { } } - if settings["target_session_attrs"] == "read-write" { + switch tsa := settings["target_session_attrs"]; tsa { + case "read-write": config.ValidateConnect = ValidateConnectTargetSessionAttrsReadWrite - } else if settings["target_session_attrs"] != "any" { - return nil, &parseConfigError{connString: connString, msg: fmt.Sprintf("unknown target_session_attrs value: %v", settings["target_session_attrs"])} + case "read-only": + config.ValidateConnect = ValidateConnectTargetSessionAttrsReadOnly + case "primary": + config.ValidateConnect = ValidateConnectTargetSessionAttrsPrimary + case "standby": + config.ValidateConnect = ValidateConnectTargetSessionAttrsStandby + case "any", "prefer-standby": + // do nothing + default: + return nil, &parseConfigError{connString: connString, msg: fmt.Sprintf("unknown target_session_attrs value: %v", tsa)} } return config, nil @@ -727,3 +736,48 @@ func ValidateConnectTargetSessionAttrsReadWrite(ctx context.Context, pgConn *PgC return nil } + +// ValidateConnectTargetSessionAttrsReadOnly is an ValidateConnectFunc that implements libpq compatible +// target_session_attrs=read-only. +func ValidateConnectTargetSessionAttrsReadOnly(ctx context.Context, pgConn *PgConn) error { + result := pgConn.ExecParams(ctx, "show transaction_read_only", nil, nil, nil, nil).Read() + if result.Err != nil { + return result.Err + } + + if string(result.Rows[0][0]) != "on" { + return errors.New("connection is not read only") + } + + return nil +} + +// ValidateConnectTargetSessionAttrsStandby is an ValidateConnectFunc that implements libpq compatible +// target_session_attrs=standby. +func ValidateConnectTargetSessionAttrsStandby(ctx context.Context, pgConn *PgConn) error { + result := pgConn.ExecParams(ctx, "select pg_is_in_recovery()", nil, nil, nil, nil).Read() + if result.Err != nil { + return result.Err + } + + if string(result.Rows[0][0]) != "t" { + return errors.New("server is not in hot standby mode") + } + + return nil +} + +// ValidateConnectTargetSessionAttrsPrimary is an ValidateConnectFunc that implements libpq compatible +// target_session_attrs=primary. +func ValidateConnectTargetSessionAttrsPrimary(ctx context.Context, pgConn *PgConn) error { + result := pgConn.ExecParams(ctx, "select pg_is_in_recovery()", nil, nil, nil, nil).Read() + if result.Err != nil { + return result.Err + } + + if string(result.Rows[0][0]) == "t" { + return errors.New("server is in standby mode") + } + + return nil +} diff --git a/vendor/github.com/jackc/pgconn/internal/ctxwatch/context_watcher.go b/vendor/github.com/jackc/pgconn/internal/ctxwatch/context_watcher.go index 391f0b791..b39cb3ee5 100644 --- a/vendor/github.com/jackc/pgconn/internal/ctxwatch/context_watcher.go +++ b/vendor/github.com/jackc/pgconn/internal/ctxwatch/context_watcher.go @@ -2,6 +2,7 @@ package ctxwatch import ( "context" + "sync" ) // ContextWatcher watches a context and performs an action when the context is canceled. It can watch one context at a @@ -10,8 +11,10 @@ type ContextWatcher struct { onCancel func() onUnwatchAfterCancel func() unwatchChan chan struct{} - watchInProgress bool - onCancelWasCalled bool + + lock sync.Mutex + watchInProgress bool + onCancelWasCalled bool } // NewContextWatcher returns a ContextWatcher. onCancel will be called when a watched context is canceled. @@ -29,6 +32,9 @@ func NewContextWatcher(onCancel func(), onUnwatchAfterCancel func()) *ContextWat // Watch starts watching ctx. If ctx is canceled then the onCancel function passed to NewContextWatcher will be called. func (cw *ContextWatcher) Watch(ctx context.Context) { + cw.lock.Lock() + defer cw.lock.Unlock() + if cw.watchInProgress { panic("Watch already in progress") } @@ -54,6 +60,9 @@ func (cw *ContextWatcher) Watch(ctx context.Context) { // Unwatch stops watching the previously watched context. If the onCancel function passed to NewContextWatcher was // called then onUnwatchAfterCancel will also be called. func (cw *ContextWatcher) Unwatch() { + cw.lock.Lock() + defer cw.lock.Unlock() + if cw.watchInProgress { cw.unwatchChan <- struct{}{} if cw.onCancelWasCalled { diff --git a/vendor/github.com/jackc/pgconn/pgconn.go b/vendor/github.com/jackc/pgconn/pgconn.go index 43b13e43a..7bf2f20ef 100644 --- a/vendor/github.com/jackc/pgconn/pgconn.go +++ b/vendor/github.com/jackc/pgconn/pgconn.go @@ -11,6 +11,7 @@ import ( "io" "math" "net" + "strconv" "strings" "sync" "time" @@ -44,7 +45,8 @@ type Notification struct { // DialFunc is a function that can be used to connect to a PostgreSQL server. type DialFunc func(ctx context.Context, network, addr string) (net.Conn, error) -// LookupFunc is a function that can be used to lookup IPs addrs from host. +// LookupFunc is a function that can be used to lookup IPs addrs from host. Optionally an ip:port combination can be +// returned in order to override the connection string's port. type LookupFunc func(ctx context.Context, host string) (addrs []string, err error) // BuildFrontendFunc is a function that can be used to create Frontend implementation for connection. @@ -196,11 +198,24 @@ func expandWithIPs(ctx context.Context, lookupFn LookupFunc, fallbacks []*Fallba } for _, ip := range ips { - configs = append(configs, &FallbackConfig{ - Host: ip, - Port: fb.Port, - TLSConfig: fb.TLSConfig, - }) + splitIP, splitPort, err := net.SplitHostPort(ip) + if err == nil { + port, err := strconv.ParseUint(splitPort, 10, 16) + if err != nil { + return nil, fmt.Errorf("error parsing port (%s) from lookup: %w", splitPort, err) + } + configs = append(configs, &FallbackConfig{ + Host: splitIP, + Port: uint16(port), + TLSConfig: fb.TLSConfig, + }) + } else { + configs = append(configs, &FallbackConfig{ + Host: ip, + Port: fb.Port, + TLSConfig: fb.TLSConfig, + }) + } } } @@ -215,7 +230,7 @@ func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig var err error network, address := NetworkAddress(fallbackConfig.Host, fallbackConfig.Port) - pgConn.conn, err = config.DialFunc(ctx, network, address) + netConn, err := config.DialFunc(ctx, network, address) if err != nil { var netErr net.Error if errors.As(err, &netErr) && netErr.Timeout() { @@ -224,24 +239,27 @@ func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig return nil, &connectError{config: config, msg: "dial error", err: err} } - pgConn.parameterStatuses = make(map[string]string) + pgConn.conn = netConn + pgConn.contextWatcher = newContextWatcher(netConn) + pgConn.contextWatcher.Watch(ctx) if fallbackConfig.TLSConfig != nil { - if err := pgConn.startTLS(fallbackConfig.TLSConfig); err != nil { - pgConn.conn.Close() + tlsConn, err := startTLS(netConn, fallbackConfig.TLSConfig) + pgConn.contextWatcher.Unwatch() // Always unwatch `netConn` after TLS. + if err != nil { + netConn.Close() return nil, &connectError{config: config, msg: "tls error", err: err} } + + pgConn.conn = tlsConn + pgConn.contextWatcher = newContextWatcher(tlsConn) + pgConn.contextWatcher.Watch(ctx) } - pgConn.status = connStatusConnecting - pgConn.contextWatcher = ctxwatch.NewContextWatcher( - func() { pgConn.conn.SetDeadline(time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC)) }, - func() { pgConn.conn.SetDeadline(time.Time{}) }, - ) - - pgConn.contextWatcher.Watch(ctx) defer pgConn.contextWatcher.Unwatch() + pgConn.parameterStatuses = make(map[string]string) + pgConn.status = connStatusConnecting pgConn.frontend = config.BuildFrontend(pgConn.conn, pgConn.conn) startupMsg := pgproto3.StartupMessage{ @@ -317,7 +335,7 @@ func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig } } return pgConn, nil - case *pgproto3.ParameterStatus: + case *pgproto3.ParameterStatus, *pgproto3.NoticeResponse: // handled by ReceiveMessage case *pgproto3.ErrorResponse: pgConn.conn.Close() @@ -329,24 +347,29 @@ func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig } } -func (pgConn *PgConn) startTLS(tlsConfig *tls.Config) (err error) { - err = binary.Write(pgConn.conn, binary.BigEndian, []int32{8, 80877103}) +func newContextWatcher(conn net.Conn) *ctxwatch.ContextWatcher { + return ctxwatch.NewContextWatcher( + func() { conn.SetDeadline(time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC)) }, + func() { conn.SetDeadline(time.Time{}) }, + ) +} + +func startTLS(conn net.Conn, tlsConfig *tls.Config) (net.Conn, error) { + err := binary.Write(conn, binary.BigEndian, []int32{8, 80877103}) if err != nil { - return + return nil, err } response := make([]byte, 1) - if _, err = io.ReadFull(pgConn.conn, response); err != nil { - return + if _, err = io.ReadFull(conn, response); err != nil { + return nil, err } if response[0] != 'S' { - return errors.New("server refused TLS connection") + return nil, errors.New("server refused TLS connection") } - pgConn.conn = tls.Client(pgConn.conn, tlsConfig) - - return nil + return tls.Client(conn, tlsConfig), nil } func (pgConn *PgConn) txPasswordMessage(password string) (err error) { @@ -578,7 +601,6 @@ func (pgConn *PgConn) Close(ctx context.Context) error { // // See https://github.com/jackc/pgx/issues/637 pgConn.conn.Write([]byte{'X', 0, 0, 0, 4}) - pgConn.conn.Read(make([]byte, 1)) return pgConn.conn.Close() } @@ -605,7 +627,6 @@ func (pgConn *PgConn) asyncClose() { pgConn.conn.SetDeadline(deadline) pgConn.conn.Write([]byte{'X', 0, 0, 0, 4}) - pgConn.conn.Read(make([]byte, 1)) }() } @@ -1187,27 +1208,6 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co return nil, &writeError{err: err, safeToRetry: n == 0} } - // Read until copy in response or error. - var commandTag CommandTag - var pgErr error - pendingCopyInResponse := true - for pendingCopyInResponse { - msg, err := pgConn.receiveMessage() - if err != nil { - pgConn.asyncClose() - return nil, preferContextOverNetTimeoutError(ctx, err) - } - - switch msg := msg.(type) { - case *pgproto3.CopyInResponse: - pendingCopyInResponse = false - case *pgproto3.ErrorResponse: - pgErr = ErrorResponseToPgError(msg) - case *pgproto3.ReadyForQuery: - return commandTag, pgErr - } - } - // Send copy data abortCopyChan := make(chan struct{}) copyErrChan := make(chan error, 1) @@ -1246,6 +1246,7 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co } }() + var pgErr error var copyErr error for copyErr == nil && pgErr == nil { select { @@ -1282,6 +1283,7 @@ func (pgConn *PgConn) CopyFrom(ctx context.Context, r io.Reader, sql string) (Co } // Read results + var commandTag CommandTag for { msg, err := pgConn.receiveMessage() if err != nil { @@ -1715,10 +1717,7 @@ func Construct(hc *HijackedConn) (*PgConn, error) { cleanupDone: make(chan struct{}), } - pgConn.contextWatcher = ctxwatch.NewContextWatcher( - func() { pgConn.conn.SetDeadline(time.Date(1, 1, 1, 1, 1, 1, 1, time.UTC)) }, - func() { pgConn.conn.SetDeadline(time.Time{}) }, - ) + pgConn.contextWatcher = newContextWatcher(pgConn.conn) return pgConn, nil } diff --git a/vendor/github.com/jackc/pgconn/stmtcache/lru.go b/vendor/github.com/jackc/pgconn/stmtcache/lru.go index f58f2ac34..90fb76c2f 100644 --- a/vendor/github.com/jackc/pgconn/stmtcache/lru.go +++ b/vendor/github.com/jackc/pgconn/stmtcache/lru.go @@ -42,6 +42,14 @@ func NewLRU(conn *pgconn.PgConn, mode int, cap int) *LRU { // Get returns the prepared statement description for sql preparing or describing the sql on the server as needed. func (c *LRU) Get(ctx context.Context, sql string) (*pgconn.StatementDescription, error) { + if ctx != context.Background() { + select { + case <-ctx.Done(): + return nil, ctx.Err() + default: + } + } + // flush an outstanding bad statements txStatus := c.conn.TxStatus() if (txStatus == 'I' || txStatus == 'T') && len(c.stmtsToClear) > 0 { diff --git a/vendor/github.com/jackc/pgproto3/v2/backend.go b/vendor/github.com/jackc/pgproto3/v2/backend.go index e9ba38fc3..9c42ad02e 100644 --- a/vendor/github.com/jackc/pgproto3/v2/backend.go +++ b/vendor/github.com/jackc/pgproto3/v2/backend.go @@ -21,6 +21,7 @@ type Backend struct { describe Describe execute Execute flush Flush + functionCall FunctionCall gssEncRequest GSSEncRequest parse Parse query Query @@ -29,10 +30,11 @@ type Backend struct { sync Sync terminate Terminate - bodyLen int - msgType byte - partialMsg bool - authType uint32 + bodyLen int + msgType byte + partialMsg bool + authType uint32 + } const ( @@ -125,6 +127,8 @@ func (b *Backend) Receive() (FrontendMessage, error) { msg = &b.describe case 'E': msg = &b.execute + case 'F': + msg = &b.functionCall case 'f': msg = &b.copyFail case 'd': diff --git a/vendor/github.com/jackc/pgproto3/v2/function_call.go b/vendor/github.com/jackc/pgproto3/v2/function_call.go new file mode 100644 index 000000000..b3a22c4fb --- /dev/null +++ b/vendor/github.com/jackc/pgproto3/v2/function_call.go @@ -0,0 +1,94 @@ +package pgproto3 + +import ( + "encoding/binary" + "github.com/jackc/pgio" +) + +type FunctionCall struct { + Function uint32 + ArgFormatCodes []uint16 + Arguments [][]byte + ResultFormatCode uint16 +} + +// Frontend identifies this message as sendable by a PostgreSQL frontend. +func (*FunctionCall) Frontend() {} + +// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message +// type identifier and 4 byte message length. +func (dst *FunctionCall) Decode(src []byte) error { + *dst = FunctionCall{} + rp := 0 + // Specifies the object ID of the function to call. + dst.Function = binary.BigEndian.Uint32(src[rp:]) + rp += 4 + // The number of argument format codes that follow (denoted C below). + // This can be zero to indicate that there are no arguments or that the arguments all use the default format (text); + // or one, in which case the specified format code is applied to all arguments; + // or it can equal the actual number of arguments. + nArgumentCodes := int(binary.BigEndian.Uint16(src[rp:])) + rp += 2 + argumentCodes := make([]uint16, nArgumentCodes) + for i := 0; i < nArgumentCodes; i++ { + // The argument format codes. Each must presently be zero (text) or one (binary). + ac := binary.BigEndian.Uint16(src[rp:]) + if ac != 0 && ac != 1 { + return &invalidMessageFormatErr{messageType: "FunctionCall"} + } + argumentCodes[i] = ac + rp += 2 + } + dst.ArgFormatCodes = argumentCodes + + // Specifies the number of arguments being supplied to the function. + nArguments := int(binary.BigEndian.Uint16(src[rp:])) + rp += 2 + arguments := make([][]byte, nArguments) + for i := 0; i < nArguments; i++ { + // The length of the argument value, in bytes (this count does not include itself). Can be zero. + // As a special case, -1 indicates a NULL argument value. No value bytes follow in the NULL case. + argumentLength := int(binary.BigEndian.Uint32(src[rp:])) + rp += 4 + if argumentLength == -1 { + arguments[i] = nil + } else { + // The value of the argument, in the format indicated by the associated format code. n is the above length. + argumentValue := src[rp : rp+argumentLength] + rp += argumentLength + arguments[i] = argumentValue + } + } + dst.Arguments = arguments + // The format code for the function result. Must presently be zero (text) or one (binary). + resultFormatCode := binary.BigEndian.Uint16(src[rp:]) + if resultFormatCode != 0 && resultFormatCode != 1 { + return &invalidMessageFormatErr{messageType: "FunctionCall"} + } + dst.ResultFormatCode = resultFormatCode + return nil +} + +// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length. +func (src *FunctionCall) Encode(dst []byte) []byte { + dst = append(dst, 'F') + sp := len(dst) + dst = pgio.AppendUint32(dst, 0) // Unknown length, set it at the end + dst = pgio.AppendUint32(dst, src.Function) + dst = pgio.AppendUint16(dst, uint16(len(src.ArgFormatCodes))) + for _, argFormatCode := range src.ArgFormatCodes { + dst = pgio.AppendUint16(dst, argFormatCode) + } + dst = pgio.AppendUint16(dst, uint16(len(src.Arguments))) + for _, argument := range src.Arguments { + if argument == nil { + dst = pgio.AppendInt32(dst, -1) + } else { + dst = pgio.AppendInt32(dst, int32(len(argument))) + dst = append(dst, argument...) + } + } + dst = pgio.AppendUint16(dst, src.ResultFormatCode) + pgio.SetInt32(dst[sp:], int32(len(dst[sp:]))) + return dst +} diff --git a/vendor/github.com/jackc/pgproto3/v2/sasl_initial_response.go b/vendor/github.com/jackc/pgproto3/v2/sasl_initial_response.go index f7e5f36a9..f862f2a85 100644 --- a/vendor/github.com/jackc/pgproto3/v2/sasl_initial_response.go +++ b/vendor/github.com/jackc/pgproto3/v2/sasl_initial_response.go @@ -64,7 +64,7 @@ func (src SASLInitialResponse) MarshalJSON() ([]byte, error) { }{ Type: "SASLInitialResponse", AuthMechanism: src.AuthMechanism, - Data: hex.EncodeToString(src.Data), + Data: string(src.Data), }) } diff --git a/vendor/github.com/jackc/pgproto3/v2/sasl_response.go b/vendor/github.com/jackc/pgproto3/v2/sasl_response.go index 41fb4c397..d402759a5 100644 --- a/vendor/github.com/jackc/pgproto3/v2/sasl_response.go +++ b/vendor/github.com/jackc/pgproto3/v2/sasl_response.go @@ -38,7 +38,7 @@ func (src SASLResponse) MarshalJSON() ([]byte, error) { Data string }{ Type: "SASLResponse", - Data: hex.EncodeToString(src.Data), + Data: string(src.Data), }) } diff --git a/vendor/github.com/jackc/pgx/v4/CHANGELOG.md b/vendor/github.com/jackc/pgx/v4/CHANGELOG.md index ef4a2029a..4dd93b30e 100644 --- a/vendor/github.com/jackc/pgx/v4/CHANGELOG.md +++ b/vendor/github.com/jackc/pgx/v4/CHANGELOG.md @@ -1,3 +1,27 @@ +# 4.15.0 (February 7, 2022) + +* Upgrade to pgconn v1.11.0 +* Upgrade to pgtype v1.10.0 +* Upgrade puddle to v1.2.1 +* Make BatchResults.Close safe to be called multiple times + +# 4.14.1 (November 28, 2021) + +* Upgrade pgtype to v1.9.1 (fixes unintentional change to timestamp binary decoding) +* Start pgxpool background health check after initial connections + +# 4.14.0 (November 20, 2021) + +* Upgrade pgconn to v1.10.1 +* Upgrade pgproto3 to v2.2.0 +* Upgrade pgtype to v1.9.0 +* Upgrade puddle to v1.2.0 +* Add QueryFunc to BatchResults +* Add context options to zerologadapter (Thomas Frössman) +* Add zerologadapter.NewContextLogger (urso) +* Eager initialize minpoolsize on connect (Daniel) +* Unpin memory used by large queries immediately after use + # 4.13.0 (July 24, 2021) * Trimmed pseudo-dependencies in Go modules from other packages tests diff --git a/vendor/github.com/jackc/pgx/v4/README.md b/vendor/github.com/jackc/pgx/v4/README.md index 732320447..110d4f02e 100644 --- a/vendor/github.com/jackc/pgx/v4/README.md +++ b/vendor/github.com/jackc/pgx/v4/README.md @@ -73,7 +73,7 @@ pgx supports many features beyond what is available through `database/sql`: * Single-round trip query mode * Full TLS connection control * Binary format support for custom types (allows for much quicker encoding/decoding) -* Copy protocol support for faster bulk data loads +* COPY protocol support for faster bulk data loads * Extendable logging support including built-in support for `log15adapter`, [`logrus`](https://github.com/sirupsen/logrus), [`zap`](https://github.com/uber-go/zap), and [`zerolog`](https://github.com/rs/zerolog) * Connection pool with after-connect hook for arbitrary connection setup * Listen / notify @@ -149,7 +149,7 @@ In addition, there are tests specific for PgBouncer that will be executed if `PG ## Supported Go and PostgreSQL Versions -pgx supports the same versions of Go and PostgreSQL that are supported by their respective teams. For [Go](https://golang.org/doc/devel/release.html#policy) that is the two most recent major releases and for [PostgreSQL](https://www.postgresql.org/support/versioning/) the major releases in the last 5 years. This means pgx supports Go 1.15 and higher and PostgreSQL 9.6 and higher. pgx also is tested against the latest version of [CockroachDB](https://www.cockroachlabs.com/product/). +pgx supports the same versions of Go and PostgreSQL that are supported by their respective teams. For [Go](https://golang.org/doc/devel/release.html#policy) that is the two most recent major releases and for [PostgreSQL](https://www.postgresql.org/support/versioning/) the major releases in the last 5 years. This means pgx supports Go 1.16 and higher and PostgreSQL 10 and higher. pgx also is tested against the latest version of [CockroachDB](https://www.cockroachlabs.com/product/). ## Version Policy diff --git a/vendor/github.com/jackc/pgx/v4/batch.go b/vendor/github.com/jackc/pgx/v4/batch.go index 4b96ca194..7f86ad5c3 100644 --- a/vendor/github.com/jackc/pgx/v4/batch.go +++ b/vendor/github.com/jackc/pgx/v4/batch.go @@ -3,6 +3,7 @@ package pgx import ( "context" "errors" + "fmt" "github.com/jackc/pgconn" ) @@ -41,19 +42,23 @@ type BatchResults interface { // QueryRow reads the results from the next query in the batch as if the query has been sent with Conn.QueryRow. QueryRow() Row + // QueryFunc reads the results from the next query in the batch as if the query has been sent with Conn.QueryFunc. + QueryFunc(scans []interface{}, f func(QueryFuncRow) error) (pgconn.CommandTag, error) + // Close closes the batch operation. This must be called before the underlying connection can be used again. Any error // that occurred during a batch operation may have made it impossible to resyncronize the connection with the server. - // In this case the underlying connection will have been closed. + // In this case the underlying connection will have been closed. Close is safe to call multiple times. Close() error } type batchResults struct { - ctx context.Context - conn *Conn - mrr *pgconn.MultiResultReader - err error - b *Batch - ix int + ctx context.Context + conn *Conn + mrr *pgconn.MultiResultReader + err error + b *Batch + ix int + closed bool } // Exec reads the results from the next query in the batch as if the query has been sent with Exec. @@ -61,6 +66,9 @@ func (br *batchResults) Exec() (pgconn.CommandTag, error) { if br.err != nil { return nil, br.err } + if br.closed { + return nil, fmt.Errorf("batch already closed") + } query, arguments, _ := br.nextQueryAndArgs() @@ -111,6 +119,11 @@ func (br *batchResults) Query() (Rows, error) { return &connRows{err: br.err, closed: true}, br.err } + if br.closed { + alreadyClosedErr := fmt.Errorf("batch already closed") + return &connRows{err: alreadyClosedErr, closed: true}, alreadyClosedErr + } + rows := br.conn.getRows(br.ctx, query, arguments) if !br.mrr.NextResult() { @@ -135,6 +148,37 @@ func (br *batchResults) Query() (Rows, error) { return rows, nil } +// QueryFunc reads the results from the next query in the batch as if the query has been sent with Conn.QueryFunc. +func (br *batchResults) QueryFunc(scans []interface{}, f func(QueryFuncRow) error) (pgconn.CommandTag, error) { + if br.closed { + return nil, fmt.Errorf("batch already closed") + } + + rows, err := br.Query() + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + err = rows.Scan(scans...) + if err != nil { + return nil, err + } + + err = f(rows) + if err != nil { + return nil, err + } + } + + if err := rows.Err(); err != nil { + return nil, err + } + + return rows.CommandTag(), nil +} + // QueryRow reads the results from the next query in the batch as if the query has been sent with QueryRow. func (br *batchResults) QueryRow() Row { rows, _ := br.Query() @@ -149,6 +193,11 @@ func (br *batchResults) Close() error { return br.err } + if br.closed { + return nil + } + br.closed = true + // log any queries that haven't yet been logged by Exec or Query for { query, args, ok := br.nextQueryAndArgs() diff --git a/vendor/github.com/jackc/pgx/v4/conn.go b/vendor/github.com/jackc/pgx/v4/conn.go index 9636f2fd6..102158ab5 100644 --- a/vendor/github.com/jackc/pgx/v4/conn.go +++ b/vendor/github.com/jackc/pgx/v4/conn.go @@ -50,6 +50,7 @@ func (cc *ConnConfig) Copy() *ConnConfig { return newConfig } +// ConnString returns the connection string as parsed by pgx.ParseConfig into pgx.ConnConfig. func (cc *ConnConfig) ConnString() string { return cc.connString } // BuildStatementCacheFunc is a function that can be used to create a stmtcache.Cache implementation for connection. @@ -107,8 +108,8 @@ func Connect(ctx context.Context, connString string) (*Conn, error) { return connect(ctx, connConfig) } -// Connect establishes a connection with a PostgreSQL server with a configuration struct. connConfig must have been -// created by ParseConfig. +// ConnectConfig establishes a connection with a PostgreSQL server with a configuration struct. +// connConfig must have been created by ParseConfig. func ConnectConfig(ctx context.Context, connConfig *ConnConfig) (*Conn, error) { return connect(ctx, connConfig) } @@ -324,6 +325,7 @@ func (c *Conn) WaitForNotification(ctx context.Context) (*pgconn.Notification, e return n, err } +// IsClosed reports if the connection has been closed. func (c *Conn) IsClosed() bool { return c.pgConn.IsClosed() } @@ -357,6 +359,8 @@ func quoteIdentifier(s string) string { return `"` + strings.ReplaceAll(s, `"`, `""`) + `"` } +// Ping executes an empty sql statement against the *Conn +// If the sql returns without error, the database Ping is considered successful, otherwise, the error is returned. func (c *Conn) Ping(ctx context.Context) error { _, err := c.Exec(ctx, ";") return err @@ -517,6 +521,7 @@ func (c *Conn) execParams(ctx context.Context, sd *pgconn.StatementDescription, } result := c.pgConn.ExecParams(ctx, sd.SQL, c.eqb.paramValues, sd.ParamOIDs, c.eqb.paramFormats, c.eqb.resultFormats).Read() + c.eqb.Reset() // Allow c.eqb internal memory to be GC'ed as soon as possible. return result.CommandTag, result.Err } @@ -527,6 +532,7 @@ func (c *Conn) execPrepared(ctx context.Context, sd *pgconn.StatementDescription } result := c.pgConn.ExecPrepared(ctx, sd.Name, c.eqb.paramValues, c.eqb.paramFormats, c.eqb.resultFormats).Read() + c.eqb.Reset() // Allow c.eqb internal memory to be GC'ed as soon as possible. return result.CommandTag, result.Err } @@ -558,8 +564,12 @@ type QueryResultFormats []int16 // QueryResultFormatsByOID controls the result format (text=0, binary=1) of a query by the result column OID. type QueryResultFormatsByOID map[uint32]int16 -// Query executes sql with args. If there is an error the returned Rows will be returned in an error state. So it is -// allowed to ignore the error returned from Query and handle it in Rows. +// Query executes sql with args. It is safe to attempt to read from the returned Rows even if an error is returned. The +// error will be the available in rows.Err() after rows are closed. So it is allowed to ignore the error returned from +// Query and handle it in Rows. +// +// Err() on the returned Rows must be checked after the Rows is closed to determine if the query executed successfully +// as some errors can only be detected by reading the entire response. e.g. A divide by zero error on the last row. // // For extra control over how the query is executed, the types QuerySimpleProtocol, QueryResultFormats, and // QueryResultFormatsByOID may be used as the first args to control exactly how the query is executed. This is rarely @@ -670,6 +680,8 @@ optionLoop: rows.resultReader = c.pgConn.ExecPrepared(ctx, sd.Name, c.eqb.paramValues, c.eqb.paramFormats, resultFormats) } + c.eqb.Reset() // Allow c.eqb internal memory to be GC'ed as soon as possible. + return rows, rows.err } @@ -817,6 +829,8 @@ func (c *Conn) SendBatch(ctx context.Context, b *Batch) BatchResults { } } + c.eqb.Reset() // Allow c.eqb internal memory to be GC'ed as soon as possible. + mrr := c.pgConn.ExecBatch(ctx, batch) return &batchResults{ diff --git a/vendor/github.com/jackc/pgx/v4/doc.go b/vendor/github.com/jackc/pgx/v4/doc.go index 51b0d9f44..222f90479 100644 --- a/vendor/github.com/jackc/pgx/v4/doc.go +++ b/vendor/github.com/jackc/pgx/v4/doc.go @@ -309,7 +309,7 @@ CopyFrom can be faster than an insert with as few as 5 rows. Listen and Notify pgx can listen to the PostgreSQL notification system with the `Conn.WaitForNotification` method. It blocks until a -context is received or the context is canceled. +notification is received or the context is canceled. _, err := conn.Exec(context.Background(), "listen channelname") if err != nil { diff --git a/vendor/github.com/jackc/pgx/v4/extended_query_builder.go b/vendor/github.com/jackc/pgx/v4/extended_query_builder.go index 09419f0d0..d06f63fd1 100644 --- a/vendor/github.com/jackc/pgx/v4/extended_query_builder.go +++ b/vendor/github.com/jackc/pgx/v4/extended_query_builder.go @@ -13,8 +13,6 @@ type extendedQueryBuilder struct { paramValueBytes []byte paramFormats []int16 resultFormats []int16 - - resetCount int } func (eqb *extendedQueryBuilder) AppendParam(ci *pgtype.ConnInfo, oid uint32, arg interface{}) error { @@ -34,32 +32,27 @@ func (eqb *extendedQueryBuilder) AppendResultFormat(f int16) { eqb.resultFormats = append(eqb.resultFormats, f) } +// Reset readies eqb to build another query. func (eqb *extendedQueryBuilder) Reset() { eqb.paramValues = eqb.paramValues[0:0] eqb.paramValueBytes = eqb.paramValueBytes[0:0] eqb.paramFormats = eqb.paramFormats[0:0] eqb.resultFormats = eqb.resultFormats[0:0] - eqb.resetCount++ - - // Every so often shrink our reserved memory if it is abnormally high - if eqb.resetCount%128 == 0 { - if cap(eqb.paramValues) > 64 { - eqb.paramValues = make([][]byte, 0, cap(eqb.paramValues)/2) - } - - if cap(eqb.paramValueBytes) > 256 { - eqb.paramValueBytes = make([]byte, 0, cap(eqb.paramValueBytes)/2) - } - - if cap(eqb.paramFormats) > 64 { - eqb.paramFormats = make([]int16, 0, cap(eqb.paramFormats)/2) - } - if cap(eqb.resultFormats) > 64 { - eqb.resultFormats = make([]int16, 0, cap(eqb.resultFormats)/2) - } + if cap(eqb.paramValues) > 64 { + eqb.paramValues = make([][]byte, 0, 64) } + if cap(eqb.paramValueBytes) > 256 { + eqb.paramValueBytes = make([]byte, 0, 256) + } + + if cap(eqb.paramFormats) > 64 { + eqb.paramFormats = make([]int16, 0, 64) + } + if cap(eqb.resultFormats) > 64 { + eqb.resultFormats = make([]int16, 0, 64) + } } func (eqb *extendedQueryBuilder) encodeExtendedParamValue(ci *pgtype.ConnInfo, oid uint32, formatCode int16, arg interface{}) ([]byte, error) { diff --git a/vendor/github.com/jackc/pgx/v4/go.mod b/vendor/github.com/jackc/pgx/v4/go.mod index 2d877032b..b0f685897 100644 --- a/vendor/github.com/jackc/pgx/v4/go.mod +++ b/vendor/github.com/jackc/pgx/v4/go.mod @@ -7,11 +7,11 @@ require ( github.com/cockroachdb/apd v1.1.0 github.com/go-kit/log v0.1.0 github.com/gofrs/uuid v4.0.0+incompatible - github.com/jackc/pgconn v1.10.0 + github.com/jackc/pgconn v1.11.0 github.com/jackc/pgio v1.0.0 - github.com/jackc/pgproto3/v2 v2.1.1 - github.com/jackc/pgtype v1.8.1 - github.com/jackc/puddle v1.1.3 + github.com/jackc/pgproto3/v2 v2.2.0 + github.com/jackc/pgtype v1.10.0 + github.com/jackc/puddle v1.2.1 github.com/rs/zerolog v1.15.0 github.com/shopspring/decimal v1.2.0 github.com/sirupsen/logrus v1.4.2 diff --git a/vendor/github.com/jackc/pgx/v4/go.sum b/vendor/github.com/jackc/pgx/v4/go.sum index 2222449d8..aa5a3ae93 100644 --- a/vendor/github.com/jackc/pgx/v4/go.sum +++ b/vendor/github.com/jackc/pgx/v4/go.sum @@ -32,6 +32,10 @@ github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8 github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.10.0 h1:4EYhlDVEMsJ30nNj0mmgwIUXoq7e9sMJrVC2ED6QlCU= github.com/jackc/pgconn v1.10.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.10.1 h1:DzdIHIjG1AxGwoEEqS+mGsURyjt4enSmqzACXvVzOT8= +github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.11.0 h1:HiHArx4yFbwl91X3qqIHtUFoiIfLNJXCQRsnzkiwwaQ= +github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -49,6 +53,8 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1: github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1 h1:7PQ/4gLoqnl87ZxL7xjO0DR5gYuviDCZxQJsUlFW1eI= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns= +github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= @@ -57,6 +63,12 @@ github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrU github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= github.com/jackc/pgtype v1.8.1 h1:9k0IXtdJXHJbyAWQgbWr1lU+MEhPXZz6RIXxfR5oxXs= github.com/jackc/pgtype v1.8.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.9.0 h1:/SH1RxEtltvJgsDqp3TbiTFApD3mey3iygpuEGeuBXk= +github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.9.1 h1:MJc2s0MFS8C3ok1wQTdQxWuXQcB6+HwAm5x1CzW7mf0= +github.com/jackc/pgtype v1.9.1/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.10.0 h1:ILnBWrRMSXGczYvmkYD6PsYyVFUNLTnIUJHHDLmqk38= +github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= @@ -65,6 +77,12 @@ github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0f github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3 h1:JnPg/5Q9xVJGfjsO5CPUOjnJps1JaRUm8I9FXVCFK94= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.4 h1:5Ey/o5IfV7dYX6Znivq+N9MdK1S18OJI5OJq6EAAADw= +github.com/jackc/puddle v1.1.4/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.2.0 h1:DNDKdn/pDrWvDWyT2FYvpZVE81OAhWrjCv19I9n108Q= +github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.2.1 h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw= +github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= diff --git a/vendor/github.com/jackc/pgx/v4/pgxpool/batch_results.go b/vendor/github.com/jackc/pgx/v4/pgxpool/batch_results.go index ec393a8c7..c625a4741 100644 --- a/vendor/github.com/jackc/pgx/v4/pgxpool/batch_results.go +++ b/vendor/github.com/jackc/pgx/v4/pgxpool/batch_results.go @@ -17,6 +17,10 @@ func (br errBatchResults) Query() (pgx.Rows, error) { return errRows{err: br.err}, br.err } +func (br errBatchResults) QueryFunc(scans []interface{}, f func(pgx.QueryFuncRow) error) (pgconn.CommandTag, error) { + return nil, br.err +} + func (br errBatchResults) QueryRow() pgx.Row { return errRow{err: br.err} } @@ -38,6 +42,10 @@ func (br *poolBatchResults) Query() (pgx.Rows, error) { return br.br.Query() } +func (br *poolBatchResults) QueryFunc(scans []interface{}, f func(pgx.QueryFuncRow) error) (pgconn.CommandTag, error) { + return br.br.QueryFunc(scans, f) +} + func (br *poolBatchResults) QueryRow() pgx.Row { return br.br.QueryRow() } diff --git a/vendor/github.com/jackc/pgx/v4/pgxpool/conn.go b/vendor/github.com/jackc/pgx/v4/pgxpool/conn.go index 29ca04d06..0b59d7416 100644 --- a/vendor/github.com/jackc/pgx/v4/pgxpool/conn.go +++ b/vendor/github.com/jackc/pgx/v4/pgxpool/conn.go @@ -70,10 +70,12 @@ func (c *Conn) CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNam return c.Conn().CopyFrom(ctx, tableName, columnNames, rowSrc) } +// Begin starts a transaction block from the *Conn without explicitly setting a transaction mode (see BeginTx with TxOptions if transaction mode is required). func (c *Conn) Begin(ctx context.Context) (pgx.Tx, error) { return c.Conn().Begin(ctx) } +// BeginTx starts a transaction block from the *Conn with txOptions determining the transaction mode. func (c *Conn) BeginTx(ctx context.Context, txOptions pgx.TxOptions) (pgx.Tx, error) { return c.Conn().BeginTx(ctx, txOptions) } diff --git a/vendor/github.com/jackc/pgx/v4/pgxpool/pool.go b/vendor/github.com/jackc/pgx/v4/pgxpool/pool.go index 7f200622c..f287ad88b 100644 --- a/vendor/github.com/jackc/pgx/v4/pgxpool/pool.go +++ b/vendor/github.com/jackc/pgx/v4/pgxpool/pool.go @@ -68,6 +68,7 @@ func (cr *connResource) getPoolRows(c *Conn, r pgx.Rows) *poolRows { return pr } +// Pool allows for connection reuse. type Pool struct { p *puddle.Pool config *Config @@ -96,7 +97,7 @@ type Config struct { // AfterConnect is called after a connection is established, but before it is added to the pool. AfterConnect func(context.Context, *pgx.Conn) error - // BeforeAcquire is called before before a connection is acquired from the pool. It must return true to allow the + // BeforeAcquire is called before a connection is acquired from the pool. It must return true to allow the // acquision or false to indicate that the connection should be destroyed and a different connection should be // acquired. BeforeAcquire func(context.Context, *pgx.Conn) bool @@ -139,6 +140,7 @@ func (c *Config) Copy() *Config { return newConfig } +// ConnString returns the connection string as parsed by pgxpool.ParseConfig into pgxpool.Config. func (c *Config) ConnString() string { return c.ConnConfig.ConnString() } // Connect creates a new Pool and immediately establishes one connection. ctx can be used to cancel this initial @@ -220,9 +222,13 @@ func ConnectConfig(ctx context.Context, config *Config) (*Pool, error) { config.MaxConns, ) - go p.backgroundHealthCheck() - if !config.LazyConnect { + if err := p.createIdleResources(ctx, int(p.minConns)); err != nil { + // Couldn't create resources for minpool size. Close unhealthy pool. + p.Close() + return nil, err + } + // Initially establish one connection res, err := p.p.Acquire(ctx) if err != nil { @@ -232,6 +238,8 @@ func ConnectConfig(ctx context.Context, config *Config) (*Pool, error) { res.Release() } + go p.backgroundHealthCheck() + return p, nil } @@ -375,6 +383,32 @@ func (p *Pool) checkMinConns() { } } +func (p *Pool) createIdleResources(parentCtx context.Context, targetResources int) error { + ctx, cancel := context.WithCancel(parentCtx) + defer cancel() + + errs := make(chan error, targetResources) + + for i := 0; i < targetResources; i++ { + go func() { + err := p.p.CreateResource(ctx) + errs <- err + }() + } + + var firstError error + for i := 0; i < targetResources; i++ { + err := <-errs + if err != nil && firstError == nil { + cancel() + firstError = err + } + } + + return firstError +} + +// Acquire returns a connection (*Conn) from the Pool func (p *Pool) Acquire(ctx context.Context) (*Conn, error) { for { res, err := p.p.Acquire(ctx) @@ -424,10 +458,15 @@ func (p *Pool) AcquireAllIdle(ctx context.Context) []*Conn { // Config returns a copy of config that was used to initialize this pool. func (p *Pool) Config() *Config { return p.config.Copy() } +// Stat returns a pgxpool.Stat struct with a snapshot of Pool statistics. func (p *Pool) Stat() *Stat { return &Stat{s: p.p.Stat()} } +// Exec acquires a connection from the Pool and executes the given SQL. +// SQL can be either a prepared statement name or an SQL string. +// Arguments should be referenced positionally from the SQL string as $1, $2, etc. +// The acquired connection is returned to the pool when the Exec function returns. func (p *Pool) Exec(ctx context.Context, sql string, arguments ...interface{}) (pgconn.CommandTag, error) { c, err := p.Acquire(ctx) if err != nil { @@ -438,6 +477,16 @@ func (p *Pool) Exec(ctx context.Context, sql string, arguments ...interface{}) ( return c.Exec(ctx, sql, arguments...) } +// Query acquires a connection and executes a query that returns pgx.Rows. +// Arguments should be referenced positionally from the SQL string as $1, $2, etc. +// See pgx.Rows documentation to close the returned Rows and return the acquired connection to the Pool. +// +// If there is an error, the returned pgx.Rows will be returned in an error state. +// If preferred, ignore the error returned from Query and handle errors using the returned pgx.Rows. +// +// For extra control over how the query is executed, the types QuerySimpleProtocol, QueryResultFormats, and +// QueryResultFormatsByOID may be used as the first args to control exactly how the query is executed. This is rarely +// needed. See the documentation for those types for details. func (p *Pool) Query(ctx context.Context, sql string, args ...interface{}) (pgx.Rows, error) { c, err := p.Acquire(ctx) if err != nil { @@ -453,6 +502,18 @@ func (p *Pool) Query(ctx context.Context, sql string, args ...interface{}) (pgx. return c.getPoolRows(rows), nil } +// QueryRow acquires a connection and executes a query that is expected +// to return at most one row (pgx.Row). Errors are deferred until pgx.Row's +// Scan method is called. If the query selects no rows, pgx.Row's Scan will +// return ErrNoRows. Otherwise, pgx.Row's Scan scans the first selected row +// and discards the rest. The acquired connection is returned to the Pool when +// pgx.Row's Scan method is called. +// +// Arguments should be referenced positionally from the SQL string as $1, $2, etc. +// +// For extra control over how the query is executed, the types QuerySimpleProtocol, QueryResultFormats, and +// QueryResultFormatsByOID may be used as the first args to control exactly how the query is executed. This is rarely +// needed. See the documentation for those types for details. func (p *Pool) QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row { c, err := p.Acquire(ctx) if err != nil { @@ -483,9 +544,18 @@ func (p *Pool) SendBatch(ctx context.Context, b *pgx.Batch) pgx.BatchResults { return &poolBatchResults{br: br, c: c} } +// Begin acquires a connection from the Pool and starts a transaction. Unlike database/sql, the context only affects the begin command. i.e. there is no +// auto-rollback on context cancellation. Begin initiates a transaction block without explicitly setting a transaction mode for the block (see BeginTx with TxOptions if transaction mode is required). +// *pgxpool.Tx is returned, which implements the pgx.Tx interface. +// Commit or Rollback must be called on the returned transaction to finalize the transaction block. func (p *Pool) Begin(ctx context.Context) (pgx.Tx, error) { return p.BeginTx(ctx, pgx.TxOptions{}) } + +// BeginTx acquires a connection from the Pool and starts a transaction with pgx.TxOptions determining the transaction mode. +// Unlike database/sql, the context only affects the begin command. i.e. there is no auto-rollback on context cancellation. +// *pgxpool.Tx is returned, which implements the pgx.Tx interface. +// Commit or Rollback must be called on the returned transaction to finalize the transaction block. func (p *Pool) BeginTx(ctx context.Context, txOptions pgx.TxOptions) (pgx.Tx, error) { c, err := p.Acquire(ctx) if err != nil { @@ -525,6 +595,8 @@ func (p *Pool) CopyFrom(ctx context.Context, tableName pgx.Identifier, columnNam return c.Conn().CopyFrom(ctx, tableName, columnNames, rowSrc) } +// Ping acquires a connection from the Pool and executes an empty sql statement against it. +// If the sql returns without error, the database Ping is considered successful, otherwise, the error is returned. func (p *Pool) Ping(ctx context.Context) error { c, err := p.Acquire(ctx) if err != nil { diff --git a/vendor/github.com/jackc/pgx/v4/pgxpool/stat.go b/vendor/github.com/jackc/pgx/v4/pgxpool/stat.go index a4b2e750e..336be42d5 100644 --- a/vendor/github.com/jackc/pgx/v4/pgxpool/stat.go +++ b/vendor/github.com/jackc/pgx/v4/pgxpool/stat.go @@ -6,6 +6,7 @@ import ( "github.com/jackc/puddle" ) +// Stat is a snapshot of Pool statistics. type Stat struct { s *puddle.Stat } @@ -50,7 +51,7 @@ func (s *Stat) IdleConns() int32 { return s.s.IdleResources() } -// MaxResources returns the maximum size of the pool. +// MaxConns returns the maximum size of the pool. func (s *Stat) MaxConns() int32 { return s.s.MaxResources() } diff --git a/vendor/github.com/jackc/pgx/v4/pgxpool/tx.go b/vendor/github.com/jackc/pgx/v4/pgxpool/tx.go index e1c980e19..6f566e41b 100644 --- a/vendor/github.com/jackc/pgx/v4/pgxpool/tx.go +++ b/vendor/github.com/jackc/pgx/v4/pgxpool/tx.go @@ -7,11 +7,13 @@ import ( "github.com/jackc/pgx/v4" ) +// Tx represents a database transaction acquired from a Pool. type Tx struct { t pgx.Tx c *Conn } +// Begin starts a pseudo nested transaction implemented with a savepoint. func (tx *Tx) Begin(ctx context.Context) (pgx.Tx, error) { return tx.t.Begin(ctx) } @@ -20,6 +22,9 @@ func (tx *Tx) BeginFunc(ctx context.Context, f func(pgx.Tx) error) error { return tx.t.BeginFunc(ctx, f) } +// Commit commits the transaction and returns the associated connection back to the Pool. Commit will return ErrTxClosed +// if the Tx is already closed, but is otherwise safe to call multiple times. If the commit fails with a rollback status +// (e.g. the transaction was already in a broken state) then ErrTxCommitRollback will be returned. func (tx *Tx) Commit(ctx context.Context) error { err := tx.t.Commit(ctx) if tx.c != nil { @@ -29,6 +34,9 @@ func (tx *Tx) Commit(ctx context.Context) error { return err } +// Rollback rolls back the transaction and returns the associated connection back to the Pool. Rollback will return ErrTxClosed +// if the Tx is already closed, but is otherwise safe to call multiple times. Hence, defer tx.Rollback() is safe even if +// tx.Commit() will be called first in a non-error condition. func (tx *Tx) Rollback(ctx context.Context) error { err := tx.t.Rollback(ctx) if tx.c != nil { @@ -50,6 +58,13 @@ func (tx *Tx) LargeObjects() pgx.LargeObjects { return tx.t.LargeObjects() } +// Prepare creates a prepared statement with name and sql. If the name is empty, +// an anonymous prepared statement will be used. sql can contain placeholders +// for bound parameters. These placeholders are referenced positionally as $1, $2, etc. +// +// Prepare is idempotent; i.e. it is safe to call Prepare multiple times with the same +// name and sql arguments. This allows a code path to Prepare and Query/Exec without +// needing to first check whether the statement has already been prepared. func (tx *Tx) Prepare(ctx context.Context, name, sql string) (*pgconn.StatementDescription, error) { return tx.t.Prepare(ctx, name, sql) } diff --git a/vendor/github.com/jackc/pgx/v4/rows.go b/vendor/github.com/jackc/pgx/v4/rows.go index d57d5cbf6..271c6e527 100644 --- a/vendor/github.com/jackc/pgx/v4/rows.go +++ b/vendor/github.com/jackc/pgx/v4/rows.go @@ -41,10 +41,13 @@ type Rows interface { // Scan reads the values from the current row into dest values positionally. // dest can include pointers to core types, values implementing the Scanner - // interface, and nil. nil will skip the value entirely. + // interface, and nil. nil will skip the value entirely. It is an error to + // call Scan without first calling Next() and checking that it returned true. Scan(dest ...interface{}) error - // Values returns the decoded row values. + // Values returns the decoded row values. As with Scan(), it is an error to + // call Values without first calling Next() and checking that it returned + // true. Values() ([]interface{}, error) // RawValues returns the unparsed bytes of the row values. The returned [][]byte is only valid until the next Next diff --git a/vendor/github.com/jackc/pgx/v4/tx.go b/vendor/github.com/jackc/pgx/v4/tx.go index 7a296f4fe..1971ed673 100644 --- a/vendor/github.com/jackc/pgx/v4/tx.go +++ b/vendor/github.com/jackc/pgx/v4/tx.go @@ -10,32 +10,36 @@ import ( "github.com/jackc/pgconn" ) +// TxIsoLevel is the transaction isolation level (serializable, repeatable read, read committed or read uncommitted) type TxIsoLevel string // Transaction isolation levels const ( - Serializable = TxIsoLevel("serializable") - RepeatableRead = TxIsoLevel("repeatable read") - ReadCommitted = TxIsoLevel("read committed") - ReadUncommitted = TxIsoLevel("read uncommitted") + Serializable TxIsoLevel = "serializable" + RepeatableRead TxIsoLevel = "repeatable read" + ReadCommitted TxIsoLevel = "read committed" + ReadUncommitted TxIsoLevel = "read uncommitted" ) +// TxAccessMode is the transaction access mode (read write or read only) type TxAccessMode string // Transaction access modes const ( - ReadWrite = TxAccessMode("read write") - ReadOnly = TxAccessMode("read only") + ReadWrite TxAccessMode = "read write" + ReadOnly TxAccessMode = "read only" ) +// TxDeferrableMode is the transaction deferrable mode (deferrable or not deferrable) type TxDeferrableMode string // Transaction deferrable modes const ( - Deferrable = TxDeferrableMode("deferrable") - NotDeferrable = TxDeferrableMode("not deferrable") + Deferrable TxDeferrableMode = "deferrable" + NotDeferrable TxDeferrableMode = "not deferrable" ) +// TxOptions are transaction modes within a transaction block type TxOptions struct { IsoLevel TxIsoLevel AccessMode TxAccessMode @@ -109,7 +113,7 @@ func (c *Conn) BeginTxFunc(ctx context.Context, txOptions TxOptions, f func(Tx) } defer func() { rollbackErr := tx.Rollback(ctx) - if !(rollbackErr == nil || errors.Is(rollbackErr, ErrTxClosed)) { + if rollbackErr != nil && !errors.Is(rollbackErr, ErrTxClosed) { err = rollbackErr } }() @@ -203,7 +207,7 @@ func (tx *dbTx) BeginFunc(ctx context.Context, f func(Tx) error) (err error) { } defer func() { rollbackErr := savepoint.Rollback(ctx) - if !(rollbackErr == nil || errors.Is(rollbackErr, ErrTxClosed)) { + if rollbackErr != nil && !errors.Is(rollbackErr, ErrTxClosed) { err = rollbackErr } }() diff --git a/vendor/github.com/jackc/puddle/CHANGELOG.md b/vendor/github.com/jackc/puddle/CHANGELOG.md index 1b4c09c37..246f3dcca 100644 --- a/vendor/github.com/jackc/puddle/CHANGELOG.md +++ b/vendor/github.com/jackc/puddle/CHANGELOG.md @@ -1,3 +1,17 @@ +# 1.2.1 (December 2, 2021) + +* TryAcquire now does not block when background constructing resource + +# 1.2.0 (November 20, 2021) + +* Add TryAcquire (A. Jensen) +* Fix: remove memory leak / unintentionally pinned memory when shrinking slices (Alexander Staubo) +* Fix: Do not leave pool locked after panic from nil context + +# 1.1.4 (September 11, 2021) + +* Fix: Deadlock in CreateResource if pool was closed during resource acquisition (Dmitriy Matrenichev) + # 1.1.3 (December 3, 2020) * Fix: Failed resource creation could cause concurrent Acquire to hang. (Evgeny Vanslov) diff --git a/vendor/github.com/jackc/puddle/pool.go b/vendor/github.com/jackc/puddle/pool.go index 9123572f7..1baf88ce4 100644 --- a/vendor/github.com/jackc/puddle/pool.go +++ b/vendor/github.com/jackc/puddle/pool.go @@ -18,6 +18,10 @@ const ( // or a pool that is closed while the acquire is waiting. var ErrClosedPool = errors.New("closed pool") +// ErrNotAvailable occurs on an attempt to acquire a resource from a pool +// that is at maximum capacity and has no available resources. +var ErrNotAvailable = errors.New("resource not available") + // Constructor is a function called by the pool to construct a resource. type Constructor func(ctx context.Context) (res interface{}, err error) @@ -259,10 +263,10 @@ func (p *Pool) Stat() *Stat { // to cancel the Acquire. func (p *Pool) Acquire(ctx context.Context) (*Resource, error) { startNano := nanotime() - p.cond.L.Lock() if doneChan := ctx.Done(); doneChan != nil { select { case <-ctx.Done(): + p.cond.L.Lock() p.canceledAcquireCount += 1 p.cond.L.Unlock() return nil, ctx.Err() @@ -270,6 +274,8 @@ func (p *Pool) Acquire(ctx context.Context) (*Resource, error) { } } + p.cond.L.Lock() + emptyAcquire := false for { @@ -281,6 +287,7 @@ func (p *Pool) Acquire(ctx context.Context) (*Resource, error) { // If a resource is available now if len(p.idleResources) > 0 { res := p.idleResources[len(p.idleResources)-1] + p.idleResources[len(p.idleResources)-1] = nil // Avoid memory leak p.idleResources = p.idleResources[:len(p.idleResources)-1] res.status = resourceStatusAcquired if emptyAcquire { @@ -359,6 +366,53 @@ func (p *Pool) Acquire(ctx context.Context) (*Resource, error) { } } +// TryAcquire gets a resource from the pool if one is immediately available. If not, it returns ErrNotAvailable. If no +// resources are available but the pool has room to grow, a resource will be created in the background. ctx is only +// used to cancel the background creation. +func (p *Pool) TryAcquire(ctx context.Context) (*Resource, error) { + p.cond.L.Lock() + defer p.cond.L.Unlock() + + if p.closed { + return nil, ErrClosedPool + } + + // If a resource is available now + if len(p.idleResources) > 0 { + res := p.idleResources[len(p.idleResources)-1] + p.idleResources[len(p.idleResources)-1] = nil // Avoid memory leak + p.idleResources = p.idleResources[:len(p.idleResources)-1] + p.acquireCount += 1 + res.status = resourceStatusAcquired + return res, nil + } + + if len(p.allResources) < int(p.maxSize) { + res := &Resource{pool: p, creationTime: time.Now(), lastUsedNano: nanotime(), status: resourceStatusConstructing} + p.allResources = append(p.allResources, res) + p.destructWG.Add(1) + + go func() { + value, err := p.constructResourceValue(ctx) + defer p.cond.Signal() + p.cond.L.Lock() + defer p.cond.L.Unlock() + + if err != nil { + p.allResources = removeResource(p.allResources, res) + p.destructWG.Done() + return + } + + res.value = value + res.status = resourceStatusIdle + p.idleResources = append(p.idleResources, res) + }() + } + + return nil, ErrNotAvailable +} + // AcquireAllIdle atomically acquires all currently idle resources. Its intended // use is for health check and keep-alive functionality. It does not update pool // statistics. @@ -372,9 +426,8 @@ func (p *Pool) AcquireAllIdle() []*Resource { for _, res := range p.idleResources { res.status = resourceStatusAcquired } - resources := make([]*Resource, len(p.idleResources)) - copy(resources, p.idleResources) - p.idleResources = p.idleResources[0:0] + resources := p.idleResources // Swap out current slice + p.idleResources = nil p.cond.L.Unlock() return resources @@ -409,6 +462,7 @@ func (p *Pool) CreateResource(ctx context.Context) error { // If closed while constructing resource then destroy it and return an error if p.closed { go p.destructResourceValue(res.value) + p.cond.L.Unlock() return ErrClosedPool } p.allResources = append(p.allResources, res) @@ -460,6 +514,7 @@ func removeResource(slice []*Resource, res *Resource) []*Resource { for i := range slice { if slice[i] == res { slice[i] = slice[len(slice)-1] + slice[len(slice)-1] = nil // Avoid memory leak return slice[:len(slice)-1] } } diff --git a/vendor/modules.txt b/vendor/modules.txt index 4e132745d..8589d9a68 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -284,7 +284,7 @@ github.com/hashicorp/go-retryablehttp github.com/inconshreveable/mousetrap # github.com/jackc/chunkreader/v2 v2.0.1 github.com/jackc/chunkreader/v2 -# github.com/jackc/pgconn v1.10.0 +# github.com/jackc/pgconn v1.11.0 github.com/jackc/pgconn github.com/jackc/pgconn/internal/ctxwatch github.com/jackc/pgconn/stmtcache @@ -292,19 +292,19 @@ github.com/jackc/pgconn/stmtcache github.com/jackc/pgio # github.com/jackc/pgpassfile v1.0.0 github.com/jackc/pgpassfile -# github.com/jackc/pgproto3/v2 v2.1.1 +# github.com/jackc/pgproto3/v2 v2.2.0 github.com/jackc/pgproto3/v2 # github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b github.com/jackc/pgservicefile # github.com/jackc/pgtype v1.10.0 ## explicit github.com/jackc/pgtype -# github.com/jackc/pgx/v4 v4.13.0 +# github.com/jackc/pgx/v4 v4.15.0 ## explicit github.com/jackc/pgx/v4 github.com/jackc/pgx/v4/internal/sanitize github.com/jackc/pgx/v4/pgxpool -# github.com/jackc/puddle v1.1.3 +# github.com/jackc/puddle v1.2.1 github.com/jackc/puddle # github.com/jmespath/go-jmespath v0.4.0 github.com/jmespath/go-jmespath