mirror of
https://github.com/status-im/status-go.git
synced 2025-02-19 18:28:18 +00:00
feat: enable multiple db connections with sqlcipher
part of: status-im/status-desktop#10558
This commit is contained in:
parent
75864528b1
commit
5777bb429a
@ -2,11 +2,13 @@ package sqlite
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"database/sql/driver"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
_ "github.com/mutecomm/go-sqlcipher" // We require go sqlcipher that overrides default implementation
|
sqlcipher "github.com/mutecomm/go-sqlcipher" // We require go sqlcipher that overrides default implementation
|
||||||
|
|
||||||
"github.com/status-im/status-go/protocol/sqlite"
|
"github.com/status-im/status-go/protocol/sqlite"
|
||||||
)
|
)
|
||||||
@ -75,52 +77,60 @@ func EncryptDB(unencryptedPath string, encryptedPath string, key string, kdfIter
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func openCipher(db *sql.DB, key string, kdfIterationsNumber int, inMemory bool) error {
|
func openDB(path string, key string, kdfIterationsNumber int) (*sql.DB, error) {
|
||||||
keyString := fmt.Sprintf("PRAGMA key = '%s'", key)
|
driverName := fmt.Sprintf("sqlcipher_with_extensions-%d", len(sql.Drivers()))
|
||||||
if _, err := db.Exec(keyString); err != nil {
|
sql.Register(driverName, &sqlcipher.SQLiteDriver{
|
||||||
return errors.New("failed to set key pragma")
|
ConnectHook: func(conn *sqlcipher.SQLiteConn) error {
|
||||||
|
if _, err := conn.Exec("PRAGMA foreign_keys=ON", []driver.Value{}); err != nil {
|
||||||
|
return errors.New("failed to set `foreign_keys` pragma")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := conn.Exec(fmt.Sprintf("PRAGMA key = '%s'", key), []driver.Value{}); err != nil {
|
||||||
|
return errors.New("failed to set `key` pragma")
|
||||||
}
|
}
|
||||||
|
|
||||||
if kdfIterationsNumber <= 0 {
|
if kdfIterationsNumber <= 0 {
|
||||||
kdfIterationsNumber = sqlite.ReducedKDFIterationsNumber
|
kdfIterationsNumber = sqlite.ReducedKDFIterationsNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := db.Exec(fmt.Sprintf("PRAGMA kdf_iter = '%d'", kdfIterationsNumber)); err != nil {
|
if _, err := conn.Exec(fmt.Sprintf("PRAGMA kdf_iter = '%d'", kdfIterationsNumber), []driver.Value{}); err != nil {
|
||||||
return err
|
return errors.New("failed to set `kdf_iter` pragma")
|
||||||
}
|
}
|
||||||
|
|
||||||
// readers do not block writers and faster i/o operations
|
// readers do not block writers and faster i/o operations
|
||||||
// https://www.sqlite.org/draft/wal.html
|
if _, err := conn.Exec("PRAGMA journal_mode=WAL", []driver.Value{}); err != nil && path != InMemoryPath {
|
||||||
// must be set after db is encrypted
|
return errors.New("failed to set `journal_mode` pragma")
|
||||||
var mode string
|
|
||||||
err := db.QueryRow("PRAGMA journal_mode=WAL").Scan(&mode)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
if mode != WALMode && !inMemory {
|
|
||||||
return fmt.Errorf("unable to set journal_mode to WAL. actual mode %s", mode)
|
// workaround to mitigate the issue of "database is locked" errors during concurrent write operations
|
||||||
|
if _, err := conn.Exec("PRAGMA busy_timeout=60000", []driver.Value{}); err != nil {
|
||||||
|
return errors.New("failed to set `busy_timeout` pragma")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
},
|
||||||
|
})
|
||||||
|
|
||||||
func openDB(path string, key string, kdfIterationsNumber int) (*sql.DB, error) {
|
db, err := sql.Open(driverName, path)
|
||||||
db, err := sql.Open("sqlite3", path)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable concurrent access as not supported by the driver
|
if path == InMemoryPath {
|
||||||
db.SetMaxOpenConns(1)
|
db.SetMaxOpenConns(1)
|
||||||
|
} else {
|
||||||
if _, err = db.Exec("PRAGMA foreign_keys=ON"); err != nil {
|
nproc := func() int {
|
||||||
return nil, err
|
maxProcs := runtime.GOMAXPROCS(0)
|
||||||
|
numCPU := runtime.NumCPU()
|
||||||
|
if maxProcs < numCPU {
|
||||||
|
return maxProcs
|
||||||
|
}
|
||||||
|
return numCPU
|
||||||
|
}()
|
||||||
|
db.SetMaxOpenConns(nproc)
|
||||||
|
db.SetMaxIdleConns(nproc)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = openCipher(db, key, kdfIterationsNumber, path == InMemoryPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return db, nil
|
return db, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user