mirror of
https://github.com/ncruces/go-sqlite3.git
synced 2026-01-12 05:59:14 +00:00
Only reuse main db files.
This commit is contained in:
@@ -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{})
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
15
vfs.go
@@ -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)
|
||||
|
||||
18
vfs_files.go
18
vfs_files.go
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user