Only reuse main db files.

This commit is contained in:
Nuno Cruces
2023-02-23 02:22:57 +00:00
parent 75f2644b0e
commit d52e0371eb
5 changed files with 34 additions and 48 deletions

View File

@@ -47,8 +47,8 @@ func (sqlite) Open(name string) (driver.Conn, error) {
}
}
if pragmas.Len() == 0 {
pragmas.WriteString(`PRAGMA locking_mode=normal;`)
pragmas.WriteString(`PRAGMA busy_timeout=60000;`)
pragmas.WriteString(`PRAGMA locking_mode=normal;`)
}
err = c.Exec(pragmas.String())
@@ -58,43 +58,25 @@ func (sqlite) Open(name string) (driver.Conn, error) {
return conn{
conn: c,
txBegin: txBegin,
pragmas: pragmas.String(),
}, nil
}
type conn struct {
conn *sqlite3.Conn
pragmas string
txBegin string
txReadOnly bool
}
var (
// Ensure these interfaces are implemented:
_ driver.Validator = conn{}
_ driver.SessionResetter = conn{}
_ driver.ExecerContext = conn{}
_ driver.ConnBeginTx = conn{}
_ driver.ExecerContext = conn{}
_ driver.ConnBeginTx = conn{}
)
func (c conn) Close() error {
return c.conn.Close()
}
func (c conn) IsValid() bool {
// Pool only normal locking mode connections.
stmt, _, err := c.conn.Prepare(`PRAGMA locking_mode`)
if err != nil {
return false
}
defer stmt.Close()
return stmt.Step() && stmt.ColumnText(0) == "normal"
}
func (c conn) ResetSession(ctx context.Context) error {
return c.conn.Exec(c.pragmas)
}
func (c conn) Begin() (driver.Tx, error) {
return c.BeginTx(context.Background(), driver.TxOptions{})
}

View File

@@ -41,7 +41,9 @@ func (t params) mustExec(sql string, args ...interface{}) sql.Result {
}
func (sqliteDB) RunTest(t *testing.T, fn func(params)) {
db, err := sql.Open("sqlite3", filepath.Join(t.TempDir(), "foo.db"))
db, err := sql.Open("sqlite3", "file:"+
filepath.Join(t.TempDir(), "foo.db")+
"?_pragma=busy_timeout(10000)&_pragma=locking_mode(normal)&_pragma=synchronous(off)")
if err != nil {
t.Fatalf("foo.db open fail: %v", err)
}
@@ -104,7 +106,7 @@ func testTxQuery(t params) {
}
defer tx.Rollback()
_, err = t.DB.Exec("create table " + TablePrefix + "foo (id integer primary key, name varchar(50))")
_, err = tx.Exec("create table " + TablePrefix + "foo (id integer primary key, name varchar(50))")
if err != nil {
t.Logf("cannot drop table "+TablePrefix+"foo: %s", err)
}

View File

@@ -1,7 +1,6 @@
package tests
import (
"errors"
"io"
"os"
"os/exec"
@@ -16,7 +15,7 @@ import (
func TestParallel(t *testing.T) {
name := filepath.Join(t.TempDir(), "test.db")
testParallel(t, name, 100)
testParallel(t, name, 1000)
testIntegrity(t, name)
}
@@ -46,10 +45,6 @@ func TestMultiProcess(t *testing.T) {
testParallel(t, name, 1000)
if err := cmd.Wait(); err != nil {
t.Error(err)
var eerr *exec.ExitError
if errors.As(err, &eerr) {
t.Error(eerr.Stderr)
}
}
testIntegrity(t, name)
}
@@ -72,8 +67,10 @@ func testParallel(t *testing.T, name string, n int) {
defer db.Close()
err = db.Exec(`
PRAGMA locking_mode = NORMAL;
PRAGMA busy_timeout = 10000;
PRAGMA busy_timeout=10000;
PRAGMA synchronous=off;
PRAGMA locking_mode=normal;
PRAGMA journal_mode=truncate;
`)
if err != nil {
return err
@@ -100,8 +97,8 @@ func testParallel(t *testing.T, name string, n int) {
defer db.Close()
err = db.Exec(`
PRAGMA locking_mode = NORMAL;
PRAGMA busy_timeout = 10000;
PRAGMA busy_timeout=10000;
PRAGMA locking_mode=normal;
`)
if err != nil {
return err
@@ -148,7 +145,7 @@ func testParallel(t *testing.T, name string, n int) {
}
err = group.Wait()
if err != nil {
t.Fatal(err)
t.Error(err)
}
}

15
vfs.go
View File

@@ -223,12 +223,15 @@ func vfsOpen(ctx context.Context, mod api.Module, pVfs, zName, pFile uint32, fla
deleteOnClose(file)
}
info, err := file.Stat()
if err != nil {
return uint32(CANTOPEN)
}
if info.IsDir() {
return uint32(CANTOPEN_ISDIR)
var info fs.FileInfo
if flags&OPEN_MAIN_DB != 0 {
info, err = file.Stat()
if err != nil {
return uint32(CANTOPEN)
}
if info.IsDir() {
return uint32(CANTOPEN_ISDIR)
}
}
id := vfsGetOpenFileID(file, info)
vfsFilePtr{mod, pFile}.SetID(id).SetLock(_NO_LOCK)

View File

@@ -24,14 +24,16 @@ func vfsGetOpenFileID(file *os.File, info os.FileInfo) uint32 {
defer vfsOpenFilesMtx.Unlock()
// Reuse an already opened file.
for id, of := range vfsOpenFiles {
if of == nil {
continue
}
if os.SameFile(info, of.info) {
of.nref++
_ = file.Close()
return uint32(id)
if info != nil {
for id, of := range vfsOpenFiles {
if of == nil {
continue
}
if os.SameFile(info, of.info) {
of.nref++
_ = file.Close()
return uint32(id)
}
}
}