lnd/kvdb/postgres/db_conn_set.go
2021-11-17 11:08:43 +01:00

90 lines
1.8 KiB
Go

package postgres
import (
"database/sql"
"fmt"
"sync"
_ "github.com/jackc/pgx/v4/stdlib"
)
// dbConn stores the actual connection and a user count.
type dbConn struct {
db *sql.DB
count int
}
// dbConnSet stores a set of connections.
type dbConnSet struct {
dbConn map[string]*dbConn
maxConnections int
sync.Mutex
}
// newDbConnSet initializes a new set of connections.
func newDbConnSet(maxConnections int) *dbConnSet {
return &dbConnSet{
dbConn: make(map[string]*dbConn),
maxConnections: maxConnections,
}
}
// Open opens a new database connection. If a connection already exists for the
// given dsn, the existing connection is returned.
func (d *dbConnSet) Open(dsn string) (*sql.DB, error) {
d.Lock()
defer d.Unlock()
if dbConn, ok := d.dbConn[dsn]; ok {
dbConn.count++
return dbConn.db, nil
}
db, err := sql.Open("pgx", dsn)
if err != nil {
return nil, err
}
// Limit maximum number of open connections. This is useful to prevent
// the server from running out of connections and returning an error.
// With this client-side limit in place, lnd will wait for a connection
// to become available.
if d.maxConnections != 0 {
db.SetMaxOpenConns(d.maxConnections)
}
d.dbConn[dsn] = &dbConn{
db: db,
count: 1,
}
return db, nil
}
// Close closes the connection with the given dsn. If there are still other
// users of the same connection, this function does nothing.
func (d *dbConnSet) Close(dsn string) error {
d.Lock()
defer d.Unlock()
dbConn, ok := d.dbConn[dsn]
if !ok {
return fmt.Errorf("connection not found: %v", dsn)
}
// Reduce user count.
dbConn.count--
// Do not close if there are other users.
if dbConn.count > 0 {
return nil
}
// Close connection.
delete(d.dbConn, dsn)
return dbConn.db.Close()
}