2023-01-17 13:54:12 +02:00
|
|
|
package sqlbase
|
2021-11-17 09:45:45 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2022-12-15 17:38:14 +02:00
|
|
|
// mu is used to guard access to the dbConn map.
|
|
|
|
mu sync.Mutex
|
2021-11-17 09:45:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2023-01-17 13:46:45 +02:00
|
|
|
func (d *dbConnSet) Open(driver, dsn string) (*sql.DB, error) {
|
2022-12-15 17:38:14 +02:00
|
|
|
d.mu.Lock()
|
|
|
|
defer d.mu.Unlock()
|
2021-11-17 09:45:45 +01:00
|
|
|
|
|
|
|
if dbConn, ok := d.dbConn[dsn]; ok {
|
|
|
|
dbConn.count++
|
|
|
|
|
|
|
|
return dbConn.db, nil
|
|
|
|
}
|
|
|
|
|
2023-01-17 13:46:45 +02:00
|
|
|
db, err := sql.Open(driver, dsn)
|
2021-11-17 09:45:45 +01:00
|
|
|
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 {
|
2022-12-15 17:38:14 +02:00
|
|
|
d.mu.Lock()
|
|
|
|
defer d.mu.Unlock()
|
2021-11-17 09:45:45 +01:00
|
|
|
|
|
|
|
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()
|
|
|
|
}
|