fixed "unable to open database file" (potentially), and errors wrapped in pkg/persistence
This commit is contained in:
parent
d5a03feb43
commit
64543d71d7
@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -104,7 +105,7 @@ func MakeDatabase(rawURL string, logger *zap.Logger) (Database, error) {
|
|||||||
|
|
||||||
url_, err := url.Parse(rawURL)
|
url_, err := url.Parse(rawURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.Wrap(err, "url.Parse")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch url_.Scheme {
|
switch url_.Scheme {
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@ -27,23 +27,43 @@ func makeSqlite3Database(url_ *url.URL) (Database, error) {
|
|||||||
|
|
||||||
dbDir, _ := path.Split(url_.Path)
|
dbDir, _ := path.Split(url_.Path)
|
||||||
if err := os.MkdirAll(dbDir, 0755); err != nil {
|
if err := os.MkdirAll(dbDir, 0755); err != nil {
|
||||||
return nil, fmt.Errorf("for directory `%s`: %s", dbDir, err.Error())
|
return nil, errors.Wrapf(err, "mkdirAll error for `%s`", dbDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
url_.Scheme = ""
|
url_.Scheme = ""
|
||||||
db.conn, err = sql.Open("sqlite3", url_.String())
|
db.conn, err = sql.Open("sqlite3", url_.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("sql.Open: %s", err.Error())
|
return nil, errors.Wrap(err, "sql.Open")
|
||||||
}
|
}
|
||||||
|
|
||||||
// > Open may just validate its arguments without creating a connection to the database. To
|
// > Open may just validate its arguments without creating a connection to the database. To
|
||||||
// > verify that the data source Name is valid, call Ping.
|
// > verify that the data source Name is valid, call Ping.
|
||||||
// https://golang.org/pkg/database/sql/#Open
|
// https://golang.org/pkg/database/sql/#Open
|
||||||
if err = db.conn.Ping(); err != nil {
|
if err = db.conn.Ping(); err != nil {
|
||||||
return nil, fmt.Errorf("sql.DB.Ping: %s", err.Error())
|
return nil, errors.Wrap(err, "sql.DB.Ping")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// > After some time we receive "unable to open database file" error while trying to execute a transaction using
|
||||||
|
// > Tx.Exec().
|
||||||
|
// -- boramalper
|
||||||
|
//
|
||||||
|
// > Not sure if this would be contributing to your issue, but one of the problems we've observed in the past is the
|
||||||
|
// > standard library's attempt to pool connections. (This makes more sense for database connections that are actual
|
||||||
|
// > network connections, as opposed to SQLite.)
|
||||||
|
// > Basically, the problem we encountered was that most pragmas (except specifically PRAGMA journal_mode=WAL, as
|
||||||
|
// > per the documentation) apply to the connection, so if the standard library is opening/closing connections
|
||||||
|
// > behind your back for pooling purposes, it can lead to unintended behavior.
|
||||||
|
// -- rittneje
|
||||||
|
//
|
||||||
|
// https://github.com/mattn/go-sqlite3/issues/618
|
||||||
|
//
|
||||||
|
// Our solution is to set the connection max lifetime to infinity (reuse connection forever), and max open
|
||||||
|
// connections to 1.
|
||||||
|
db.conn.SetConnMaxLifetime(0) // https://golang.org/pkg/database/sql/#DB.SetConnMaxLifetime
|
||||||
|
db.conn.SetMaxOpenConns(1)
|
||||||
|
db.conn.SetMaxIdleConns(0)
|
||||||
|
|
||||||
if err := db.setupDatabase(); err != nil {
|
if err := db.setupDatabase(); err != nil {
|
||||||
return nil, errors.Wrap(err, "setupDatabase")
|
return nil, errors.Wrap(err, "setupDatabase")
|
||||||
}
|
}
|
||||||
@ -299,7 +319,7 @@ func (db *sqlite3Database) QueryTorrents(
|
|||||||
rows, err := db.conn.Query(sqlQuery, queryArgs...)
|
rows, err := db.conn.Query(sqlQuery, queryArgs...)
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error while querying torrents: %s", err.Error())
|
return nil, errors.Wrap(err, "query error")
|
||||||
}
|
}
|
||||||
|
|
||||||
torrents := make([]TorrentMetadata, 0)
|
torrents := make([]TorrentMetadata, 0)
|
||||||
@ -395,7 +415,7 @@ func (db *sqlite3Database) GetFiles(infoHash []byte) ([]File, error) {
|
|||||||
func (db *sqlite3Database) GetStatistics(from string, n uint) (*Statistics, error) {
|
func (db *sqlite3Database) GetStatistics(from string, n uint) (*Statistics, error) {
|
||||||
fromTime, gran, err := ParseISO8601(from)
|
fromTime, gran, err := ParseISO8601(from)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error while parsing from: %s", err.Error())
|
return nil, errors.Wrap(err, "parsing ISO8601 error")
|
||||||
}
|
}
|
||||||
|
|
||||||
var toTime time.Time
|
var toTime time.Time
|
||||||
@ -479,12 +499,12 @@ func (db *sqlite3Database) setupDatabase() error {
|
|||||||
PRAGMA encoding='UTF-8';
|
PRAGMA encoding='UTF-8';
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("sql.DB.Exec (PRAGMAs): %s", err.Error())
|
return errors.Wrap(err, "sql.DB.Exec (PRAGMAs)")
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, err := db.conn.Begin()
|
tx, err := db.conn.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("sql.DB.Begin: %s", err.Error())
|
return errors.Wrap(err, "sql.DB.Begin")
|
||||||
}
|
}
|
||||||
// If everything goes as planned and no error occurs, we will commit the transaction before
|
// If everything goes as planned and no error occurs, we will commit the transaction before
|
||||||
// returning from the function so the tx.Rollback() call will fail, trying to rollback a
|
// returning from the function so the tx.Rollback() call will fail, trying to rollback a
|
||||||
@ -512,13 +532,13 @@ func (db *sqlite3Database) setupDatabase() error {
|
|||||||
);
|
);
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("sql.Tx.Exec (v0): %s", err.Error())
|
return errors.Wrap(err, "sql.Tx.Exec (v0)")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the user_version:
|
// Get the user_version:
|
||||||
rows, err := tx.Query("PRAGMA user_version;")
|
rows, err := tx.Query("PRAGMA user_version;")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("sql.Tx.Query (user_version): %s", err.Error())
|
return errors.Wrap(err, "sql.Tx.Query (user_version)")
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
var userVersion int
|
var userVersion int
|
||||||
@ -526,7 +546,7 @@ func (db *sqlite3Database) setupDatabase() error {
|
|||||||
return fmt.Errorf("sql.Rows.Next (user_version): PRAGMA user_version did not return any rows!")
|
return fmt.Errorf("sql.Rows.Next (user_version): PRAGMA user_version did not return any rows!")
|
||||||
}
|
}
|
||||||
if err = rows.Scan(&userVersion); err != nil {
|
if err = rows.Scan(&userVersion); err != nil {
|
||||||
return fmt.Errorf("sql.Rows.Scan (user_version): %s", err.Error())
|
return errors.Wrap(err, "sql.Rows.Scan (user_version)")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch userVersion {
|
switch userVersion {
|
||||||
@ -541,7 +561,7 @@ func (db *sqlite3Database) setupDatabase() error {
|
|||||||
PRAGMA user_version = 1;
|
PRAGMA user_version = 1;
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("sql.Tx.Exec (v0 -> v1): %s", err.Error())
|
return errors.Wrap(err, "sql.Tx.Exec (v0 -> v1)")
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
||||||
@ -586,7 +606,7 @@ func (db *sqlite3Database) setupDatabase() error {
|
|||||||
PRAGMA user_version = 2;
|
PRAGMA user_version = 2;
|
||||||
`)
|
`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("sql.Tx.Exec (v1 -> v2): %s", err.Error())
|
return errors.Wrap(err, "sql.Tx.Exec (v1 -> v2)")
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
|
|
||||||
@ -650,7 +670,7 @@ func (db *sqlite3Database) setupDatabase() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err = tx.Commit(); err != nil {
|
if err = tx.Commit(); err != nil {
|
||||||
return fmt.Errorf("sql.Tx.Commit: %s", err.Error())
|
return errors.Wrap(err, "sql.Tx.Commit")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
Loading…
Reference in New Issue
Block a user