Commit a61a41f9 authored by gwenn's avatar gwenn

Small step toward Stmt cache support.

parent f11efc26
......@@ -6,24 +6,41 @@ package sqlite
import (
"container/list"
"fmt"
"sync"
)
const (
defaultCacheSize = 0
)
// Like http://www.sqlite.org/tclsqlite.html#cache
type Cache struct {
m sync.Mutex
l *list.List
MaxSize int // Cache turned off when MaxSize <= 0
maxSize int // Cache turned off when maxSize <= 0
}
func newCache() *Cache {
return newCacheSize(defaultCacheSize)
}
func newCacheSize(maxSize int) *Cache {
if maxSize <= 0 {
return &Cache{maxSize: maxSize}
}
return &Cache{l: list.New(), maxSize: maxSize}
}
// TODO To be called in Conn#Prepare
func (c *Cache) find(sql string) *Stmt {
if c.MaxSize <= 0 {
if c.maxSize <= 0 {
return nil
}
c.m.Lock()
defer c.m.Unlock()
for e := c.l.Front(); e != nil; e = e.Next() {
if s, ok := e.Value.(*Stmt); ok {
if s.SQL() == sql {
if s.SQL() == sql { // TODO s.SQL() may have been trimmed by SQLite
c.l.Remove(e)
return s
}
......@@ -32,15 +49,16 @@ func (c *Cache) find(sql string) *Stmt {
return nil
}
// TODO To be called instead of Stmt#Finalize
func (c *Cache) release(s *Stmt) {
if c.MaxSize <= 0 {
if c.maxSize <= 0 || len(s.tail) > 0 {
s.Finalize()
return
}
c.m.Lock()
defer c.m.Unlock()
c.l.InsertBefore(s, c.l.Front())
for c.l.Len() > c.MaxSize {
for c.l.Len() > c.maxSize {
v := c.l.Remove(c.l.Back())
if s, ok := v.(*Stmt); ok {
s.Finalize()
......@@ -48,7 +66,12 @@ func (c *Cache) release(s *Stmt) {
}
}
// Finalize and free the cached prepared statements
// (To be called in Conn#Close)
func (c *Cache) flush() {
if c.maxSize <= 0 {
return
}
c.m.Lock()
defer c.m.Unlock()
var e, next *list.Element
......@@ -57,6 +80,29 @@ func (c *Cache) flush() {
v := c.l.Remove(e)
if s, ok := v.(*Stmt); ok {
s.Finalize()
} else {
panic(fmt.Sprintf("unexpected element in Stmt cache: %#v", v))
}
}
}
// Return (current, max) sizes.
// Cache is turned off when max size is 0
func (c *Conn) CacheSize() (int, int) {
if c.stmtCache.maxSize <= 0 {
return 0, 0
}
return c.stmtCache.l.Len(), c.stmtCache.maxSize
}
// Cache is turned off (and flushed) when size <= 0
func (c *Conn) SetCacheSize(size int) {
stmtCache := c.stmtCache
if stmtCache.l == nil && size > 0 {
stmtCache.l = list.New()
}
if size <= 0 {
stmtCache.flush()
}
stmtCache.maxSize = size
}
......@@ -184,6 +184,7 @@ func (c *Conn) LastError() error {
type Conn struct {
db *C.sqlite3
Filename string
stmtCache *Cache
authorizer *sqliteAuthorizer
busyHandler *sqliteBusyHandler
profile *sqliteProfile
......@@ -264,7 +265,7 @@ func OpenVfs(filename string, vfsname string, flags ...OpenFlag) (*Conn, error)
if db == nil {
return nil, errors.New("sqlite succeeded without returning a database")
}
return &Conn{db: db, Filename: filename}, nil
return &Conn{db: db, Filename: filename, stmtCache: newCache()}, nil
}
// Set a busy timeout
......@@ -461,6 +462,9 @@ func (c *Conn) Close() error {
if c.db == nil {
return nil
}
c.stmtCache.flush()
// Dangling statements
stmt := C.sqlite3_next_stmt(c.db, nil)
for stmt != nil {
......
......@@ -163,7 +163,7 @@ func (s *Stmt) Insert(args ...interface{}) (int64, error) {
// The callback function is invoked for each result row coming out of the statement.
//
// s, err := c.Prepare(...)
// s, err := db.Prepare(...)
// // TODO error handling
// defer s.Finalize()
// err = s.Select(func(s *Stmt) error {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment