summaryrefslogtreecommitdiff
path: root/vendor/github.com/ncruces/go-sqlite3/conn.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/ncruces/go-sqlite3/conn.go')
-rw-r--r--vendor/github.com/ncruces/go-sqlite3/conn.go46
1 files changed, 15 insertions, 31 deletions
diff --git a/vendor/github.com/ncruces/go-sqlite3/conn.go b/vendor/github.com/ncruces/go-sqlite3/conn.go
index 5ae0eef7c..d1ce30556 100644
--- a/vendor/github.com/ncruces/go-sqlite3/conn.go
+++ b/vendor/github.com/ncruces/go-sqlite3/conn.go
@@ -4,6 +4,7 @@ import (
"context"
"fmt"
"math"
+ "math/rand"
"net/url"
"strings"
"time"
@@ -24,7 +25,6 @@ type Conn struct {
interrupt context.Context
pending *Stmt
stmts []*Stmt
- timer *time.Timer
busy func(context.Context, int) bool
log func(xErrorCode, string)
collation func(*Conn, string)
@@ -36,7 +36,9 @@ type Conn struct {
rollback func()
arena arena
- handle uint32
+ busy1st time.Time
+ busylst time.Time
+ handle uint32
}
// Open calls [OpenFlags] with [OPEN_READWRITE], [OPEN_CREATE] and [OPEN_URI].
@@ -389,38 +391,20 @@ func (c *Conn) BusyTimeout(timeout time.Duration) error {
}
func timeoutCallback(ctx context.Context, mod api.Module, count, tmout int32) (retry uint32) {
+ // https://fractaledmind.github.io/2024/04/15/sqlite-on-rails-the-how-and-why-of-optimal-performance/
if c, ok := ctx.Value(connKey{}).(*Conn); ok && c.interrupt.Err() == nil {
- const delays = "\x01\x02\x05\x0a\x0f\x14\x19\x19\x19\x32\x32\x64"
- const totals = "\x00\x01\x03\x08\x12\x21\x35\x4e\x67\x80\xb2\xe4"
- const ndelay = int32(len(delays) - 1)
-
- var delay, prior int32
- if count <= ndelay {
- delay = int32(delays[count])
- prior = int32(totals[count])
- } else {
- delay = int32(delays[ndelay])
- prior = int32(totals[ndelay]) + delay*(count-ndelay)
+ switch {
+ case count == 0:
+ c.busy1st = time.Now()
+ case time.Since(c.busy1st) >= time.Duration(tmout)*time.Millisecond:
+ return 0
}
-
- if delay = min(delay, tmout-prior); delay > 0 {
- delay := time.Duration(delay) * time.Millisecond
- if c.interrupt.Done() == nil {
- time.Sleep(delay)
- return 1
- }
- if c.timer == nil {
- c.timer = time.NewTimer(delay)
- } else {
- c.timer.Reset(delay)
- }
- select {
- case <-c.interrupt.Done():
- c.timer.Stop()
- case <-c.timer.C:
- return 1
- }
+ if time.Since(c.busylst) < time.Millisecond {
+ const sleepIncrement = 2*1024*1024 - 1 // power of two, ~2ms
+ time.Sleep(time.Duration(rand.Int63() & sleepIncrement))
}
+ c.busylst = time.Now()
+ return 1
}
return 0
}