mydb/internal/sqladapter/statement.go

86 lines
1.5 KiB
Go
Raw Normal View History

2023-09-18 15:15:42 +08:00
package sqladapter
import (
"database/sql"
"errors"
"sync"
"sync/atomic"
)
var (
activeStatements int64
)
// Stmt represents a *sql.Stmt that is cached and provides the
// OnEvict method to allow it to clean after itself.
type Stmt struct {
*sql.Stmt
query string
mu sync.Mutex
count int64
dead bool
}
// NewStatement creates an returns an opened statement
func NewStatement(stmt *sql.Stmt, query string) *Stmt {
s := &Stmt{
Stmt: stmt,
query: query,
}
atomic.AddInt64(&activeStatements, 1)
return s
}
// Open marks the statement as in-use
func (c *Stmt) Open() (*Stmt, error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.dead {
return nil, errors.New("statement is dead")
}
c.count++
return c, nil
}
// Close closes the underlying statement if no other go-routine is using it.
func (c *Stmt) Close() error {
c.mu.Lock()
defer c.mu.Unlock()
c.count--
return c.checkClose()
}
func (c *Stmt) checkClose() error {
if c.dead && c.count == 0 {
// Statement is dead and we can close it for real.
err := c.Stmt.Close()
if err != nil {
return err
}
// Reduce active statements counter.
atomic.AddInt64(&activeStatements, -1)
}
return nil
}
// OnEvict marks the statement as ready to be cleaned up.
func (c *Stmt) OnEvict() {
c.mu.Lock()
defer c.mu.Unlock()
c.dead = true
c.checkClose()
}
// NumActiveStatements returns the global number of prepared statements in use
// at any point.
func NumActiveStatements() int64 {
return atomic.LoadInt64(&activeStatements)
}