mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-05-14 05:41:29 +00:00
* fix(filer/postgres): use pgx v5 API for PgBouncer simple protocol
In pgx/v5 the `prefer_simple_protocol` DSN parameter was removed, so
appending it to the connection string caused PgBouncer/PostgreSQL to
reject it as an unknown startup parameter:
FATAL: unsupported startup parameter: prefer_simple_protocol (SQLSTATE 08P01)
Parse the DSN with pgx.ParseConfig and, when pgbouncer_compatible is
set, configure DefaultQueryExecMode = QueryExecModeSimpleProtocol and
disable the statement/description caches. Register the config via
stdlib.RegisterConnConfig before sql.Open.
Fixes #9005
* refactor(filer/postgres): extract shared OpenPGXDB helper with cleanup
Extract the pgx v5 ParseConfig/RegisterConnConfig/sql.Open/Ping logic
into a shared postgres.OpenPGXDB helper used by both postgres and
postgres2 filer stores, eliminating ~60 lines of duplication.
The helper also unregisters the conn config via stdlib.UnregisterConnConfig
on every failure path (sql.Open error, Ping error) so we do not leak
entries in stdlib's global connection config map when initialization
fails.
* refactor(filer/postgres): use stdlib.OpenDB to avoid conn config leak
Switch OpenPGXDB from RegisterConnConfig + sql.Open("pgx", connStr) to
stdlib.OpenDB(*connConfig). The former leaks an entry in stdlib's global
conn config map on every successful initialization; stdlib.OpenDB takes
the config directly and keeps no global registration.
Addresses CodeRabbit review feedback on #9010.
124 lines
3.7 KiB
Go
124 lines
3.7 KiB
Go
// Package postgres2 provides PostgreSQL filer store implementation with bucket support
|
|
// Migrated from github.com/lib/pq to github.com/jackc/pgx for:
|
|
// - Active development and support
|
|
// - Better performance and PostgreSQL-specific features
|
|
// - Improved error handling (no more panics)
|
|
// - Built-in logging capabilities
|
|
// - Superior SSL certificate support
|
|
package postgres2
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/filer"
|
|
"github.com/seaweedfs/seaweedfs/weed/filer/abstract_sql"
|
|
"github.com/seaweedfs/seaweedfs/weed/filer/postgres"
|
|
"github.com/seaweedfs/seaweedfs/weed/util"
|
|
)
|
|
|
|
var _ filer.BucketAware = (*PostgresStore2)(nil)
|
|
|
|
func init() {
|
|
filer.Stores = append(filer.Stores, &PostgresStore2{})
|
|
}
|
|
|
|
type PostgresStore2 struct {
|
|
abstract_sql.AbstractSqlStore
|
|
}
|
|
|
|
func (store *PostgresStore2) GetName() string {
|
|
return "postgres2"
|
|
}
|
|
|
|
func (store *PostgresStore2) Initialize(configuration util.Configuration, prefix string) (err error) {
|
|
return store.initialize(
|
|
configuration.GetString(prefix+"createTable"),
|
|
configuration.GetString(prefix+"upsertQuery"),
|
|
configuration.GetBool(prefix+"enableUpsert"),
|
|
configuration.GetString(prefix+"username"),
|
|
configuration.GetString(prefix+"password"),
|
|
configuration.GetString(prefix+"hostname"),
|
|
configuration.GetInt(prefix+"port"),
|
|
configuration.GetString(prefix+"database"),
|
|
configuration.GetString(prefix+"schema"),
|
|
configuration.GetString(prefix+"sslmode"),
|
|
configuration.GetString(prefix+"sslcert"),
|
|
configuration.GetString(prefix+"sslkey"),
|
|
configuration.GetString(prefix+"sslrootcert"),
|
|
configuration.GetString(prefix+"sslcrl"),
|
|
configuration.GetBool(prefix+"pgbouncer_compatible"),
|
|
configuration.GetInt(prefix+"connection_max_idle"),
|
|
configuration.GetInt(prefix+"connection_max_open"),
|
|
configuration.GetInt(prefix+"connection_max_lifetime_seconds"),
|
|
)
|
|
}
|
|
|
|
func (store *PostgresStore2) initialize(createTable, upsertQuery string, enableUpsert bool, user, password, hostname string, port int, database, schema, sslmode, sslcert, sslkey, sslrootcert, sslcrl string, pgbouncerCompatible bool, maxIdle, maxOpen, maxLifetimeSeconds int) (err error) {
|
|
|
|
store.SupportBucketTable = true
|
|
if !enableUpsert {
|
|
upsertQuery = ""
|
|
}
|
|
store.SqlGenerator = &postgres.SqlGenPostgres{
|
|
CreateTableSqlTemplate: createTable,
|
|
DropTableSqlTemplate: `drop table "%s"`,
|
|
UpsertQueryTemplate: upsertQuery,
|
|
}
|
|
|
|
// pgx-optimized connection string with better timeouts and connection handling
|
|
sqlUrl := "connect_timeout=30"
|
|
|
|
if hostname != "" {
|
|
sqlUrl += " host=" + hostname
|
|
}
|
|
if port != 0 {
|
|
sqlUrl += " port=" + strconv.Itoa(port)
|
|
}
|
|
|
|
// SSL configuration - pgx provides better SSL support than lib/pq
|
|
if sslmode != "" {
|
|
sqlUrl += " sslmode=" + sslmode
|
|
}
|
|
if sslcert != "" {
|
|
sqlUrl += " sslcert=" + sslcert
|
|
}
|
|
if sslkey != "" {
|
|
sqlUrl += " sslkey=" + sslkey
|
|
}
|
|
if sslrootcert != "" {
|
|
sqlUrl += " sslrootcert=" + sslrootcert
|
|
}
|
|
if sslcrl != "" {
|
|
sqlUrl += " sslcrl=" + sslcrl
|
|
}
|
|
if user != "" {
|
|
sqlUrl += " user=" + user
|
|
}
|
|
adaptedSqlUrl := sqlUrl
|
|
if password != "" {
|
|
sqlUrl += " password=" + password
|
|
adaptedSqlUrl += " password=ADAPTED"
|
|
}
|
|
if database != "" {
|
|
sqlUrl += " dbname=" + database
|
|
adaptedSqlUrl += " dbname=" + database
|
|
}
|
|
if schema != "" && !pgbouncerCompatible {
|
|
sqlUrl += " search_path=" + schema
|
|
adaptedSqlUrl += " search_path=" + schema
|
|
}
|
|
db, openErr := postgres.OpenPGXDB(sqlUrl, adaptedSqlUrl, pgbouncerCompatible, maxIdle, maxOpen, maxLifetimeSeconds)
|
|
if openErr != nil {
|
|
return openErr
|
|
}
|
|
store.DB = db
|
|
|
|
if err = store.CreateTable(context.Background(), abstract_sql.DEFAULT_TABLE); err != nil {
|
|
return fmt.Errorf("init table %s: %v", abstract_sql.DEFAULT_TABLE, err)
|
|
}
|
|
|
|
return nil
|
|
}
|